Skip to content

Commit

Permalink
AUT-1689 Handle access token value while authenticating and display i…
Browse files Browse the repository at this point in the history
…t on the dashboard if it is in JWT format
  • Loading branch information
Marten332 committed Mar 21, 2024
1 parent b0cd795 commit d7482b1
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 6 deletions.
Expand Up @@ -2,7 +2,9 @@

import ee.ria.govsso.client.authentication.ExampleClientUser;
import ee.ria.govsso.client.configuration.ExampleClientSessionProperties;
import ee.ria.govsso.client.govsso.configuration.authentication.GovssoAuthentication;
import ee.ria.govsso.client.govsso.oauth2.GovssoSessionUtil;
import ee.ria.govsso.client.util.AccessTokenUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
Expand Down Expand Up @@ -65,13 +67,18 @@ public ModelAndView clientLoginView(
}

@GetMapping(value = DASHBOARD_MAPPING, produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView dashboard(@AuthenticationPrincipal OidcUser oidcUser, ExampleClientUser exampleClientUser) {
public ModelAndView dashboard(@AuthenticationPrincipal OidcUser oidcUser, ExampleClientUser exampleClientUser, GovssoAuthentication authentication) {
ModelAndView model = new ModelAndView("dashboard");
model.addObject("application_logo", applicationLogo);
model.addObject("authentication_provider", getAuthenticationProvider());
model.addObject("application_title", applicationTitle);
model.addObject("exampleClientUser", exampleClientUser);
model.addObject("allowed_idle_time", sessionProperties.idleTimeout().toSeconds());
model.addObject("refresh_token", authentication.getRefreshToken().getTokenValue());
String accessToken = authentication.getAccessToken().getTokenValue();
if (AccessTokenUtil.isJwtAccessToken(accessToken)) {
model.addObject("access_token", accessToken);
}

log.info("Showing dashboard for subject='{}'", oidcUser.getSubject());
addIdTokenDataToModel(oidcUser, model);
Expand Down
Expand Up @@ -254,6 +254,7 @@ private GovssoAuthentication createGovssoAuthenticationToken(
authenticationResult.getAuthorities(),
authenticationResult.getClientRegistration().getRegistrationId(),
authenticationResult.getRefreshToken(),
authenticationResult.getAccessToken(),
govssoExampleClientUserFactory.create(authenticationResult.getPrincipal()));
}

Expand Down
Expand Up @@ -7,6 +7,7 @@
import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.core.user.OAuth2User;

Expand All @@ -19,16 +20,20 @@ public class GovssoAuthentication extends OAuth2AuthenticationToken implements E
@Getter
private final OAuth2RefreshToken refreshToken;
private final ExampleClientUser user;
@Getter
private final OAuth2AccessToken accessToken;

public GovssoAuthentication(
OAuth2User principal,
Collection<? extends GrantedAuthority> authorities,
String authorizedClientRegistrationId,
OAuth2RefreshToken refreshToken,
OAuth2AccessToken accessToken,
ExampleClientUser user) {
super(principal, authorities, authorizedClientRegistrationId);
this.refreshToken = refreshToken;
this.user = user;
this.accessToken = accessToken;
}

@Override
Expand Down
Expand Up @@ -5,6 +5,7 @@
import ee.ria.govsso.client.govsso.configuration.authentication.GovssoAuthentication;
import ee.ria.govsso.client.govsso.configuration.authentication.GovssoExampleClientUserFactory;
import ee.ria.govsso.client.govsso.oauth2.GovssoSessionUtil;
import ee.ria.govsso.client.util.AccessTokenUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -99,7 +100,7 @@ private void handleRefresh(HttpServletResponse response) throws IOException {
SecurityContextHolder.getContext().setAuthentication(newAuthToken);
saveAuthorizedClient(newAuthToken, clientRegistration, tokenResponse);

writeResponse(response, ((OidcUser) newAuthToken.getPrincipal()).getIdToken());
writeResponse(response, ((OidcUser) newAuthToken.getPrincipal()).getIdToken(), tokenResponse.getAccessToken().getTokenValue(), tokenResponse.getRefreshToken().getTokenValue());
log.info("Refresh token request successful");
}

Expand All @@ -119,11 +120,12 @@ private GovssoAuthentication createNewAuthentication(
oidcUser.getAuthorities(),
oidcUserRequest.getClientRegistration().getRegistrationId(),
tokenResponse.getRefreshToken(),
tokenResponse.getAccessToken(),
govssoExampleClientUserFactory.create(oidcUser));
}

private void writeResponse(HttpServletResponse response, OidcIdToken idToken) throws IOException {
String refreshTokenResponse = generateDemoResponse(idToken);
private void writeResponse(HttpServletResponse response, OidcIdToken idToken, String accessToken, String refreshToken) throws IOException {
String refreshTokenResponse = generateDemoResponse(idToken, accessToken, refreshToken);
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json");
response.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
Expand Down Expand Up @@ -155,9 +157,14 @@ private void saveAuthorizedClient(GovssoAuthentication authToken, ClientRegistra
* You most likely wouldn't want to return all of this to your applications front-end but since we do want to
* display all of it in example client to make debugging easier, we are doing it in this case.
*/
private String generateDemoResponse(OidcIdToken idToken) {
private String generateDemoResponse(OidcIdToken idToken, String accessToken, String refreshToken) {
Map<String, Object> response = new HashMap<>();
response.put("id_token", idToken.getTokenValue());

if (AccessTokenUtil.isJwtAccessToken(accessToken)) {
response.put("access_token", accessToken);
}
response.put("refresh_token", refreshToken);
response.put("jti", idToken.getClaimAsString("jti"));
response.put("iss", idToken.getIssuer().toString());
response.put("aud", idToken.getAudience().stream()
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/ee/ria/govsso/client/util/AccessTokenUtil.java
@@ -0,0 +1,19 @@
package ee.ria.govsso.client.util;

import com.nimbusds.jwt.JWTParser;
import lombok.experimental.UtilityClass;

import java.text.ParseException;

@UtilityClass
public class AccessTokenUtil {

public boolean isJwtAccessToken(String accessToken) {
try {
JWTParser.parse(accessToken);
return true;
} catch (ParseException e) {
return false;
}
}
}
2 changes: 2 additions & 0 deletions src/main/resources/static/scripts/govsso-session-update.js
Expand Up @@ -47,6 +47,8 @@ function updateGovSsoSession() {
const idToken = await response.json();

$('#id_token').text(idToken.id_token);
$('#access_token').text(idToken.access_token);
$('#refresh_token').text(idToken.access_token);
$('#jti').text(idToken.jti);
$('#iss').text(idToken.iss);
$('#aud').text(idToken.aud);
Expand Down
8 changes: 8 additions & 0 deletions src/main/resources/templates/dashboard.html
Expand Up @@ -77,6 +77,14 @@ <h2 class="h3">Token Endpoint Response</h2>
<td>id_token</td>
<td th:id="id_token" th:text="${id_token}"></td>
</tr>
<tr th:if="${access_token}">
<td>access_token</td>
<td th:id="access_token" th:text="${access_token}"></td>
</tr>
<tr>
<td>refresh_token</td>
<td th:id="refresh_token" th:text="${refresh_token}"></td>
</tr>
</tbody>
</table>
</div>
Expand Down
11 changes: 11 additions & 0 deletions src/test/java/ee/ria/govsso/client/GovssoAuthenticationTest.java
Expand Up @@ -18,8 +18,10 @@
import java.nio.charset.StandardCharsets;

import static ee.ria.govsso.client.UrlMatcher.url;
import static ee.ria.govsso.client.controller.ClientController.DASHBOARD_MAPPING;
import static io.restassured.RestAssured.given;
import static java.util.Objects.requireNonNull;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;

Expand Down Expand Up @@ -106,6 +108,15 @@ public void authentication() {
.host(equalTo("localhost"))
.port(equalTo(port))
.path(equalTo("/dashboard")));

given()
.filter(cookieFilter)
.when()
.get(DASHBOARD_MAPPING)
.then()
.statusCode(200)
.body(containsString("id=\"access_token\">eyJhbGciOiJSUzI1NiIsImtpZCI6IjJiMDZiMjNmLTI2MDMtNGMxYy05OWU2LWRmOTVjYjRlMzAwMSIsInR5cCI6IkpXVCJ9.eyJhY3IiOiJoaWdoIiwiYW1yIjpbIm1JRCJdLCJhdWQiOlsiaHR0cHM6Ly90ZXN0Il0sImJpcnRoZGF0ZSI6IjE5NjEtMDctMTIiLCJjbGllbnRfaWQiOiJjbGllbnQtYSIsImV4cCI6MTcxMDgzMzk2MywiZXh0Ijp7ImFjciI6ImhpZ2giLCJhbXIiOlsibUlEIl0sImJpcnRoZGF0ZSI6IjE5NjEtMDctMTIiLCJmYW1pbHlfbmFtZSI6IlBlcmVrb25uYW5pbWkzIiwiZ2l2ZW5fbmFtZSI6IkVlc25pbWkzIn0sImZhbWlseV9uYW1lIjoiUGVyZWtvbm5hbmltaTMiLCJnaXZlbl9uYW1lIjoiRWVzbmltaTMiLCJpYXQiOjE3MTA4MzM5NjIsImlzcyI6Imh0dHBzOi8vaW5wcm94eS5sb2NhbGhvc3Q6MTM0NDMvIiwianRpIjoiYWFjMmM4ZDEtYTNiMy00MmM1LWEzYzQtZTc4ZGIyZTc1NWNmIiwic2NwIjpbIm9wZW5pZCJdLCJzdWIiOiJJc2lrdWtvb2QzIn0.ZLVYuMPTrz-D8XIfc_V1DnAwfBGDD02IjUIKNPstwKmN3WcWPFL1utjDtbo3oGPoQvWEZYBfnpXOdAFYYcnBax7Aj4cUW1uamz0rKGInOE_-0o66Go9bMqJ5sA9mJn5EYS293SYsfDaFLz_P598FNohAIlovJj2CgYRQI7JPHkIBGKDKYGprQ-QywB13qEamosDGII1DH_RtCwWcqn5QEHzbsbuoARNXZ28G4vLpihuCKl-aHUDnms5vTsZRaeiR6YyAxJYkJdUG7FKE6c5ocLmp29aN19jIANpoiDLsGVATuoqFns0VwnVaXugMpAMvgscb29hItvoQlrwyKlbrPwRRHpdBP4L74kMxL5u8yTjVgTlnySKtc7YmJfXdpBUcRedsdTu4qsApzPkLASr0x7hSiclHYUtR1s9mDhuZH38_gsa43cVhOsayoeH-Fdr8hGvqTCihVlsFdWgd0fLfXYRqXDz9lPLpphMdJty1iQ1DSG5jSVaoaT-e1JSHNXCH1I21AomxWp5cvrEbK9VmaAeT6lelReVADeTJg1pBBUx_mJVxnh_Js0LrJrtxHRV-OWNo4kCBVYUjtJFsjvPovKR8dSGt1KzuCLKehKo5JNM4wiM4-hXMiwLkjE-qOYazMapGmqrXU-ijV3lOr0DROnB8fBWLl3j2FoHiQ9a0nbY"))
.body(containsString("id=\"refresh_token\">XF-G7eKbiuZ0eaUaZY7WZsz70Jmm0Tro6AiTyeQcULU.Xh4GpFqcJ-vatFArYknlH6dbY8FfnxaC3xf-uzLHhPY"));
}

private static String getQueryParam(UriComponents locationComponents, String paramName) {
Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/__files/govsso_mock/token.json
@@ -1,5 +1,5 @@
{
"access_token": "GGTwRppcvVtQPFM0HL4AXK_4VzSN0ydEUOSv6sajb8o.uQAIGCm4uePtOr2pVUUJVQkKR-A0De5XJlk8zz9XM9A",
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjJiMDZiMjNmLTI2MDMtNGMxYy05OWU2LWRmOTVjYjRlMzAwMSIsInR5cCI6IkpXVCJ9.eyJhY3IiOiJoaWdoIiwiYW1yIjpbIm1JRCJdLCJhdWQiOlsiaHR0cHM6Ly90ZXN0Il0sImJpcnRoZGF0ZSI6IjE5NjEtMDctMTIiLCJjbGllbnRfaWQiOiJjbGllbnQtYSIsImV4cCI6MTcxMDgzMzk2MywiZXh0Ijp7ImFjciI6ImhpZ2giLCJhbXIiOlsibUlEIl0sImJpcnRoZGF0ZSI6IjE5NjEtMDctMTIiLCJmYW1pbHlfbmFtZSI6IlBlcmVrb25uYW5pbWkzIiwiZ2l2ZW5fbmFtZSI6IkVlc25pbWkzIn0sImZhbWlseV9uYW1lIjoiUGVyZWtvbm5hbmltaTMiLCJnaXZlbl9uYW1lIjoiRWVzbmltaTMiLCJpYXQiOjE3MTA4MzM5NjIsImlzcyI6Imh0dHBzOi8vaW5wcm94eS5sb2NhbGhvc3Q6MTM0NDMvIiwianRpIjoiYWFjMmM4ZDEtYTNiMy00MmM1LWEzYzQtZTc4ZGIyZTc1NWNmIiwic2NwIjpbIm9wZW5pZCJdLCJzdWIiOiJJc2lrdWtvb2QzIn0.ZLVYuMPTrz-D8XIfc_V1DnAwfBGDD02IjUIKNPstwKmN3WcWPFL1utjDtbo3oGPoQvWEZYBfnpXOdAFYYcnBax7Aj4cUW1uamz0rKGInOE_-0o66Go9bMqJ5sA9mJn5EYS293SYsfDaFLz_P598FNohAIlovJj2CgYRQI7JPHkIBGKDKYGprQ-QywB13qEamosDGII1DH_RtCwWcqn5QEHzbsbuoARNXZ28G4vLpihuCKl-aHUDnms5vTsZRaeiR6YyAxJYkJdUG7FKE6c5ocLmp29aN19jIANpoiDLsGVATuoqFns0VwnVaXugMpAMvgscb29hItvoQlrwyKlbrPwRRHpdBP4L74kMxL5u8yTjVgTlnySKtc7YmJfXdpBUcRedsdTu4qsApzPkLASr0x7hSiclHYUtR1s9mDhuZH38_gsa43cVhOsayoeH-Fdr8hGvqTCihVlsFdWgd0fLfXYRqXDz9lPLpphMdJty1iQ1DSG5jSVaoaT-e1JSHNXCH1I21AomxWp5cvrEbK9VmaAeT6lelReVADeTJg1pBBUx_mJVxnh_Js0LrJrtxHRV-OWNo4kCBVYUjtJFsjvPovKR8dSGt1KzuCLKehKo5JNM4wiM4-hXMiwLkjE-qOYazMapGmqrXU-ijV3lOr0DROnB8fBWLl3j2FoHiQ9a0nbY",
"expires_in": 1,
"id_token": <id-token>,
"refresh_token": "XF-G7eKbiuZ0eaUaZY7WZsz70Jmm0Tro6AiTyeQcULU.Xh4GpFqcJ-vatFArYknlH6dbY8FfnxaC3xf-uzLHhPY",
Expand Down

0 comments on commit d7482b1

Please sign in to comment.