Skip to content

Commit

Permalink
Refactor security token handling and update logging configs. #deploy-…
Browse files Browse the repository at this point in the history
…idporten-frontend

Simplified and unified authentication token handling across reactive security classes. Adjusted logging configurations for better stack trace management. Enabled Playwright job in GitHub workflow.
  • Loading branch information
krharum committed Dec 18, 2024
1 parent 94e6e68 commit 90f9bfe
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 65 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/app.dolly-frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ on:
- ".github/workflows/common.playwright.yml"

jobs:
# playwright:
# uses: ./.github/workflows/common.playwright.yml
# with:
# working-directory: "apps/dolly-frontend"
# secrets:
# READER_TOKEN: ${{ secrets.READER_TOKEN }}
playwright:
uses: ./.github/workflows/common.playwright.yml
with:
working-directory: "apps/dolly-frontend"
secrets:
READER_TOKEN: ${{ secrets.READER_TOKEN }}

workflow:
uses: ./.github/workflows/common.workflow.frontend.yml
Expand Down
14 changes: 3 additions & 11 deletions apps/dolly-frontend/src/main/resources/logback-spring.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,9 @@
<springProfile name="prod,dev,idporten">
<appender name="stdout_json" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="no.nav.testnav.libs.reactivecore.logging.TestnavLogbackEncoder">
<throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter">
<rootCauseFirst>true</rootCauseFirst>
<maxLength>10280</maxLength>
<shortenedClassNameLength>20</shortenedClassNameLength>
<exclude>^sun\.reflect\..*\.invoke</exclude>
<exclude>^net\.sf\.cglib\.proxy\.MethodProxy\.invoke</exclude>
<exclude>java\.util\.concurrent\..*</exclude>
<exclude>org\.apache\.catalina\..*</exclude>
<exclude>org\.apache\.coyote\..*</exclude>
<exclude>org\.apache\.tomcat\..*</exclude>
</throwableConverter>
<maxStackTraceLength>-1</maxStackTraceLength>
<addCauses>true</addCauses>
<stackTraceIncludePrefix>-</stackTraceIncludePrefix>
</encoder>
</appender>
<root level="INFO">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.RequiredArgsConstructor;
import no.nav.testnav.libs.securitycore.domain.ResourceServerType;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
Expand Down Expand Up @@ -30,11 +31,18 @@ private Optional<ResourceServerType> getResourceTypeForm(JwtAuthenticationToken

@Override
public Mono<ResourceServerType> call() {

return getJwtAuthenticationToken()
.onErrorResume(JwtResolverException.class, throwable -> Mono.empty())
.flatMap(token -> getResourceTypeForm(token)
.map(Mono::just)
.orElseGet(Mono::empty)
);
.flatMap(authentication -> {
if (authentication instanceof JwtAuthenticationToken jwtAuthenticationTokentoken) {
return getResourceTypeForm(jwtAuthenticationTokentoken)
.map(Mono::just)
.orElseGet(Mono::empty);
} else if (authentication instanceof OAuth2AuthenticationToken) {
return Mono.just(ResourceServerType.TOKEN_X);
}
return Mono.empty();
});
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package no.nav.testnav.libs.reactivesecurity.action;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import no.nav.testnav.libs.securitycore.domain.Token;
import org.springframework.http.HttpStatus;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;
import reactor.core.publisher.Mono;

import java.util.concurrent.Callable;
Expand All @@ -21,13 +27,21 @@ public Mono<Token> call() {
.call()
.flatMap(serverType -> switch (serverType) {
case TOKEN_X -> getJwtAuthenticationToken()
.map(jwt -> Token.builder()
.clientCredentials(false)
.userId(jwt.getTokenAttributes().get("pid").toString())
.accessTokenValue(jwt.getToken().getTokenValue())
.expiresAt(jwt.getToken().getExpiresAt())
.build());
.map(OAuth2AuthenticationToken.class::cast)
.handle((oauth2, sink) -> {
try {
sink.next(Token.builder()
.clientCredentials(false)
.userId(oauth2.getPrincipal().getAttribute("pid"))
.accessTokenValue(new ObjectMapper().writeValueAsString(oauth2))
.expiresAt(oauth2.getPrincipal().getAttribute("exp"))
.build());
} catch (JsonProcessingException e) {
sink.error(new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Feilet å konvertere token to string", e));
}
});
case AZURE_AD -> getJwtAuthenticationToken()
.map(JwtAuthenticationToken.class::cast)
.map(jwt -> Token.builder()
.clientCredentials(jwt.getTokenAttributes().get("oid").equals(jwt.getTokenAttributes().get("sub")))
.userId(jwt.getTokenAttributes().get("oid").toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Component;
Expand All @@ -15,7 +12,7 @@
@Slf4j
@Component
@RequiredArgsConstructor
public class GetAuthenticatedUserId implements Callable<Mono<String>> {
public class GetAuthenticatedUserId extends JwtResolver implements Callable<Mono<String>> {

private final GetAuthenticatedResourceServerType getAuthenticatedResourceServerType;

Expand All @@ -31,24 +28,20 @@ public Mono<String> call() {

private Mono<String> getTokenAttribute(String attribute) {

return ReactiveSecurityContextHolder
.getContext()
.map(SecurityContext::getAuthentication)
.map(authentication -> getTokenAttribute(authentication, attribute));
}
return getJwtAuthenticationToken()
.map(authentication -> {

private String getTokenAttribute(Authentication authentication, String attribute) {
log.info("GetAuthenticatedUserId context.authentication {}, {}", authentication.getClass().getPackageName(), authentication);
return switch (authentication) {

log.info("GetAuthenticatedUserId context.authentication {}, {}", authentication.getClass().getPackageName(), authentication);
if (authentication instanceof JwtAuthenticationToken jwtAuthenticationToken) {
return jwtAuthenticationToken.getTokenAttributes().get(attribute).toString();
case JwtAuthenticationToken jwtAuthenticationToken ->
jwtAuthenticationToken.getTokenAttributes().get(attribute).toString();

} else if (authentication instanceof OAuth2AuthenticationToken oauth2AuthenticationToken) {
log.info("oauth2AuthenticationToken {}", oauth2AuthenticationToken.getPrincipal());
return oauth2AuthenticationToken.getPrincipal().getAttributes().get(attribute).toString();
case OAuth2AuthenticationToken oauth2AuthenticationToken ->
oauth2AuthenticationToken.getPrincipal().getAttributes().get(attribute).toString();

} else {
return "";
}
default -> "";
};
});
}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,19 @@
package no.nav.testnav.libs.reactivesecurity.action;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import reactor.core.publisher.Mono;

import java.time.Instant;
import java.time.ZonedDateTime;

@Slf4j
@SuppressWarnings("java:S1610")
abstract class JwtResolver {

Mono<JwtAuthenticationToken> getJwtAuthenticationToken() {
Mono<Authentication> getJwtAuthenticationToken() {
return ReactiveSecurityContextHolder
.getContext()
.switchIfEmpty(Mono.error(new JwtResolverException("ReactiveSecurityContext is empty")))
.doOnNext(context -> log.info("JwtResolver context.authentication {} {}", context.getAuthentication().getClass().getCanonicalName(), context.getAuthentication()))
.map(SecurityContext::getAuthentication)
.map(JwtAuthenticationToken.class::cast)
.doOnError(throwable -> log.warn("Klarte ikke hente Jwt Auth Token", throwable))
.doOnSuccess(jwtAuthenticationToken -> {
Jwt credentials = (Jwt) jwtAuthenticationToken.getCredentials();
Instant expiresAt = credentials.getExpiresAt();
if (expiresAt == null || expiresAt.isBefore(ZonedDateTime.now().toInstant().plusSeconds(120))) {
throw new CredentialsExpiredException("Jwt er utløpt eller utløper innen kort tid");
}
});
.map(SecurityContext::getAuthentication);
}

}

0 comments on commit 90f9bfe

Please sign in to comment.