Skip to content

Commit

Permalink
change token response to JWT string
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander Schwarz committed Sep 20, 2021
1 parent dd00f6f commit 88923cf
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ public class DccTokenController {
@ApiResponse(responseCode = "410", description = "Gone. Repository service reports errors"),
@ApiResponse(responseCode = "500", description = "Internal Server Error"),
})
@PostMapping(value = PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<AccessTokenPayload> token(
@PostMapping(value = PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = "application/jwt")
public ResponseEntity<String> token(
@RequestHeader("Authorization") final String token,
@Valid @RequestBody final DccTokenRequest dccToken) {
log.debug("Incoming POST request to '{}' with content '{}' and token '{}'", PATH, dccToken, token);
Expand All @@ -78,12 +78,13 @@ public ResponseEntity<AccessTokenPayload> token(
final Map<String, String> tokenContent = accessTokenService.parseAccessToken(token);
if (tokenContent.containsKey("sub") && tokenContent.get("sub") != null) {
final String subject = tokenContent.get("sub");
final AccessTokenPayload accessTocken = dccTokenService
final AccessTokenPayload accessTockenPayload = dccTokenService
.getAccessTockenForValidationService(dccToken, subject);
final String accessToken = this.accessTokenService.buildAccessToken(accessTockenPayload);

final HttpHeaders headers = new HttpHeaders();
headers.set("X-Nonce", accessTocken.getNonce());
return ResponseEntity.ok().headers(headers).body(accessTocken);
headers.set("X-Nonce", accessTockenPayload.getNonce());
return ResponseEntity.ok().headers(headers).body(accessToken);
}
}
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
/*-
* ---license-start
* European Digital COVID Certificate Validation Decorator Service / dgca-validation-decorator
* ---
* Copyright (C) 2021 T-Systems International GmbH and all other contributors
* ---
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ---license-end
*/

package eu.europa.ec.dgc.validation.decorator.exception;

import org.springframework.http.HttpStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package eu.europa.ec.dgc.validation.decorator.service;

import eu.europa.ec.dgc.validation.decorator.config.DgcProperties;
import eu.europa.ec.dgc.validation.decorator.dto.AccessTokenPayload;
import eu.europa.ec.dgc.validation.decorator.exception.DccException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
Expand All @@ -32,6 +33,7 @@
import java.time.Instant;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -50,7 +52,7 @@ public class AccessTokenService {
* This token is generated an default header token without 'Bearer' prefix.
*/
public String buildHeaderToken() {
return String.format("%s%s", TOKEN_PREFIX, buildAccessToken());
return String.format("%s%s", TOKEN_PREFIX, this.buildAccessToken());
}

/**
Expand All @@ -59,15 +61,15 @@ public String buildHeaderToken() {
* @param subject Subject
* @return {@link String} JWT token
*/
public String buildHeaderToken(String subject) {
return String.format("%s%s", TOKEN_PREFIX, buildAccessToken(subject));
public String buildHeaderToken(final String subject) {
return String.format("%s%s", TOKEN_PREFIX, this.buildAccessToken(subject));
}

/**
* This token is generated an default access token without claims.
*/
public String buildAccessToken() {
return getAccessTokenBuilder()
return this.getAccessTokenBuilder()
.compact();
}

Expand All @@ -78,25 +80,41 @@ public String buildAccessToken() {
* @return {@link String} JWT token
*/
public String buildAccessToken(final String subject) {
return getAccessTokenBuilder()
return this.getAccessTokenBuilder()
.addClaims(Collections.singletonMap("sub", subject))
.compact();
}

public String buildAccessToken(final AccessTokenPayload payload) {
final Map<String, Object> claims = new HashMap<>();
claims.put("jti", payload.getJti());
claims.put("sub", payload.getSub());
claims.put("aud", payload.getAud());
claims.put("iat", payload.getIat());
claims.put("t", payload.getType());
claims.put("v", payload.getVersion());
claims.put("vc", payload.getConditions());

final JwtBuilder builder = this.getAccessTokenBuilder()
.setExpiration(new Date(payload.getExp()))
.addClaims(claims);
return builder.compact();
}

/**
* Read content from token, if token is valid.
*
* @param token with or without prefix
* @return {@link Map} with {@link String} as key and {@link String} as value
*/
public Map<String, String> parseAccessToken(String token) {
public Map<String, String> parseAccessToken(final String token) {
final String tokenContent = token.startsWith(TOKEN_PREFIX) ? token.replace(TOKEN_PREFIX, "") : token;
final String activeSignKey = this.keyProvider.getActiveSignKey();
final PublicKey publicKey = this.keyProvider.receiveCertificate(activeSignKey).getPublicKey();

final Jws<Claims> parsedToken = Jwts.parser()
.setSigningKey(publicKey)
.requireIssuer(properties.getToken().getIssuer())
.requireIssuer(this.properties.getToken().getIssuer())
.parseClaimsJws(tokenContent);
final Claims body = parsedToken.getBody();
if (!body.containsKey("sub")) {
Expand All @@ -118,7 +136,7 @@ public Map<String, String> parseAccessToken(String token) {
*/
public boolean isValid(final String token) {
try {
parseAccessToken(token);
this.parseAccessToken(token);
return true;
} catch (Exception e) {
return false;
Expand All @@ -129,15 +147,15 @@ private JwtBuilder getAccessTokenBuilder() {
final String activeSignKey = this.keyProvider.getActiveSignKey();
final PrivateKey privateKey = this.keyProvider.receivePrivateKey(activeSignKey);
final String algorithm = this.keyProvider.getAlg(activeSignKey);
final SignatureAlgorithm signatureAlgorithm = io.jsonwebtoken.SignatureAlgorithm.valueOf(algorithm);
final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.valueOf(algorithm);
final String keyId = this.keyProvider.getKid(activeSignKey);
final int validity = properties.getToken().getInitialize().getValidity();
final int validity = this.properties.getToken().getInitialize().getValidity();

return Jwts.builder()
.signWith(signatureAlgorithm, privateKey)
.setHeaderParam("typ", properties.getToken().getType())
.setHeaderParam("typ", this.properties.getToken().getType())
.setHeaderParam("kid", keyId)
.setIssuer(properties.getToken().getIssuer())
.setIssuer(this.properties.getToken().getIssuer())
.setExpiration(new Date(Instant.now().plusSeconds(validity).toEpochMilli()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public class DccTokenService {

private static final String TYPE_VALIDATION_SERVICE = "ValidationService";

private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_DATE_TIME;
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-dd-MM'T'HH:mm:ssxxxxx");

private final DgcProperties dgcProperties;

Expand Down

0 comments on commit 88923cf

Please sign in to comment.