From 643ba0780b5bf9f7383357075adb505774a39a27 Mon Sep 17 00:00:00 2001 From: Arnab Dutta Date: Tue, 31 Oct 2023 13:58:41 +0530 Subject: [PATCH] feat: adding scopes in config-api endpoint access token based on tags (admin-ui) #6413 (#6414) Signed-off-by: Arnab Dutta --- .../model/config/adminui/AdminPermission.java | 18 ++- .../adminui/model/auth/ApiTokenRequest.java | 24 ++++ .../adminui/rest/auth/OAuth2Resource.java | 57 +------- .../plugin/adminui/service/BaseService.java | 8 +- .../adminui/service/auth/OAuth2Service.java | 126 ++---------------- 5 files changed, 59 insertions(+), 174 deletions(-) create mode 100644 jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/auth/ApiTokenRequest.java diff --git a/jans-auth-server/model/src/main/java/io/jans/as/model/config/adminui/AdminPermission.java b/jans-auth-server/model/src/main/java/io/jans/as/model/config/adminui/AdminPermission.java index 66d979541ca..ef7392903f7 100644 --- a/jans-auth-server/model/src/main/java/io/jans/as/model/config/adminui/AdminPermission.java +++ b/jans-auth-server/model/src/main/java/io/jans/as/model/config/adminui/AdminPermission.java @@ -3,6 +3,7 @@ import java.util.Objects; public class AdminPermission { + private String tag; private String permission; private String description; private Boolean defaultPermissionInToken; @@ -31,25 +32,34 @@ public void setDefaultPermissionInToken(Boolean defaultPermissionInToken) { this.defaultPermissionInToken = defaultPermissionInToken; } + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AdminPermission that = (AdminPermission) o; - return permission.equals(that.permission); + return tag.equals(that.tag) && permission.equals(that.permission) && Objects.equals(description, that.description) && Objects.equals(defaultPermissionInToken, that.defaultPermissionInToken); } @Override public int hashCode() { - return Objects.hash(permission); + return Objects.hash(tag, permission, description, defaultPermissionInToken); } @Override public String toString() { return "AdminPermission{" + - "permission='" + permission + '\'' + + "tag='" + tag + '\'' + + ", permission='" + permission + '\'' + ", description='" + description + '\'' + - ", defaultPermissionInToken='" + defaultPermissionInToken + '\'' + + ", defaultPermissionInToken=" + defaultPermissionInToken + '}'; } } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/auth/ApiTokenRequest.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/auth/ApiTokenRequest.java new file mode 100644 index 00000000000..c1ade7a1da5 --- /dev/null +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/auth/ApiTokenRequest.java @@ -0,0 +1,24 @@ +package io.jans.ca.plugin.adminui.model.auth; + +import java.util.List; + +public class ApiTokenRequest { + private List permissionTag; + private String ujwt; + + public List getPermissionTag() { + return permissionTag; + } + + public void setPermissionTag(List permissionTag) { + this.permissionTag = permissionTag; + } + + public String getUjwt() { + return ujwt; + } + + public void setUjwt(String ujwt) { + this.ujwt = ujwt; + } +} diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/auth/OAuth2Resource.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/auth/OAuth2Resource.java index bfc702e3d5d..85049a19a48 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/auth/OAuth2Resource.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/auth/OAuth2Resource.java @@ -1,9 +1,8 @@ package io.jans.ca.plugin.adminui.rest.auth; +import io.jans.ca.plugin.adminui.model.auth.ApiTokenRequest; import io.jans.ca.plugin.adminui.model.auth.OAuth2ConfigResponse; import io.jans.ca.plugin.adminui.model.auth.TokenResponse; -import io.jans.ca.plugin.adminui.model.auth.UserInfoRequest; -import io.jans.ca.plugin.adminui.model.auth.UserInfoResponse; import io.jans.ca.plugin.adminui.model.config.AUIConfiguration; import io.jans.ca.plugin.adminui.model.exception.ApplicationException; import io.jans.ca.plugin.adminui.service.auth.OAuth2Service; @@ -76,37 +75,13 @@ public Response getOAuth2Config(@PathParam("appType") String appType) { } } - @GET - @Path(OAUTH2_ACCESS_TOKEN) - @Produces(MediaType.APPLICATION_JSON) - public Response getAccessToken(@QueryParam("code") String code, @PathParam("codeVerifier") String codeVerifier, @PathParam("appType") String appType) { - try { - log.info("Access token request to Auth Server."); - TokenResponse tokenResponse = oAuth2Service.getAccessToken(code, codeVerifier, appType); - log.info("Access token received from Auth Server."); - return Response.ok(tokenResponse).build(); - } catch (ApplicationException e) { - log.error(ErrorResponse.GET_ACCESS_TOKEN_ERROR.getDescription(), e); - return Response - .status(e.getErrorCode()) - .entity(CommonUtils.createGenericResponse(false, e.getErrorCode(), e.getMessage())) - .build(); - } catch (Exception e) { - log.error(ErrorResponse.GET_ACCESS_TOKEN_ERROR.getDescription(), e); - return Response - .serverError() - .entity(CommonUtils.createGenericResponse(false, 500, ErrorResponse.GET_ACCESS_TOKEN_ERROR.getDescription())) - .build(); - } - } - - @GET + @POST @Path(OAUTH2_API_PROTECTION_TOKEN) @Produces(MediaType.APPLICATION_JSON) - public Response getApiProtectionToken(@QueryParam("ujwt") String ujwt, @PathParam("appType") String appType) { + public Response getApiProtectionToken(@Valid @NotNull ApiTokenRequest apiTokenRequest, @PathParam("appType") String appType) { try { log.info("Api protection token request to Auth Server."); - TokenResponse tokenResponse = oAuth2Service.getApiProtectionToken(ujwt, appType); + TokenResponse tokenResponse = oAuth2Service.getApiProtectionToken(apiTokenRequest, appType); log.info("Api protection token received from Auth Server."); return Response.ok(tokenResponse).build(); } catch (ApplicationException e) { @@ -124,28 +99,4 @@ public Response getApiProtectionToken(@QueryParam("ujwt") String ujwt, @PathPara } } - @POST - @Path(OAUTH2_API_USER_INFO) - @Produces(MediaType.APPLICATION_JSON) - public Response getUserInfo(@Valid @NotNull UserInfoRequest userInfoRequest, @PathParam("appType") String appType) { - try { - log.info("Get User-Info request to Auth Server."); - UserInfoResponse userInfoResponse = oAuth2Service.getUserInfo(userInfoRequest, appType); - log.info("Get User-Info received from Auth Server."); - return Response.ok(userInfoResponse).build(); - } catch (ApplicationException e) { - log.error(ErrorResponse.GET_USER_INFO_ERROR.getDescription(), e); - return Response - .status(e.getErrorCode()) - .entity(CommonUtils.createGenericResponse(false, e.getErrorCode(), e.getMessage())) - .build(); - } catch (Exception e) { - log.error(ErrorResponse.GET_USER_INFO_ERROR.getDescription(), e); - return Response - .serverError() - .entity(CommonUtils.createGenericResponse(false, 500, ErrorResponse.GET_USER_INFO_ERROR.getDescription())) - .build(); - } - } - } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/BaseService.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/BaseService.java index 5f796947695..661c27b52ff 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/BaseService.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/BaseService.java @@ -31,7 +31,7 @@ public class BaseService { Logger log; public io.jans.as.client.TokenResponse getToken(TokenRequest tokenRequest, String tokenEndpoint) { - return getToken(tokenRequest, tokenEndpoint, null); + return getToken(tokenRequest, tokenEndpoint, null, null); } /** @@ -42,7 +42,7 @@ public io.jans.as.client.TokenResponse getToken(TokenRequest tokenRequest, Strin * @param userInfoJwt This is the JWT that is returned from the userinfo endpoint. * @return A TokenResponse object */ - public io.jans.as.client.TokenResponse getToken(TokenRequest tokenRequest, String tokenEndpoint, String userInfoJwt) { + public io.jans.as.client.TokenResponse getToken(TokenRequest tokenRequest, String tokenEndpoint, String userInfoJwt, List permissionTags) { try { MultivaluedMap body = new MultivaluedHashMap<>(); @@ -58,6 +58,10 @@ public io.jans.as.client.TokenResponse getToken(TokenRequest tokenRequest, Strin body.putSingle("ujwt", userInfoJwt); } + if (permissionTags != null && !permissionTags.isEmpty()) { + body.put("permission_tag", Collections.singletonList(String.join(" ", permissionTags))); + } + if (!Strings.isNullOrEmpty(tokenRequest.getCodeVerifier())) { body.putSingle("code_verifier", tokenRequest.getCodeVerifier()); } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/auth/OAuth2Service.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/auth/OAuth2Service.java index fe4f2d37231..3d46144efa1 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/auth/OAuth2Service.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/auth/OAuth2Service.java @@ -1,33 +1,23 @@ package io.jans.ca.plugin.adminui.service.auth; import com.google.common.base.Strings; -import com.google.common.collect.Maps; import com.google.common.collect.Sets; import io.jans.as.client.TokenRequest; import io.jans.as.common.service.common.EncryptionService; import io.jans.as.model.common.GrantType; import io.jans.as.model.jwt.Jwt; -import io.jans.as.model.jwt.JwtClaims; +import io.jans.ca.plugin.adminui.model.auth.ApiTokenRequest; import io.jans.ca.plugin.adminui.model.auth.TokenResponse; -import io.jans.ca.plugin.adminui.model.auth.UserInfoRequest; -import io.jans.ca.plugin.adminui.model.auth.UserInfoResponse; import io.jans.ca.plugin.adminui.model.config.AUIConfiguration; import io.jans.ca.plugin.adminui.model.exception.ApplicationException; import io.jans.ca.plugin.adminui.rest.auth.OAuth2Resource; import io.jans.ca.plugin.adminui.service.BaseService; import io.jans.ca.plugin.adminui.service.config.AUIConfigurationService; -import io.jans.ca.plugin.adminui.utils.ClientFactory; import io.jans.ca.plugin.adminui.utils.CommonUtils; import io.jans.ca.plugin.adminui.utils.ErrorResponse; import jakarta.inject.Inject; import jakarta.inject.Singleton; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.Invocation; -import jakarta.ws.rs.core.MultivaluedHashMap; -import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.Response; -import org.json.JSONArray; -import org.json.JSONObject; import org.slf4j.Logger; import java.io.UnsupportedEncodingException; @@ -50,48 +40,7 @@ public class OAuth2Service extends BaseService { /** * Calls token endpoint from the Identity Provider and returns a valid Access Token. */ - public TokenResponse getAccessToken(String code, String codeVerifier, String appType) throws ApplicationException { - try { - log.debug("Getting access token with code"); - if (Strings.isNullOrEmpty(code)) { - log.error(ErrorResponse.AUTHORIZATION_CODE_BLANK.getDescription()); - throw new ApplicationException(Response.Status.BAD_REQUEST.getStatusCode(), ErrorResponse.AUTHORIZATION_CODE_BLANK.getDescription()); - } - if (Strings.isNullOrEmpty(codeVerifier)) { - log.error(ErrorResponse.CODE_VERIFIER_REQUIRED.getDescription()); - throw new ApplicationException(Response.Status.BAD_REQUEST.getStatusCode(), ErrorResponse.CODE_VERIFIER_REQUIRED.getDescription()); - } - AUIConfiguration auiConfiguration = auiConfigurationService.getAUIConfiguration(appType); - - TokenRequest tokenRequest = new TokenRequest(GrantType.AUTHORIZATION_CODE); - tokenRequest.setCode(code); - tokenRequest.setCodeVerifier(codeVerifier); - tokenRequest.setAuthUsername(auiConfiguration.getAuiWebServerClientId()); - tokenRequest.setAuthPassword(encryptionService.decrypt(auiConfiguration.getAuiWebServerClientSecret())); - tokenRequest.setGrantType(GrantType.AUTHORIZATION_CODE); - tokenRequest.setRedirectUri(auiConfiguration.getAuiWebServerRedirectUrl()); - tokenRequest.setScope(auiConfiguration.getAuiWebServerScope()); - io.jans.as.client.TokenResponse tokenResponse = getToken(tokenRequest, auiConfiguration.getAuiWebServerTokenEndpoint()); - - TokenResponse tokenResp = new TokenResponse(); - tokenResp.setAccessToken(tokenResponse.getAccessToken()); - tokenResp.setIdToken(tokenResponse.getIdToken()); - tokenResp.setRefreshToken(tokenResponse.getRefreshToken()); - - return tokenResp; - } catch (ApplicationException e) { - log.error(ErrorResponse.GET_ACCESS_TOKEN_ERROR.getDescription()); - throw e; - } catch (Exception e) { - log.error(ErrorResponse.GET_ACCESS_TOKEN_ERROR.getDescription(), e); - throw new ApplicationException(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ErrorResponse.GET_ACCESS_TOKEN_ERROR.getDescription()); - } - } - - /** - * Calls token endpoint from the Identity Provider and returns a valid Access Token. - */ - public TokenResponse getApiProtectionToken(String userInfoJwt, String appType) throws ApplicationException { + public TokenResponse getApiProtectionToken(ApiTokenRequest apiTokenRequest, String appType) throws ApplicationException { try { log.debug("Getting api-protection token"); @@ -103,11 +52,17 @@ public TokenResponse getApiProtectionToken(String userInfoJwt, String appType) t tokenRequest.setGrantType(GrantType.CLIENT_CREDENTIALS); tokenRequest.setRedirectUri(auiConfiguration.getAuiBackendApiServerRedirectUrl()); - if (Strings.isNullOrEmpty(userInfoJwt)) { - log.warn(ErrorResponse.USER_INFO_JWT_BLANK.getDescription()); + io.jans.as.client.TokenResponse tokenResponse = null; + if (apiTokenRequest == null) { tokenRequest.setScope(scopeAsString(Arrays.asList(OAuth2Resource.SCOPE_OPENID))); + tokenResponse = getToken(tokenRequest, auiConfiguration.getAuiBackendApiServerTokenEndpoint()); + } else { + if (Strings.isNullOrEmpty(apiTokenRequest.getUjwt())) { + log.warn(ErrorResponse.USER_INFO_JWT_BLANK.getDescription()); + tokenRequest.setScope(scopeAsString(Arrays.asList(OAuth2Resource.SCOPE_OPENID))); + } + tokenResponse = getToken(tokenRequest, auiConfiguration.getAuiBackendApiServerTokenEndpoint(), apiTokenRequest.getUjwt(), apiTokenRequest.getPermissionTag()); } - io.jans.as.client.TokenResponse tokenResponse = getToken(tokenRequest, auiConfiguration.getAuiBackendApiServerTokenEndpoint(), userInfoJwt); final Jwt tokenJwt = Jwt.parse(tokenResponse.getAccessToken()); Map claims = getClaims(tokenJwt); @@ -142,65 +97,6 @@ public TokenResponse getApiProtectionToken(String userInfoJwt, String appType) t } } - public UserInfoResponse getUserInfo(UserInfoRequest userInfoRequest, String appType) throws ApplicationException { - try { - log.debug("Getting User-Info from auth-server: {}", userInfoRequest.getAccessToken()); - AUIConfiguration auiConfiguration = auiConfigurationService.getAUIConfiguration(appType); - - String accessToken = org.apache.logging.log4j.util.Strings.isNotBlank(userInfoRequest.getAccessToken()) ? userInfoRequest.getAccessToken() : null; - - if (Strings.isNullOrEmpty(userInfoRequest.getCode()) && Strings.isNullOrEmpty(accessToken)) { - log.error(ErrorResponse.CODE_OR_TOKEN_REQUIRED.getDescription()); - throw new ApplicationException(Response.Status.BAD_REQUEST.getStatusCode(), ErrorResponse.CODE_OR_TOKEN_REQUIRED.getDescription()); - } - - if (Strings.isNullOrEmpty(userInfoRequest.getCodeVerifier())) { - log.error(ErrorResponse.CODE_VERIFIER_REQUIRED.getDescription()); - throw new ApplicationException(Response.Status.BAD_REQUEST.getStatusCode(), ErrorResponse.CODE_VERIFIER_REQUIRED.getDescription()); - } - - if (org.apache.logging.log4j.util.Strings.isNotBlank(userInfoRequest.getCode()) && org.apache.logging.log4j.util.Strings.isBlank(accessToken)) { - TokenResponse tokenResponse = getAccessToken(userInfoRequest.getCode(), userInfoRequest.getCodeVerifier(), appType); - accessToken = tokenResponse.getAccessToken(); - } - log.debug("Access Token : {}", accessToken); - - MultivaluedMap body = new MultivaluedHashMap<>(); - body.putSingle("access_token", accessToken); - - Invocation.Builder request = ClientFactory.instance().getClientBuilder(auiConfiguration.getAuiWebServerUserInfoEndpoint()); - request.header("Authorization", "Bearer " + accessToken); - - Response response = request - .post(Entity.form(body)); - - log.debug("User-Info response status code: {}", response.getStatus()); - - if (response.getStatus() == 200) { - String entity = response.readEntity(String.class); - log.debug("User-Info response entity: {}", entity); - final Jwt jwtUserInfo = Jwt.parse(entity); - - log.debug("User-Info response jwtUserInfo: {}", jwtUserInfo); - - UserInfoResponse userInfoResponse = new UserInfoResponse(); - userInfoResponse.setClaims(getClaims(jwtUserInfo)); - userInfoResponse.setJwtUserInfo(entity); - - log.debug("User-Info response userInfoResponse: {}", userInfoResponse); - return userInfoResponse; - } - - } catch (ApplicationException e) { - log.error(ErrorResponse.GET_USER_INFO_ERROR.getDescription()); - throw e; - } catch (Exception e) { - log.error(ErrorResponse.GET_USER_INFO_ERROR.getDescription(), e); - throw new ApplicationException(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ErrorResponse.GET_USER_INFO_ERROR.getDescription()); - } - return null; - } - private static String scopeAsString(List scopes) throws UnsupportedEncodingException { Set scope = Sets.newHashSet(); scope.addAll(scopes);