1 | package org.cardanofoundation.explorer.api.util; | |
2 | ||
3 | import java.security.PublicKey; | |
4 | import java.util.Collections; | |
5 | import java.util.HashSet; | |
6 | import java.util.List; | |
7 | import java.util.Map; | |
8 | import java.util.Objects; | |
9 | import java.util.Set; | |
10 | ||
11 | import jakarta.servlet.http.HttpServletRequest; | |
12 | ||
13 | import lombok.AccessLevel; | |
14 | import lombok.NoArgsConstructor; | |
15 | import lombok.extern.log4j.Log4j2; | |
16 | ||
17 | import org.springframework.util.StringUtils; | |
18 | ||
19 | import io.jsonwebtoken.ExpiredJwtException; | |
20 | import io.jsonwebtoken.Jwts; | |
21 | import io.jsonwebtoken.MalformedJwtException; | |
22 | import io.jsonwebtoken.UnsupportedJwtException; | |
23 | import io.jsonwebtoken.security.SignatureException; | |
24 | ||
25 | import org.cardanofoundation.explorer.common.exception.BusinessException; | |
26 | import org.cardanofoundation.explorer.common.exception.CommonErrorCode; | |
27 | ||
28 | @Log4j2 | |
29 | @NoArgsConstructor(access = AccessLevel.PRIVATE) | |
30 | public class JwtUtils { | |
31 | ||
32 | /* | |
33 | * @since: 11/11/2022 | |
34 | * description: get accountId from token with rsa public key | |
35 | * @update: 22/05/2023 | |
36 | */ | |
37 | public static String getAccountIdFromJwtToken(String token, PublicKey publicKey) { | |
38 |
1
1. getAccountIdFromJwtToken : replaced return value with "" for org/cardanofoundation/explorer/api/util/JwtUtils::getAccountIdFromJwtToken → NO_COVERAGE |
return Jwts.parserBuilder() |
39 | .setSigningKey(publicKey) | |
40 | .build() | |
41 | .parseClaimsJws(token) | |
42 | .getBody() | |
43 | .getSubject(); | |
44 | } | |
45 | ||
46 | /* | |
47 | * @since: 11/11/2022 | |
48 | * description: parse token from header request | |
49 | * @update: | |
50 | */ | |
51 | public static String parseJwt(HttpServletRequest request) { | |
52 | final String headerAuthentication = request.getHeader("Authorization"); | |
53 | ||
54 |
2
1. parseJwt : negated conditional → NO_COVERAGE 2. parseJwt : negated conditional → NO_COVERAGE |
if (StringUtils.hasText(headerAuthentication) && headerAuthentication.startsWith("Bearer ")) { |
55 |
1
1. parseJwt : replaced return value with "" for org/cardanofoundation/explorer/api/util/JwtUtils::parseJwt → NO_COVERAGE |
return headerAuthentication.substring(7); |
56 | } | |
57 |
1
1. parseJwt : replaced return value with "" for org/cardanofoundation/explorer/api/util/JwtUtils::parseJwt → NO_COVERAGE |
return null; |
58 | } | |
59 | ||
60 | /* | |
61 | * @since: 11/11/2022 | |
62 | * description: validate token with rsa public key | |
63 | * @update: | |
64 | */ | |
65 | public static void validateJwtToken(String token, PublicKey publicKey) { | |
66 | try { | |
67 | Jwts.parserBuilder().setSigningKey(publicKey).build().parseClaimsJws(token); | |
68 | } catch (SignatureException e) { | |
69 | log.error("Invalid JWT signature: {}", e.getMessage()); | |
70 | throw new BusinessException(CommonErrorCode.TOKEN_INVALID_SIGNATURE); | |
71 | } catch (MalformedJwtException e) { | |
72 | log.error("Invalid JWT token: {}", e.getMessage()); | |
73 | throw new BusinessException(CommonErrorCode.INVALID_TOKEN); | |
74 | } catch (ExpiredJwtException e) { | |
75 | log.error("JWT token is expired: {}", e.getMessage()); | |
76 | throw new BusinessException(CommonErrorCode.TOKEN_EXPIRED); | |
77 | } catch (UnsupportedJwtException e) { | |
78 | log.error("JWT token is unsupported: {}", e.getMessage()); | |
79 | throw new BusinessException(CommonErrorCode.TOKEN_UNSUPPORTED); | |
80 | } catch (IllegalArgumentException e) { | |
81 | log.error("JWT claims string is empty: {}", e.getMessage()); | |
82 | throw new BusinessException(CommonErrorCode.TOKEN_IS_EMPTY); | |
83 | } | |
84 | } | |
85 | ||
86 | public static Set<String> getRolesFromToken(String token, PublicKey publicKey) { | |
87 | var claims = | |
88 | Jwts.parserBuilder().setSigningKey(publicKey).build().parseClaimsJws(token).getBody(); | |
89 | try { | |
90 | Map<String, List<String>> realmAccessMap = | |
91 | (Map<String, List<String>>) claims.get("realm_access"); | |
92 |
2
1. getRolesFromToken : negated conditional → NO_COVERAGE 2. getRolesFromToken : negated conditional → NO_COVERAGE |
if (Objects.nonNull(realmAccessMap) && Objects.nonNull(realmAccessMap.get("roles"))) { |
93 |
1
1. getRolesFromToken : replaced return value with Collections.emptySet for org/cardanofoundation/explorer/api/util/JwtUtils::getRolesFromToken → NO_COVERAGE |
return new HashSet<>(realmAccessMap.get("roles")); |
94 | } | |
95 | return Collections.emptySet(); | |
96 | } catch (Exception e) { | |
97 | return Collections.emptySet(); | |
98 | } | |
99 | } | |
100 | } | |
Mutations | ||
38 |
1.1 |
|
54 |
1.1 2.2 |
|
55 |
1.1 |
|
57 |
1.1 |
|
92 |
1.1 2.2 |
|
93 |
1.1 |