Skip to content

Commit

Permalink
Merge pull request #6 from EntrevistadorInteligente/feature/76242875
Browse files Browse the repository at this point in the history
Configurar Sonar
  • Loading branch information
JamiltonQuintero authored Aug 31, 2024
2 parents 071cd14 + 861c667 commit a519a5a
Show file tree
Hide file tree
Showing 10 changed files with 402 additions and 12 deletions.
57 changes: 57 additions & 0 deletions .github/workflows/ci-with-maven.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Java CI with Maven

on:
pull_request:
branches: [ "develop", "main" ]

jobs:
build_test_analyze:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@main

- name: Set up JDK 17
uses: actions/setup-java@main
with:
java-version: '17'
distribution: 'temurin'
cache: maven

- uses: actions/cache@main
with:
path: |
target
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Run Tests with Maven
run: mvn -B test --file pom.xml

- name: Cache SonarCloud packages
uses: actions/cache@main
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar

- name: Analyze with SonarCloud
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: >
mvn -B org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
-Dsonar.projectKey=entrevistador-inteligente-${{ github.event.repository.name }}
-Dsonar.organization=entrevistador-inteligente
-Dsonar.host.url=https://sonarcloud.io
-Dsonar.qualitygate.wait=true
4 changes: 4 additions & 0 deletions .sonarlint/connectedMode.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"sonarCloudOrganization": "entrevistadorinteligente",
"projectKey": "EntrevistadorInteligente_si-gateway"
}
30 changes: 28 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<spring-cloud.version>2023.0.0</spring-cloud.version>
<jar.manifest.packageName>com.entrevistador</jar.manifest.packageName>
<org.keycloak.admin-client.version>23.0.3</org.keycloak.admin-client.version>

