Skip to content

Commit

Permalink
feat: test cases added, file header updated and detail log added for …
Browse files Browse the repository at this point in the history
…security events
  • Loading branch information
thackerronak committed Jul 23, 2024
1 parent 15425be commit a4fa6cc
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ public void onFailure(AbstractAuthenticationFailureEvent failures) {

@EventListener
public void onFailure(AuthorizationDeniedEvent failure) {
log.warn("Failed Authorization: Missing 'Authorization' header.");
if (failure.getAuthorizationDecision() != null) {
log.warn("Failed Authorization: {}",failure.getAuthorizationDecision().toString());
} else {
log.warn("Failed Authorization: Missing 'Authorization' header.");
}
}
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* *******************************************************************************
* Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* *******************************************************************************
* Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,31 @@
import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.ACCESS_TOKEN;
import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.SCOPE;

/**
* The type Token parsing utils.
*/
@UtilityClass
public class TokenParsingUtils {

/**
* The constant PARSING_TOKEN_ERROR.
*/
public static final String PARSING_TOKEN_ERROR = "Could not parse jwt token";
/**
* The constant BEARER_ACCESS_SCOPE.
*/
public static final String BEARER_ACCESS_SCOPE = "bearer_access_scope";
/**
* The constant ACCESS_TOKEN_ERROR.
*/
public static final String ACCESS_TOKEN_ERROR = "Access token not present";

/**
* Gets claims set.
*
* @param tokenParsed the token parsed
* @return the claims set
*/
public static JWTClaimsSet getClaimsSet(SignedJWT tokenParsed) {
try {
return tokenParsed.getJWTClaimsSet();
Expand All @@ -56,6 +74,12 @@ public static JWTClaimsSet getClaimsSet(SignedJWT tokenParsed) {
}
}

/**
* Parse token signed jwt.
*
* @param token the token
* @return the signed jwt
*/
public static SignedJWT parseToken(String token) {
try {
return SignedJWT.parse(token);
Expand All @@ -64,6 +88,13 @@ public static SignedJWT parseToken(String token) {
}
}

/**
* Gets string claim.
*
* @param claimsSet the claims set
* @param name the name
* @return the string claim
*/
public static String getStringClaim(JWTClaimsSet claimsSet, String name) {
try {
return claimsSet.getStringClaim(name);
Expand All @@ -72,6 +103,12 @@ public static String getStringClaim(JWTClaimsSet claimsSet, String name) {
}
}

/**
* Gets access token.
*
* @param claims the claims
* @return the access token
*/
public static Optional<String> getAccessToken(JWTClaimsSet claims) {
try {
String accessTokenValue = claims.getStringClaim(ACCESS_TOKEN);
Expand All @@ -81,13 +118,25 @@ public static Optional<String> getAccessToken(JWTClaimsSet claims) {
}
}

/**
* Gets access token.
*
* @param outerToken the outer token
* @return the access token
*/
public static SignedJWT getAccessToken(String outerToken) {
SignedJWT jwtOuter = parseToken(outerToken);
JWTClaimsSet claimsSet = getClaimsSet(jwtOuter);
Optional<String> accessToken = getAccessToken(claimsSet);
return accessToken.map(TokenParsingUtils::parseToken).orElseThrow(() -> new BadDataException(ACCESS_TOKEN_ERROR));
}

/**
* Gets scope.
*
* @param jwtClaimsSet the jwt claims set
* @return the scope
*/
public static String getScope(JWTClaimsSet jwtClaimsSet) {
try {
String scopes = jwtClaimsSet.getStringClaim(SCOPE);
Expand All @@ -100,6 +149,12 @@ public static String getScope(JWTClaimsSet jwtClaimsSet) {
}
}

/**
* Gets jti access token.
*
* @param accessToken the access token
* @return the jti access token
*/
public static String getJtiAccessToken(JWT accessToken) {
try {
return getStringClaim(accessToken.getJWTClaimsSet(), JTI);
Expand All @@ -108,6 +163,12 @@ public static String getJtiAccessToken(JWT accessToken) {
}
}

/**
* Gets nonce access token.
*
* @param accessToken the access token
* @return the nonce access token
*/
public static String getNonceAccessToken(JWT accessToken) {
try {
return accessToken.getJWTClaimsSet().getStringClaim(NONCE);
Expand All @@ -116,6 +177,12 @@ public static String getNonceAccessToken(JWT accessToken) {
}
}

/**
* Gets bpn from token.
*
* @param authentication the authentication
* @return the bpn from token
*/
public static String getBPNFromToken(Authentication authentication) {
Jwt jwt = ((JwtAuthenticationToken) authentication).getToken();
// this will misbehave if we have more then one claims with different case
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/*
* *******************************************************************************
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
* ******************************************************************************
*/

package org.eclipse.tractusx.managedidentitywallets.utils;

import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.eclipse.tractusx.managedidentitywallets.constant.StringPool;
import org.eclipse.tractusx.managedidentitywallets.exception.BadDataException;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtClaimNames;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;

import java.text.ParseException;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

class TokenParsingUtilsTest {

@Test
void parseTokenShouldReturnSignedJWTWhenTokenIsValid() throws ParseException {
String token = "valid.token.here";
SignedJWT signedJWT = mock(SignedJWT.class);

try (MockedStatic<SignedJWT> mockedSignedJWT = mockStatic(SignedJWT.class)) {
mockedSignedJWT.when(() -> SignedJWT.parse(token)).thenReturn(signedJWT);

SignedJWT result = TokenParsingUtils.parseToken(token);

assertEquals(signedJWT, result);
}
}

@Test
void parseTokenShouldThrowBadDataExceptionWhenParseExceptionOccurs() throws ParseException {
String token = "invalid.token.here";

try (MockedStatic<SignedJWT> mockedSignedJWT = mockStatic(SignedJWT.class)) {
mockedSignedJWT.when(() -> SignedJWT.parse(token)).thenThrow(ParseException.class);

BadDataException exception = assertThrows(BadDataException.class, () -> TokenParsingUtils.parseToken(token));

assertEquals(TokenParsingUtils.PARSING_TOKEN_ERROR, exception.getMessage());
}
}

@Test
void getAccessTokenShouldReturnInnerSignedJWTWhenAccessTokenIsPresent() throws ParseException {
String outerToken = "outer.token.here";
SignedJWT outerSignedJWT = mock(SignedJWT.class);
JWTClaimsSet outerClaimsSet = new JWTClaimsSet.Builder().claim("access_token", "inner.token.here").build();
SignedJWT innerSignedJWT = mock(SignedJWT.class);

try (MockedStatic<SignedJWT> mockedSignedJWT = mockStatic(SignedJWT.class)) {
mockedSignedJWT.when(() -> SignedJWT.parse(outerToken)).thenReturn(outerSignedJWT);
mockedSignedJWT.when(() -> SignedJWT.parse("inner.token.here")).thenReturn(innerSignedJWT);
when(outerSignedJWT.getJWTClaimsSet()).thenReturn(outerClaimsSet);

SignedJWT result = TokenParsingUtils.getAccessToken(outerToken);

assertEquals(innerSignedJWT, result);
}
}

@Test
void getAccessTokenShouldThrowBadDataExceptionWhenAccessTokenIsNotPresent() throws ParseException {
String outerToken = "outer.token.here";
SignedJWT outerSignedJWT = mock(SignedJWT.class);
JWTClaimsSet outerClaimsSet = new JWTClaimsSet.Builder().build();

try (MockedStatic<SignedJWT> mockedSignedJWT = mockStatic(SignedJWT.class)) {
mockedSignedJWT.when(() -> SignedJWT.parse(outerToken)).thenReturn(outerSignedJWT);
when(outerSignedJWT.getJWTClaimsSet()).thenReturn(outerClaimsSet);

BadDataException exception = assertThrows(BadDataException.class, () -> TokenParsingUtils.getAccessToken(outerToken));

assertEquals(TokenParsingUtils.ACCESS_TOKEN_ERROR, exception.getMessage());
}
}

@Test
void getBPNFromTokenShouldReturnBPNWhenBPNClaimIsPresent() {
Authentication authentication = mock(JwtAuthenticationToken.class);
Jwt jwt = mock(Jwt.class);
when(((JwtAuthenticationToken) authentication).getToken()).thenReturn(jwt);
Map<String, Object> claims = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
claims.put(StringPool.BPN, "123456");
when(jwt.getClaims()).thenReturn(claims);

String result = TokenParsingUtils.getBPNFromToken(authentication);

assertEquals("123456", result);
}

// Other test methods for TokenParsingUtils...

@Test
void getStringClaimShouldReturnClaimValueWhenClaimIsPresent() throws ParseException {
JWTClaimsSet claimsSet = mock(JWTClaimsSet.class);
when(claimsSet.getStringClaim("claim")).thenReturn("value");

String result = TokenParsingUtils.getStringClaim(claimsSet, "claim");

assertEquals("value", result);
}

@Test
void getStringClaimShouldThrowBadDataExceptionWhenParseExceptionOccurs() throws ParseException {
JWTClaimsSet claimsSet = mock(JWTClaimsSet.class);
when(claimsSet.getStringClaim("claim")).thenThrow(ParseException.class);

BadDataException exception = assertThrows(BadDataException.class, () -> TokenParsingUtils.getStringClaim(claimsSet, "claim"));

assertEquals(TokenParsingUtils.PARSING_TOKEN_ERROR, exception.getMessage());
}

@Test
void getAccessTokenShouldReturnAccessTokenWhenAccessTokenIsPresent() throws ParseException {
JWTClaimsSet claimsSet = mock(JWTClaimsSet.class);
when(claimsSet.getStringClaim("access_token")).thenReturn("accessToken");

Optional<String> result = TokenParsingUtils.getAccessToken(claimsSet);

assertTrue(result.isPresent());
assertEquals("accessToken", result.get());
}

@Test
void getAccessTokenShouldReturnEmptyOptionalWhenAccessTokenIsNotPresent() throws ParseException {
JWTClaimsSet claimsSet = mock(JWTClaimsSet.class);
when(claimsSet.getStringClaim("access_token")).thenReturn(null);

Optional<String> result = TokenParsingUtils.getAccessToken(claimsSet);

assertFalse(result.isPresent());
}

@Test
void getAccessTokenShouldThrowBadDataExceptionWhenParseExceptionOccurs() throws ParseException {
JWTClaimsSet claimsSet = mock(JWTClaimsSet.class);
when(claimsSet.getStringClaim("access_token")).thenThrow(ParseException.class);

BadDataException exception = assertThrows(BadDataException.class, () -> TokenParsingUtils.getAccessToken(claimsSet));

assertEquals(TokenParsingUtils.PARSING_TOKEN_ERROR, exception.getMessage());
}

@Test
void getScopeShouldReturnScopeWhenScopeIsPresent() throws ParseException {
JWTClaimsSet claimsSet = mock(JWTClaimsSet.class);
when(claimsSet.getStringClaim("scope")).thenReturn("scope1 scope2");

String result = TokenParsingUtils.getScope(claimsSet);

assertEquals("scope1 scope2", result);
}

@Test
void getScopeShouldReturnBearerAccessScopeWhenScopeIsNotPresentButBearerAccessScopeIs() throws ParseException {
JWTClaimsSet claimsSet = mock(JWTClaimsSet.class);
when(claimsSet.getStringClaim("scope")).thenReturn(null);
when(claimsSet.getStringClaim(TokenParsingUtils.BEARER_ACCESS_SCOPE)).thenReturn("bearerAccessScope");

String result = TokenParsingUtils.getScope(claimsSet);

assertEquals("bearerAccessScope", result);
}

@Test
void getScopeShouldThrowBadDataExceptionWhenParseExceptionOccurs() throws ParseException {
JWTClaimsSet claimsSet = mock(JWTClaimsSet.class);
when(claimsSet.getStringClaim("scope")).thenThrow(ParseException.class);

BadDataException exception = assertThrows(BadDataException.class, () -> TokenParsingUtils.getScope(claimsSet));

assertEquals("Token does not contain scope claim", exception.getMessage());
}

@Test
void getJtiAccessTokenShouldReturnJtiWhenClaimIsPresent() throws ParseException {
JWTClaimsSet claimsSet = mock(JWTClaimsSet.class);
when(claimsSet.getStringClaim(JwtClaimNames.JTI)).thenReturn("jtiValue");
SignedJWT signedJWT = mock(SignedJWT.class);
when(signedJWT.getJWTClaimsSet()).thenReturn(claimsSet);

String result = TokenParsingUtils.getJtiAccessToken(signedJWT);

assertEquals("jtiValue", result);
}

@Test
void getJtiAccessTokenShouldThrowBadDataExceptionWhenParseExceptionOccurs() throws ParseException {
JWTClaimsSet claimsSet = mock(JWTClaimsSet.class);
when(claimsSet.getStringClaim(JwtClaimNames.JTI)).thenThrow(ParseException.class);
SignedJWT signedJWT = mock(SignedJWT.class);
when(signedJWT.getJWTClaimsSet()).thenReturn(claimsSet);

BadDataException exception = assertThrows(BadDataException.class, () -> TokenParsingUtils.getJtiAccessToken(signedJWT));

assertEquals(TokenParsingUtils.PARSING_TOKEN_ERROR, exception.getMessage());
}

}

0 comments on commit a4fa6cc

Please sign in to comment.