Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert kernel core change for auth adapter 1 #1419

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions kernel/kernel-authcodeflowproxy-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@
<micrometer.registry.prometheus.version>1.4.2</micrometer.registry.prometheus.version>
<kernel.core.version>1.2.1-SNAPSHOT</kernel.core.version>
<jacoco.maven.plugin.version>0.8.5</jacoco.maven.plugin.version>
<powermock.version>2.0.0</powermock.version>
</properties>
<dependencies>
<dependency>
Expand All @@ -240,18 +239,6 @@
<artifactId>jwks-rsa</artifactId>
<version>0.18.0</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<distributionManagement>
<snapshotRepository>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -34,20 +33,11 @@
@RestController
public class LoginController {

private static final String ID_TOKEN = "id_token";

private final static Logger LOGGER= LoggerFactory.getLogger(LoginController.class);
private static final String IDTOKEN = "idToken";

@Value("${auth.token.header:Authorization}")
private String authTokenHeader;

@Value("${iam.locale.cookie.name:KEYCLOAK_LOCALE}")
private String localeCookieName;

@Value("${iam.locale.cookie.name:/auth/realms/}")
private String localeCookiePath;


@Value("#{'${auth.allowed.urls}'.split(',')}")
private List<String> allowedUrls;
Expand All @@ -56,13 +46,7 @@ public class LoginController {
private LoginService loginService;

@Autowired
private ValidateTokenHelper validateTokenHelper;

@Autowired
private Environment environment;

@Value("${auth.validate.id-token:false}")
private boolean validateIdToken;
private ValidateTokenHelper validateTokenHelper;

@GetMapping(value = "/login/{redirectURI}")
public void login(@CookieValue(name = "state", required = false) String state,
Expand All @@ -88,34 +72,27 @@ public void login(@CookieValue(name = "state", required = false) String state,

String uri = loginService.login(redirectURI, stateValue);
Cookie stateCookie = new Cookie("state", stateValue);
setCookieParams(stateCookie,true,true,"/");
stateCookie.setHttpOnly(true);
stateCookie.setSecure(true);
stateCookie.setPath("/");
res.addCookie(stateCookie);
res.setStatus(302);
res.sendRedirect(uri);
}

@GetMapping(value = "/login-redirect/{redirectURI}")
public void loginRedirect(@PathVariable("redirectURI") String redirectURI, @RequestParam("state") String state,
@RequestParam(value="session_state",required = false) String sessionState, @RequestParam("code") String code,
@CookieValue("state") String stateCookie, HttpServletRequest req, HttpServletResponse res) throws IOException {
@RequestParam("session_state") String sessionState, @RequestParam("code") String code,
@CookieValue("state") String stateCookie, HttpServletResponse res) throws IOException {
AccessTokenResponseDTO jwtResponseDTO = loginService.loginRedirect(state, sessionState, code, stateCookie,
redirectURI);
String accessToken = jwtResponseDTO.getAccessToken();
validateToken(accessToken);
String idToken = jwtResponseDTO.getIdToken();
validateToken(idToken);
Cookie cookie = loginService.createCookie(accessToken);
res.addCookie(cookie);
if(validateIdToken) {
String idTokenProperty = this.environment.getProperty(IDTOKEN, ID_TOKEN);
String idToken = jwtResponseDTO.getIdToken();
if(idToken == null) {
throw new ClientException(Errors.TOKEN_NOTPRESENT_ERROR.getErrorCode(),
Errors.TOKEN_NOTPRESENT_ERROR.getErrorMessage() + ": " + idTokenProperty);
}
validateToken(idToken);
Cookie idTokenCookie = new Cookie(idTokenProperty, idToken);
setCookieParams(idTokenCookie,true,true,"/");
res.addCookie(idTokenCookie);
}
res.addCookie(new Cookie("id_token", idToken));
res.setStatus(302);
String url = new String(Base64.decodeBase64(redirectURI.getBytes()));
if(url.contains("#")) {
Expand All @@ -126,13 +103,7 @@ public void loginRedirect(@PathVariable("redirectURI") String redirectURI, @Requ
throw new ServiceException(Errors.ALLOWED_URL_EXCEPTION.getErrorCode(), Errors.ALLOWED_URL_EXCEPTION.getErrorMessage());
}
res.sendRedirect(url);
}

private void setCookieParams(Cookie idTokenCookie, boolean isHttpOnly, boolean isSecure,String path) {
idTokenCookie.setHttpOnly(isHttpOnly);
idTokenCookie.setSecure(isSecure);
idTokenCookie.setPath(path);
}
}

private void validateToken(String accessToken) {
if(!validateTokenHelper.isTokenValid(accessToken).getKey()){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,8 @@ public ResponseEntity<ResponseWrapper<ServiceError>> clientException(
public ResponseEntity<ResponseWrapper<ServiceError>> servieException(
HttpServletRequest httpServletRequest, final ServiceException e) throws IOException {
ExceptionUtils.logRootCause(e);
HttpStatus status;
if(e.getErrorCode().equals(Errors.INVALID_TOKEN.getErrorCode())) {
status = HttpStatus.UNAUTHORIZED;
} else {
status = HttpStatus.OK;
}
return new ResponseEntity<>(
getErrorResponse(httpServletRequest, e.getErrorCode(), e.getErrorText()), status);
getErrorResponse(httpServletRequest, e.getErrorCode(), e.getErrorText()), HttpStatus.OK);
}

@ExceptionHandler(AuthenticationServiceException.class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.mosip.kernel.authcodeflowproxy.api.service.validator;

import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;

import io.mosip.kernel.core.authmanager.authadapter.model.AuthUserDetails;
/**
* Validator used to validate the scope in the token
*
* @author Loganathan S
*
*/
@Component("scopeValidator")
public class ScopeValidator {

private static final String SCOPE = "scope";

public static boolean hasAllScopes(List<String> scopes) {
return hasScopes(scopes, Stream::allMatch);
}

public static boolean hasAnyScopes(List<String> scopes) {
return hasScopes(scopes, Stream::anyMatch);
}

public static boolean hasScope(String scope) {
return hasAllScopes(List.of(scope));
}

public static boolean hasScopes(List<String> scopes, BiPredicate<Stream<String>, Predicate<? super String>> condition) {
List<? extends String> scopesInToken = getScopes();
return condition.test(scopes.stream(), scopesInToken::contains);
}

private static List<String> getScopes() {
Object principal = SecurityContextHolder
.getContext()
.getAuthentication().getPrincipal();
if(principal instanceof AuthUserDetails) {
AuthUserDetails authUserDetails = (AuthUserDetails) principal;
String jwtToken = authUserDetails.getToken();
DecodedJWT decodedJWT = JWT.decode(jwtToken);
String scpoeClaim = decodedJWT.getClaim(SCOPE).asString();
List<String> scopes = Stream.of( scpoeClaim.split(" ")).collect(Collectors.toList());
return scopes;
}

return List.of();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.impl.NullClaim;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

import io.mosip.kernel.authcodeflowproxy.api.constants.AuthConstant;
Expand Down Expand Up @@ -103,7 +101,8 @@ public ImmutablePair<Boolean, AuthErrorCode> isTokenValid(DecodedJWT decodedJWT)
}

// Second, issuer domain check.
if (validateIssuerDomain && !getTokenIssuerDomain(decodedJWT)) {
boolean tokenDomainMatch = getTokenIssuerDomain(decodedJWT);
if (validateIssuerDomain && !tokenDomainMatch) {
LOGGER.error(
"Provided Auth Token Issue domain does not match. Throwing Authentication Exception. UserName: "
+ userName);
Expand All @@ -118,8 +117,9 @@ public ImmutablePair<Boolean, AuthErrorCode> isTokenValid(DecodedJWT decodedJWT)
}

// Fourth, audience | azp validation.
boolean matchFound = validateAudience(decodedJWT);
// No match found after comparing audience & azp
if (validateAudClaim && !validateAudience(decodedJWT)) {
if (!matchFound) {
LOGGER.error("Provided Client Id does not match with Aud/AZP. Throwing Authorizaion Exception. UserName: "
+ userName);
return ImmutablePair.of(Boolean.FALSE, AuthErrorCode.FORBIDDEN);
Expand All @@ -128,17 +128,18 @@ public ImmutablePair<Boolean, AuthErrorCode> isTokenValid(DecodedJWT decodedJWT)
}

private boolean validateAudience(DecodedJWT decodedJWT) {
boolean matchFound;
boolean matchFound = false;
if (validateAudClaim) {

List<String> tokenAudience = decodedJWT.getAudience();
matchFound = tokenAudience != null && tokenAudience.stream().anyMatch(allowedAudience::contains);
List<String> tokenAudience = decodedJWT.getAudience();
matchFound = tokenAudience.stream().anyMatch(allowedAudience::contains);

// comparing with azp.
if (!matchFound) {
Claim azp = decodedJWT.getClaim(AuthConstant.AZP);
matchFound = azp != null && !(azp instanceof NullClaim) && allowedAudience.stream().anyMatch(azp.asString()::equalsIgnoreCase);
// comparing with azp.
String azp = decodedJWT.getClaim(AuthConstant.AZP).asString();
if (!matchFound) {
matchFound = allowedAudience.stream().anyMatch(azp::equalsIgnoreCase);
}
}

return matchFound;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ io.mosip.kernel.authcodeflowproxy.api.controller.LoginController,\
io.mosip.kernel.authcodeflowproxy.api.service.impl.LoginServiceImpl,\
io.mosip.kernel.authcodeflowproxy.api.config.AuthCodeProxyConfig,\
io.mosip.kernel.authcodeflowproxy.api.exception.AuthCodeProxyExceptionHandler,\
io.mosip.kernel.authcodeflowproxy.api.service.validator.ValidateTokenHelper
io.mosip.kernel.authcodeflowproxy.api.service.validator.ValidateTokenHelper,\
io.mosip.kernel.authcodeflowproxy.api.service.validator.ScopeValidator
Loading