<sonar.coverage.exclusions>*/**/jms/**,*/**/beanconfiguration/**,*/**/excepciones/**,*/**/enums/**,*/**/dto/**,*/**/model/**,*/**/properties/**</sonar.coverage.exclusions>
</properties>
<dependencies>
<dependency>
Expand Down Expand Up @@ -80,8 +80,14 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>6.1.3</version>
<scope>test</scope>
</dependency>

</dependencies>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
Expand Down Expand Up @@ -117,6 +123,26 @@
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@
)
}
)


@SuppressWarnings("all")
public class OpenApiConfiguration {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,6 @@ public SecurityWebFilterChain securityFilterChain(@NonNull ServerHttpSecurity ht
.permitAll()
.anyExchange().authenticated()
)
.cors(corsSpec -> corsSpec.configurationSource(exchange -> {
var config = new org.springframework.web.cors.CorsConfiguration();
config.setAllowedOrigins(java.util.List.of("*"));
config.setAllowedMethods(java.util.List.of("*"));
config.setAllowedHeaders(java.util.List.of("*"));
return config;
}))
.build();
}
}
2 changes: 1 addition & 1 deletion src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ spring:
corsConfigurations:
'[/**]':
allow-credentials: true
allowed-origins: ${ORIGINS:http://localhost:${server.port},http://localhost:3000}
allowed-origins: ${ORIGINS:http://localhost:${server.port},${FRONT_HOST},http://localhost:3000}
allowed-headers: '*'
allowed-methods: '*'
discovery:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.entrevistador.gateway.config;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest
@TestPropertySource(locations = "classpath:test-application.properties")
class OpenApiConfigurationTest {

@Autowired
private ApplicationContext context;

@Test
void contextLoads() {
// Verifica que el contexto carga correctamente la configuración OpenApiConfiguration
assertThat(context.containsBean("openApiConfiguration")).isFalse();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package com.entrevistador.gateway.config.security;

import com.entrevistador.gateway.config.properties.KeycloakJwtConverterProperties;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class KeycloakGrantedAuthoritiesConverterTest {

@Mock
private KeycloakJwtConverterProperties properties;

@InjectMocks
private KeycloakGrantedAuthoritiesConverter converter;

private Jwt jwt;

@BeforeEach
void setUp() {
jwt = Jwt.withTokenValue("token")
.header("alg", "none")
.claim("realm_access", Map.of("roles", List.of("user", "admin")))
.build();
}

@Test
void convert_ShouldReturnGrantedAuthorities() {
// Mock the properties to return the role claim paths
List<String> roleClaims = List.of("realm_access.roles");
when(properties.getRoleClaims()).thenReturn(new HashSet<>(roleClaims)); // Asegúrate de que el tipo coincida
// Act
Collection<GrantedAuthority> authorities = converter.convert(jwt);

// Assert
assertEquals(2, authorities.size());

Set<String> expectedAuthorities = Set.of("ROLE_user", "ROLE_admin");
Set<String> actualAuthorities = authorities.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toSet());

assertEquals(expectedAuthorities, actualAuthorities);
}

@Test
void extractAuthority_ShouldHandleMissingIntermediateLevel() {
// Arrange
when(properties.getRoleClaims()).thenReturn(Set.of("missing.level"));

jwt = Jwt.withTokenValue("token")
.header("alg", "none")
.claim("missing", Map.of()) // No contiene "level"
.build();

// Act
Collection<GrantedAuthority> authorities = converter.convert(jwt);

// Assert
assertTrue(authorities.isEmpty());
}

@Test
void extractAuthority_ShouldHandlePathNotEndingInList() {
// Arrange
when(properties.getRoleClaims()).thenReturn(Set.of("realm_access.wrong_type"));

// Proporcionar una estructura de datos válida
jwt = Jwt.withTokenValue("token")
.header("alg", "none")
.claim("realm_access", Map.of("wrong_type", List.of("admin")))
.build();

// Act
Collection<GrantedAuthority> authorities = converter.convert(jwt);

// Assert
assertEquals(1, authorities.size());
assertTrue(authorities.stream().anyMatch(auth -> auth.getAuthority().equals("ROLE_admin")));
}

@Test
void extractAuthority_ShouldReturnListWhenPathIsSimpleClaim() {
// Arrange
when(properties.getRoleClaims()).thenReturn(Set.of("roles"));

jwt = Jwt.withTokenValue("token")
.header("alg", "none")
.claim("roles", List.of("user", "admin"))
.build();

// Act
Collection<GrantedAuthority> authorities = converter.convert(jwt);

// Assert
assertEquals(2, authorities.size());
assertTrue(authorities.stream().anyMatch(auth -> auth.getAuthority().equals("ROLE_user")));
assertTrue(authorities.stream().anyMatch(auth -> auth.getAuthority().equals("ROLE_admin")));
}

@Test
void extractAuthority_ShouldReturnListWhenPathHasMultipleLevels() {
// Arrange
when(properties.getRoleClaims()).thenReturn(Set.of("realm_access.roles"));

jwt = Jwt.withTokenValue("token")
.header("alg", "none")
.claim("realm_access", Map.of("roles", List.of("user", "admin")))
.build();

// Act
Collection<GrantedAuthority> authorities = converter.convert(jwt);

// Assert
assertEquals(2, authorities.size());
assertTrue(authorities.stream().anyMatch(auth -> auth.getAuthority().equals("ROLE_user")));
assertTrue(authorities.stream().anyMatch(auth -> auth.getAuthority().equals("ROLE_admin")));
}

@Test
void extractAuthority_ShouldHandlePartialPathCorrectly() {
// Arrange
when(properties.getRoleClaims()).thenReturn(Set.of("realm_access.partial.roles"));

// Configura el JWT con una estructura que tiene una clave válida pero sin el camino esperado
jwt = Jwt.withTokenValue("token")
.header("alg", "none")
.claim("realm_access", Map.of("partial", Map.of())) // "roles" está ausente
.build();

// Act
Collection<GrantedAuthority> authorities = converter.convert(jwt);

// Assert
assertTrue(authorities.isEmpty());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.entrevistador.gateway.config.security;

import com.entrevistador.gateway.config.properties.KeycloakJwtConverterProperties;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;

import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class KeycloakJwtAuthenticationConverterTest {

@Mock
private KeycloakJwtConverterProperties properties;

@Mock
private KeycloakGrantedAuthoritiesConverter keycloakGrantedAuthoritiesConverter;

@InjectMocks
private KeycloakJwtAuthenticationConverter converter;

private Jwt jwt;

@BeforeEach
void setUp() {
jwt = Jwt.withTokenValue("token")
.header("alg", "none")
.claim("preferred_username", "testuser")
.claim("sub", "user-subject")
.build();
}

@Test
void convert_ShouldReturnJwtAuthenticationToken_WithCorrectNameAndAuthorities() {
when(properties.getUsernameAttribute()).thenReturn("preferred_username");
when(keycloakGrantedAuthoritiesConverter.convert(jwt)).thenReturn(Collections.emptyList());

AbstractAuthenticationToken result = converter.convert(jwt);

assertEquals("testuser", result.getName());
assertEquals(jwt, ((JwtAuthenticationToken) result).getToken());
assertEquals(List.of(), result.getAuthorities());
}

@Test
void convert_ShouldFallbackToSubject_WhenUsernameAttributeIsNull() {
when(properties.getUsernameAttribute()).thenReturn(null);
when(keycloakGrantedAuthoritiesConverter.convert(jwt)).thenReturn(Collections.emptyList());

AbstractAuthenticationToken result = converter.convert(jwt);

assertEquals("user-subject", result.getName());
}

}
Loading

0 comments on commit a519a5a

Please sign in to comment.