Skip to content

Commit

Permalink
AUT-1760 Refresh dashboard claims table content dynamically
Browse files Browse the repository at this point in the history
  • Loading branch information
Marten332 committed Apr 16, 2024
1 parent 19daddc commit e0c57ad
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 73 deletions.
Expand Up @@ -5,6 +5,7 @@
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 ee.ria.govsso.client.util.DemoResponseUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -18,11 +19,7 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import static ee.ria.govsso.client.govsso.configuration.condition.OnGovssoCondition.GOVSSO_PROFILE;
import static ee.ria.govsso.client.tara.configuration.condition.OnTaraCondition.TARA_PROFILE;
Expand Down Expand Up @@ -92,36 +89,12 @@ public ModelAndView dashboard(@AuthenticationPrincipal OidcUser oidcUser, Exampl

private void addIdTokenDataToModel(OidcUser oidcUser, ModelAndView model) {
model.addObject("id_token", oidcUser.getIdToken().getTokenValue());
model.addObject("claims", flattenClaims(oidcUser.getClaims()).entrySet());
model.addObject("claims", DemoResponseUtil.flattenClaims(oidcUser.getClaims()).entrySet());
model.addObject(
"time_until_govsso_session_expiration_in_seconds",
GovssoSessionUtil.getTimeUntilAuthenticationExpiration().toSeconds());
}

private Map<String, String> flattenClaims(Map<?, ?> claims) {
SortedMap<String, String> flatClaims = new TreeMap<>();
for (Map.Entry<?, ?> claim : claims.entrySet()) {
String key = claim.getKey().toString();
Object value = claim.getValue();
if (value instanceof Map<?, ?> innerClaims) {
Map<String, String> flattenedInnerClaims = flattenClaims(innerClaims);
for (Map.Entry<String, String> innerClaim : flattenedInnerClaims.entrySet()) {
flatClaims.put(key + "." + innerClaim.getKey(), innerClaim.getValue());
}
continue;
}
flatClaims.put(key, renderClaimValue(value));
}
return flatClaims;
}

private static String renderClaimValue(Object value) {
if (value instanceof Date date) {
return date.toInstant().toString();
}
return value.toString();
}

private String getAuthenticationProvider() {
Set<String> authenticationProviderProfiles = Set.of(GOVSSO_PROFILE, TARA_PROFILE);
Set<String> activeProfiles = Set.of(environment.getActiveProfiles());
Expand Down
Expand Up @@ -6,6 +6,7 @@
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 ee.ria.govsso.client.util.DemoResponseUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -37,7 +38,6 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static ee.ria.govsso.client.govsso.configuration.GovssoOidcConfiguration.GOVSSO_REGISTRATION_ID;
import static org.springframework.http.HttpMethod.POST;
Expand Down Expand Up @@ -99,8 +99,9 @@ private void handleRefresh(HttpServletResponse response, String scope) throws IO
createNewAuthentication(clientRegistration, tokenResponse);
SecurityContextHolder.getContext().setAuthentication(newAuthToken);
saveAuthorizedClient(newAuthToken, clientRegistration, tokenResponse);
OidcUser oidcUser = (OidcUser) newAuthToken.getPrincipal();

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

Expand All @@ -124,8 +125,8 @@ private GovssoAuthentication createNewAuthentication(
govssoExampleClientUserFactory.create(oidcUser));
}

private void writeResponse(HttpServletResponse response, OidcIdToken idToken, String accessToken, String refreshToken) throws IOException {
String refreshTokenResponse = generateDemoResponse(idToken, accessToken, refreshToken);
private void writeResponse(HttpServletResponse response, OidcUser oidcUser, String accessToken, String refreshToken) throws IOException {
String refreshTokenResponse = generateDemoResponse(oidcUser, accessToken, refreshToken);
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json");
response.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
Expand Down Expand Up @@ -159,33 +160,16 @@ 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, String accessToken, String refreshToken) {
private String generateDemoResponse(OidcUser oidcUser, String accessToken, String refreshToken) {
Map<String, Object> response = new HashMap<>();
response.put("id_token", idToken.getTokenValue());

response.put("id_token_claims", DemoResponseUtil.flattenClaims(oidcUser.getClaims()));
response.put("id_token", oidcUser.getIdToken().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()
.map(String::valueOf)
.collect(Collectors.joining(",", "[", "]")));
response.put("exp", idToken.getClaimAsString("exp"));
response.put("iat", idToken.getClaimAsString("iat"));
response.put("sub", idToken.getSubject());
response.put("birthdate", idToken.getClaimAsString("birthdate"));
response.put("given_name", idToken.getClaimAsString("given_name"));
response.put("family_name", idToken.getClaimAsString("family_name"));
response.put("amr", idToken.getClaimAsString("amr"));
response.put("nonce", idToken.getClaimAsString("nonce"));
response.put("acr", idToken.getClaimAsString("acr"));
response.put("at_hash", idToken.getClaimAsString("at_hash"));
response.put("sid", idToken.getClaimAsString("sid"));
response.put("time_until_govsso_session_expiration_in_seconds",
GovssoSessionUtil.getTimeUntilAuthenticationExpiration().toSeconds());
return JSONObjectUtils.toJSONString(response);
}

}
36 changes: 36 additions & 0 deletions src/main/java/ee/ria/govsso/client/util/DemoResponseUtil.java
@@ -0,0 +1,36 @@
package ee.ria.govsso.client.util;

import lombok.experimental.UtilityClass;

import java.util.Date;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

@UtilityClass
public class DemoResponseUtil {

public Map<String, String> flattenClaims(Map<?, ?> claims) {
SortedMap<String, String> flatClaims = new TreeMap<>();
for (Map.Entry<?, ?> claim : claims.entrySet()) {
java.lang.String key = claim.getKey().toString();
Object value = claim.getValue();
if (value instanceof Map<?, ?> innerClaims) {
Map<java.lang.String, java.lang.String> flattenedInnerClaims = flattenClaims(innerClaims);
for (Map.Entry<java.lang.String, java.lang.String> innerClaim : flattenedInnerClaims.entrySet()) {
flatClaims.put(key + "." + innerClaim.getKey(), innerClaim.getValue());
}
continue;
}
flatClaims.put(key, renderClaimValue(value));
}
return flatClaims;
}

private static String renderClaimValue(Object value) {
if (value instanceof Date date) {
return date.toInstant().toString();
}
return value.toString();
}
}
33 changes: 14 additions & 19 deletions src/main/resources/static/scripts/govsso-session-update.js
Expand Up @@ -48,28 +48,23 @@ function updateGovSsoSession() {
redirect: 'manual'
}).then(async function (response) {
if (response.ok) {
const idToken = await response.json();
const responseBody = await response.json();
const claimsTableBody = $('#claimsTableBody');
const rows = [];

$('#id_token').text(idToken.id_token);
$('#access_token').text(idToken.access_token);
$('#refresh_token').text(idToken.refresh_token);
$('#jti').text(idToken.jti);
$('#iss').text(idToken.iss);
$('#aud').text(idToken.aud);
$('#exp').text(idToken.exp);
$('#iat').text(idToken.iat);
$('#sub').text(idToken.sub);
$('#birthdate').text(idToken.birthdate);
$('#given_name').text(idToken.given_name);
$('#family_name').text(idToken.family_name);
$('#amr').text(idToken.amr);
$('#nonce').text(idToken.nonce);
$('#acr').text(idToken.acr);
$('#at_hash').text(idToken.at_hash);
$('#sid').text(idToken.sid);
$('#id_token').text(responseBody.id_token);
$('#access_token').text(responseBody.access_token);
$('#refresh_token').text(responseBody.refresh_token);

$.each(responseBody.id_token_claims, function (key, value) {
const keyCell = $("<td></td>").text(key);
const valueCell = $("<td></td>").text(value);
rows.push($("<tr></tr>").append([keyCell, valueCell]));
});
$('#claimsTableBody').html(rows);
$('#error').hide();

sessionLengthInSeconds = idToken.time_until_govsso_session_expiration_in_seconds;
sessionLengthInSeconds = responseBody.time_until_govsso_session_expiration_in_seconds;
clearInterval(sessionTimer);
endTime = getCurrentTimeStampInSeconds() + sessionLengthInSeconds - GOVSSO_SESSION_UPDATE_BUFFER_SECONDS;
sessionTimer = setInterval(incrementSeconds, 1000);
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/templates/dashboard.html
Expand Up @@ -107,7 +107,7 @@ <h2 class="h3">ID Token</h2>
<th>Value</th>
</tr>
</thead>
<tbody>
<tbody id="claimsTableBody">
<tr th:each="claim: ${claims}">
<td th:text="${claim.getKey()}"/>
<td th:id="${claim.getKey()}" th:text="${claim.getValue()}">
Expand Down

0 comments on commit e0c57ad

Please sign in to comment.