From fe98d92f35c1ef0b9a9d4155318c70272ca24ad1 Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Wed, 9 Nov 2022 22:43:58 +0530 Subject: [PATCH 01/28] fix(config-api): fix for swagger spec for scope creation and sessoin endpoint filter --- .../io/jans/configapi/util/ApiConstants.java | 1 + .../docs/jans-config-api-swagger-auto.yaml | 34 +- .../docs/jans-config-api-swagger.yaml | 334 ++++-------------- .../security/api/ApiProtectionService.java | 30 +- .../service/auth/SessionService.java | 5 +- 5 files changed, 101 insertions(+), 303 deletions(-) diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java index a825394e5ed..6b55995ce24 100644 --- a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java +++ b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java @@ -83,6 +83,7 @@ private ApiConstants() {} public static final String QNAME = "qname"; public static final String INCLUDE_SOURCE = "includeSource"; public static final String SOURCE = "/source/"; + public static final String PLUGIN = "/plugin"; public static final String LIMIT = "limit"; public static final String START_INDEX = "startIndex"; diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index e5ed6d6964d..4a0b2154c07 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7178,18 +7178,18 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - adminCanAccess: + adminCanEdit: type: boolean userCanAccess: type: boolean - adminCanEdit: + adminCanView: + type: boolean + adminCanAccess: type: boolean userCanView: type: boolean userCanEdit: type: boolean - adminCanView: - type: boolean whitePagesCanView: type: boolean baseDn: @@ -7528,8 +7528,6 @@ components: format: int32 displayName: type: string - tokenBindingSupported: - type: boolean authenticationMethod: type: string enum: @@ -7541,6 +7539,8 @@ components: - tls_client_auth - self_signed_tls_client_auth - none + tokenBindingSupported: + type: boolean baseDn: type: string inum: @@ -8343,6 +8343,17 @@ components: $ref: '#/components/schemas/EngineConfig' ssaConfiguration: $ref: '#/components/schemas/SsaConfiguration' + allResponseTypesSupported: + uniqueItems: true + type: array + items: + type: string + enum: + - code + - token + - id_token + fapi: + type: boolean enabledFeatureFlags: uniqueItems: true type: array @@ -8370,17 +8381,6 @@ components: - STAT - PAR - SSA - allResponseTypesSupported: - uniqueItems: true - type: array - items: - type: string - enum: - - code - - token - - id_token - fapi: - type: boolean AuthenticationFilter: required: - baseDn diff --git a/jans-config-api/docs/jans-config-api-swagger.yaml b/jans-config-api/docs/jans-config-api-swagger.yaml index 591a3ec979f..a0d67481c16 100644 --- a/jans-config-api/docs/jans-config-api-swagger.yaml +++ b/jans-config-api/docs/jans-config-api-swagger.yaml @@ -194,7 +194,7 @@ paths: $ref: '#/components/responses/InternalServerError' security: - oauth2: [ https://jans.io/oauth/config/fido2.readonly ] - + /jans-config-api/api/v1/attributes: get: summary: Gets a list of Gluu attributes. @@ -3585,7 +3585,7 @@ components: type: string details: type: string - + CustomScript: type: object description: Script @@ -5001,7 +5001,7 @@ components: sourceAttribute: type: string nameIdType: - type: string + type: string name: type: string description: Name of the attribute. @@ -5012,7 +5012,7 @@ components: type: string description: User friendly descriptive detail of attribute. origin: - type: string + type: string dataType: type: string description: Data Type of attribute. @@ -5081,10 +5081,10 @@ components: type: boolean description: Boolean value indicating if the attribute should be shown on that discovery page. custom: - type: boolean + type: boolean description: Boolean value indicating if it is a custom attribute. requred: - type: boolean + type: boolean description: Boolean value indicating if it is a attribute required. attributeValidation: type: object @@ -5098,7 +5098,7 @@ components: maxLength: type: integer tooltip: - type: string + type: string lifetime: type: string adminCanAccess: @@ -5254,157 +5254,115 @@ components: items: $ref: '#/components/schemas/Client' - CustomAttribute: - title: CustomAttribute - description: Attribute. + CustomObjectAttribute: type: object - required: - - name - - multiValued - - values properties: name: type: string - description: Name of the attribute. - example: 'name, displayName, birthdate, email' multiValued: type: boolean - description: Indicates if the attribute can hold multiple values. values: type: array items: - type: string + type: object value: - type: string + type: object displayValue: type: string + ClientAttributes: - title: ClientAttributes - description: Attribute. type: object properties: tlsClientAuthSubjectDn: - description: String representation of the expected subject distinguished name of the certificate, which the OAuth client will use in mutual TLS authentication. type: string runIntrospectionScriptBeforeJwtCreation: - description: boolean property which indicates whether to run introspection script and then include claims from result into access_token as JWT. type: boolean keepClientAuthorizationAfterExpiration: - description: boolean property which indicates whether to keep client authorization after expiration. type: boolean allowSpontaneousScopes: - description: boolean, whether to allow spontaneous scopes for client. type: boolean spontaneousScopes: - description: List of spontaneous scope regular expression. type: array items: type: string spontaneousScopeScriptDns: - description: List of spontaneous scope scripts. type: array items: type: string updateTokenScriptDns: - description: List of update token scripts. type: array items: type: string backchannelLogoutUri: - description: List of RP URL that will cause the RP to log itself out when sent a Logout Token by the OP. type: array items: type: string backchannelLogoutSessionRequired: - description: Boolean value specifying whether the RP requires that a sid (session ID) Claim be included in the Logout Token to identify the RP session with the OP when true. Default value is false. type: boolean additionalAudience: - description: List of additional client audience. type: array items: type: string postAuthnScripts: - description: List of post authentication scripts. type: array items: type: string consentGatheringScripts: - description: List of consent gathering scripts. type: array items: type: string introspectionScripts: - description: List of introspection scripts. type: array items: type: string rptClaimsScripts: - description: List of Requesting Party Token (RPT) claims scripts. type: array items: type: string ropcScripts: - description: List of Resource Owner Password Credentials (ROPC) scripts. type: array items: type: string parLifetime: - description: represents the lifetime of Pushed Authorisation Request (PAR). type: integer - format: int64 + format: int32 requirePar: - description: boolean value to indicate of Pushed Authorisation Request(PAR)is required. type: boolean jansAuthSignedRespAlg: - description: JWS alg algorithm JWA required for signing authorization responses. type: string jansAuthEncRespAlg: - description: JWE alg algorithm JWA required for encrypting authorization responses. type: string jansAuthEncRespEnc: - description: JWE enc algorithm JWA required for encrypting auhtorization responses. type: string jansSubAttr: - description: custom subject identifier attribute. type: string redirectUrisRegex: - description: If set, redirectUri must match to this regexp type: string jansAuthorizedAcr: - description: List of thentication Context Class Reference (ACR) that must exist. type: array items: type: string jansDefaultPromptLogin: - description: sets prompt=login to the authorization request, which causes the authorization server to force the user to sign in again before it will show the authorization prompt. type: boolean + idTokenLifetime: + type: integer + format: int32 Client: - title: Client object - description: Client. type: object required: - redirectUris properties: dn: type: string - baseDn: - type: string expirationDate: - description: Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating when this permission will expire. type: string format: date-time deletable: - description: Specifies whether client is deletable. type: boolean - default: false - inum: - description: XRI i-number. Client Identifier to uniquely identify the client. - type: string clientSecret: type: string - description: The client secret. The client MAY omit the parameter if the client secret is an empty string. frontChannelLogoutUri: type: string frontChannelLogoutSessionRequired: @@ -5418,358 +5376,194 @@ components: type: string format: date-time redirectUris: - description: Redirection URI values used by the Client. One of these registered Redirection URI values must exactly match the redirect_uri parameter value used in each Authorization Request type: array items: type: string - example: - - 'https://client.example.org/cb' claimRedirectUris: - description: Array of The Claims Redirect URIs to which the client wishes the authorization server to direct the requesting party's user agent after completing its interaction. type: array items: type: string responseTypes: - description: 'A list of the OAuth 2.0 response_type values that the Client is declaring that it will restrict itself to using. If omitted, the default is that the Client will use only the code Response Type. Allowed values are code, token, id_token.' type: array items: type: string enum: - - code - - token - - id_token + - code + - token + - id_token grantTypes: - description: A list of the OAuth 2.0 Grant Types that the Client is declaring that it will restrict itself to using. type: array items: type: string enum: - - authorization_code - - implicit - - password - - client_credentials - - refresh_token - - urn:ietf:params:oauth:grant-type:uma-ticket - - urn:openid:params:grant-type:ciba - - urn:ietf:params:oauth:grant-type:device_code + - none + - authorization_code + - implicit + - password + - client_credentials + - refresh_token + - urn:ietf:params:oauth:grant-type:uma-ticket + - urn:ietf:params:oauth:grant-type:token-exchange + - urn:openid:params:grant-type:ciba + - urn:ietf:params:oauth:grant-type:device_code applicationType: - description: 'Kind of the application. The default, if omitted, is web. The defined values are native or web. Web Clients using the OAuth Implicit Grant Type must only register URLs using the HTTPS scheme as redirect_uris, they must not use localhost as the hostname. Native Clients must only register redirect_uris using custom URI schemes or URLs using the http scheme with localhost as the hostname.' type: string - default: web enum: - - web - - native + - native + - web contacts: - description: e-mail addresses of people responsible for this Client. type: array items: type: string idTokenTokenBindingCnf: - description: 'Specifies the JWT Confirmation Method member name (e.g. tbh) that the Relying Party expects when receiving Token Bound ID Tokens. The presence of this parameter indicates that the Relying Party supports Token Binding of ID Tokens. If omitted, the default is that the Relying Party does not support Token Binding of ID Tokens.' type: string clientName: - $ref: '#/components/schemas/LocalizedString' - description: Name of the user suitable for display to end-users + type: string logoUri: - description: URL that references a logo for the Client application. - $ref: '#/components/schemas/LocalizedString' + type: string clientUri: - description: URL of the home page of the Client. The value of this field must point to a valid Web page. - $ref: '#/components/schemas/LocalizedString' + type: string policyUri: - description: URL that the Relying Party Client provides to the End-User to read about the how the profile data will be used. - $ref: '#/components/schemas/LocalizedString' + type: string tosUri: - description: URL that the Relying Party Client provides to the End-User to read about the Relying Party's terms of service. + type: string + clientNameLocalized: + $ref: '#/components/schemas/LocalizedString' + logoUriLocalized: + $ref: '#/components/schemas/LocalizedString' + clientUriLocalized: + $ref: '#/components/schemas/LocalizedString' + policyUriLocalized: + $ref: '#/components/schemas/LocalizedString' + tosUriLocalized: $ref: '#/components/schemas/LocalizedString' jwksUri: - description: 'URL for the Client''s JSON Web Key Set (JWK) document containing key(s) that are used for signing requests to the OP. The JWK Set may also contain the Client''s encryption keys(s) that are used by the OP to encrypt the responses to the Client. When both signing and encryption keys are made available, a use (Key Use) parameter value is required for all keys in the document to indicate each key''s intended usage.' type: string jwks: - description: 'List of JSON Web Key (JWK) - A JSON object that represents a cryptographic key. The members of the object represent properties of the key, including its value.' type: string - example: '{ "keys" : [ { "e" : "AQAB", "n" : "gmlDX_mgMcHX.." ] }' sectorIdentifierUri: - description: URL using the https scheme to be used in calculating Pseudonymous Identifiers by the OP. type: string subjectType: - description: Subject type requested for the Client ID. Valid types include pairwise and public. type: string enum: - - pairwise - - public + - pairwise + - public idTokenSignedResponseAlg: - description: JWS alg algorithm (JWA) required for signing the ID Token issued to this Client. type: string - enum: - - HS256 - - HS384 - - HS512 - - RS256 - - RS384 - - RS512 - - ES256 - - ES384 - - ES512 - - PS256 - - PS384 - - PS512 idTokenEncryptedResponseAlg: - description: JWE alg algorithm (JWA) required for encrypting the ID Token issued to this Client. type: string - enum: - - RSA1_5 - - RSA-OAEP - - A128KW - - A256KW idTokenEncryptedResponseEnc: - description: JWE enc algorithm (JWA) required for encrypting the ID Token issued to this Client. type: string - enum: - - A128CBC+HS256 - - A256CBC+HS512 - - A128GCM - - A256GCM userInfoSignedResponseAlg: - description: JWS alg algorithm (JWA) required for signing UserInfo Responses. type: string - enum: - - HS256 - - HS384 - - HS512 - - RS256 - - RS384 - - RS512 - - ES256 - - ES384 - - ES512 - - PS256 - - PS384 - - PS512 userInfoEncryptedResponseAlg: - description: JWE alg algorithm (JWA) required for encrypting UserInfo Responses. type: string - enum: - - RSA1_5 - - RSA-OAEP - - A128KW - - A256KW userInfoEncryptedResponseEnc: - description: JWE enc algorithm (JWA) required for encrypting UserInfo Responses. type: string - enum: - - A128CBC+HS256 - - A256CBC+HS512 - - A128GCM - - A256GCM requestObjectSigningAlg: - description: JWS alg algorithm (JWA) that must be used for signing Request Objects sent to the OP. type: string - enum: - - HS256 - - HS384 - - HS512 - - RS256 - - RS384 - - RS512 - - ES256 - - ES384 - - ES512 - - PS256 - - PS384 - - PS512 requestObjectEncryptionAlg: - description: JWE alg algorithm (JWA) the RP is declaring that it may use for encrypting Request Objects sent to the OP. type: string - enum: - - RSA1_5 - - RSA-OAEP - - A128KW - - A256KW requestObjectEncryptionEnc: - description: JWE enc algorithm (JWA) the RP is declaring that it may use for encrypting Request Objects sent to the OP. type: string - enum: - - A128CBC+HS256 - - A256CBC+HS512 - - A128GCM - - A256GCM tokenEndpointAuthMethod: - description: Requested Client Authentication method for the Token Endpoint. type: string - enum: - - client_secret_basic - - client_secret_post - - client_secret_jwt - - private_key_jwt - - tls_client_auth - - none tokenEndpointAuthSigningAlg: - description: JWS alg algorithm (JWA) that must be used for signing the JWT used to authenticate the Client at the Token Endpoint for the private_key_jwt and client_secret_jwt authentication methods. type: string - enum: - - HS256 - - HS384 - - HS512 - - RS256 - - RS384 - - RS512 - - ES256 - - ES384 - - ES512 - - PS256 - - PS384 - - PS512 defaultMaxAge: - description: Specifies the Default Maximum Authentication Age. type: integer format: int32 - example: 1000000 defaultAcrValues: - description: Array of default requested Authentication Context Class Reference values that the Authorization Server must use for processing requests from the Client. type: array items: type: string initiateLoginUri: - description: Specifies the URI using the https scheme that the authorization server can call to initiate a login at the client. type: string postLogoutRedirectUris: - description: Provide the URLs supplied by the RP to request that the user be redirected to this location after a logout has been performed. type: array items: type: string - example: - - 'https://client.example.org/logout/page1' - - 'https://client.example.org/logout/page2' - - 'https://client.example.org/logout/page3' requestUris: - description: Provide a list of requests_uri values that are pre-registered by the Client for use at the Authorization Server. type: array items: type: string scopes: - description: Provide list of scopes granted to the client (scope dn or scope id). type: array items: type: string - example: - - read write dolphin claims: - description: Provide list of claims granted to the client. type: array items: type: string - description: String containing a space-separated list of claims that can be requested individually. trustedClient: - description: Attribute which corresponds to the "Pre-Authorization" property. Default value is false. type: boolean - default: false lastAccessTime: - description: 'Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating last access time.' type: string format: date-time lastLogonTime: - description: 'Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating last login time.' type: string format: date-time persistClientAuthorizations: - description: Specifies if the client authorization details are to be persisted. Default value is true. type: boolean includeClaimsInIdToken: - description: 'If true then claims are included in token id, default value is false.' type: boolean - default: false refreshTokenLifetime: - description: Specifies the Client-specific refresh token expiration. type: integer format: int32 - example: 100000000 accessTokenLifetime: - description: Specifies the Client-specific access token expiration. type: integer format: int32 - example: 100000000 customAttributes: type: array items: - $ref: '#/components/schemas/CustomAttribute' + $ref: '#/components/schemas/CustomObjectAttribute' customObjectClasses: type: array items: type: string rptAsJwt: - description: Specifies whether RPT should be return as signed JWT. type: boolean accessTokenAsJwt: - description: Specifies whether access token as signed JWT. type: boolean accessTokenSigningAlg: - description: 'Specifies signing algorithm that has to be used during JWT signing. If it''s not specified, then the default OP signing algorithm will be used.' type: string - enum: - - HS256 - - HS384 - - HS512 - - RS256 - - RS384 - - RS512 - - ES256 - - ES384 - - ES512 - - PS256 - - PS384 - - PS512 disabled: - description: Specifies whether client is disabled. type: boolean - default: false authorizedOrigins: - description: Specifies authorized JavaScript origins. type: array items: type: string softwareId: - description: Specifies a unique identifier string (UUID) assigned by the client developer or software publisher used by registration endpoints to identify the client software to be dynamically registered. type: string - example: 4NRB1-0XZABZI9E6-5SM3R softwareVersion: - description: Specifies a version identifier string for the client software identified by 'software_id'. The value of the 'software_version' should change on any update to the client software identified by the same 'software_id'. type: string - example: '2.1' softwareStatement: - description: Specifies a software statement containing client metadata values about the client software as claims. This is a string value containing the entire signed JWT. type: string attributes: - type: object $ref: '#/components/schemas/ClientAttributes' backchannelTokenDeliveryMode: - description: specifies how backchannel token will be delivered. type: string enum: - - poll - - ping - - push + - poll + - ping + - push backchannelClientNotificationEndpoint: - description: 'Client Initiated Backchannel Authentication (CIBA) enables a Client to initiate the authentication of an end-user by means of out-of-band mechanisms. Upon receipt of the notification, the Client makes a request to the token endpoint to obtain the tokens.' type: string backchannelAuthenticationRequestSigningAlg: - description: 'The JWS algorithm alg value that the Client will use for signing authentication request, as described in Section 7.1.1. of OAuth 2.0 [RFC6749]. When omitted, the Client will not send signed authentication requests.' type: string enum: - - RS256 - - RS384 - - RS512 - - ES256 - - ES384 - - ES512 - - PS256 - - PS384 - - PS512 + - RS256 + - RS384 + - RS512 + - ES256 + - ES384 + - ES512 + - PS256 + - PS384 + - PS512 backchannelUserCodeParameter: - description: 'Boolean value specifying whether the Client supports the user_code parameter. If omitted, the default value is false.' type: boolean description: - description: Description of the client. type: string organization: type: string @@ -5795,6 +5589,10 @@ components: - tls_client_auth - self_signed_tls_client_auth - none + baseDn: + type: string + inum: + type: string UmaResource: @@ -7479,7 +7277,7 @@ components: type: boolean description: indicates if the parameter by default will be returned in response. default: false - + PagedResult: type: object properties: @@ -7495,8 +7293,8 @@ components: entries: type: array items: - type: object - + type: object + LocalizedString: type: object properties: diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java index 687575f4353..334e565cf2c 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java @@ -25,8 +25,6 @@ import java.util.stream.Collectors; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Response; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; @@ -136,11 +134,6 @@ private List validateScope(String scopeName) { scope = scopes.get(0); log.debug("Scope from DB is - {}", scope.getId()); scopeList.add(scope); - if (scopes.size() > 1) { - log.error("{} Scope with same name - {} ", scopes.size(), scopeName); - throw new WebApplicationException("Multiple Scope with same name - " + scopeName, - Response.status(Response.Status.INTERNAL_SERVER_ERROR).build()); - } } ScopeType scopeType = ScopeType.OAUTH; @@ -151,17 +144,20 @@ private List validateScope(String scopeName) { // Create/Update scope only if they are config-api-resource scopes if (isConfigApiScope(scopeName)) { + //ensure scope does not exists + scopes = scopeService.searchScopesById(scopeName); + log.debug("ConfigApiScope scopeName:{} in DB - scopes:{} ", scopeName, scopes); if (scopes == null || scopes.isEmpty()) { - log.debug("Scope - '{}' does not exist, hence creating it.", scopeName); - // Scope does not exists hence create Scope - scope = new Scope(); - String inum = UUID.randomUUID().toString(); - scope.setId(scopeName); - scope.setDisplayName(scopeName); - scope.setInum(inum); - scope.setDn(scopeService.getDnForScope(inum)); - scope.setScopeType(scopeType); - scopeService.addScope(scope); + log.debug("Scope - '{}' does not exist, hence creating it.", scopeName); + // Scope does not exists hence create Scope + scope = new Scope(); + String inum = UUID.randomUUID().toString(); + scope.setId(scopeName); + scope.setDisplayName(scopeName); + scope.setInum(inum); + scope.setDn(scopeService.getDnForScope(inum)); + scope.setScopeType(scopeType); + scopeService.addScope(scope); } if (scope != null) { // Update resource diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/SessionService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/SessionService.java index e389424863f..6350436dad2 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/SessionService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/SessionService.java @@ -16,6 +16,7 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.NotFoundException; +import java.util.Date; import java.util.List; import org.apache.commons.lang.StringUtils; @@ -64,7 +65,9 @@ public List getAllSessions() { } public List getSessions() { - List sessionList = persistenceEntryManager.findEntries(getDnForSession(null), SessionId.class, null, + List sessionList = persistenceEntryManager.findEntries(getDnForSession(null), SessionId.class, + Filter.createGreaterOrEqualFilter("exp", persistenceEntryManager.encodeTime(getDnForSession(null), + new Date(System.currentTimeMillis()))), 0); logger.debug("All sessionList:{}", sessionList); From b203afe234e7d8a5a1a81e322860658f07d666cc Mon Sep 17 00:00:00 2001 From: moabu <47318409+moabu@users.noreply.github.com> Date: Wed, 9 Nov 2022 08:24:01 +0000 Subject: [PATCH 02/28] ci: add yurem to linux setup codeowners --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cc51d282418..59bf47437fe 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -22,7 +22,7 @@ /jans-scim/ @jgomer2001 /jans-config-api/ @pujavs @yuriyz /jans-cli/ @devrimyatar -/jans-linux-setup/ @devrimyatar @smansoft @yuriyz +/jans-linux-setup/ @devrimyatar @smansoft @yuriyz @yurem /jans-linux-setup/jans_setup/setup_app/version.py @moabu /jans-linux-setup/static/scripts/admin_ui_plugin.py @devrimyatar @duttarnab /agama/ @jgomer2001 From dbe60b745e6c6eedb351709b66da8b671e04ac04 Mon Sep 17 00:00:00 2001 From: Isman Firmansyah Date: Wed, 9 Nov 2022 16:45:41 +0700 Subject: [PATCH 03/28] chore(image): sync missing localized attributes for sql and spanner (#2927) * chore(image): sync missing localized attributes for sql and spanner * chore(image): sync jans-schema.json template --- docker-jans-persistence-loader/Dockerfile | 2 +- docker-jans-persistence-loader/scripts/spanner_setup.py | 5 +++++ docker-jans-persistence-loader/scripts/sql_setup.py | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docker-jans-persistence-loader/Dockerfile b/docker-jans-persistence-loader/Dockerfile index db530233b36..33baf854aa4 100644 --- a/docker-jans-persistence-loader/Dockerfile +++ b/docker-jans-persistence-loader/Dockerfile @@ -24,7 +24,7 @@ RUN python3 -m ensurepip \ # ===================== # janssenproject/jans SHA commit -ENV JANS_SOURCE_VERSION=d1890e76c13c8c2c3dcdcc0625edd04cf552bbf9 +ENV JANS_SOURCE_VERSION=eea281de11013b18f715b77a5c7cf69537c668cc ARG JANS_SETUP_DIR=jans-linux-setup/jans_setup ARG JANS_SCRIPT_CATALOG_DIR=docs/script-catalog ARG JANS_CONFIG_API_DOCS=jans-config-api/docs diff --git a/docker-jans-persistence-loader/scripts/spanner_setup.py b/docker-jans-persistence-loader/scripts/spanner_setup.py index 91a13bef29c..ae676e669ef 100644 --- a/docker-jans-persistence-loader/scripts/spanner_setup.py +++ b/docker-jans-persistence-loader/scripts/spanner_setup.py @@ -364,6 +364,11 @@ def column_int_to_string(table_name, col_name): ("jansStatEntry", "jansData"), ("jansSessId", "deviceSecret"), ("jansSsa", "jansState"), + ("jansClnt", "jansClntURILocalized"), + ("jansClnt", "jansLogoURILocalized"), + ("jansClnt", "jansPolicyURILocalized"), + ("jansClnt", "jansTosURILocalized"), + ("jansClnt", "displayNameLocalized"), ]: add_column(mod[0], mod[1]) diff --git a/docker-jans-persistence-loader/scripts/sql_setup.py b/docker-jans-persistence-loader/scripts/sql_setup.py index a83e46bb2a5..9c8320f4b81 100644 --- a/docker-jans-persistence-loader/scripts/sql_setup.py +++ b/docker-jans-persistence-loader/scripts/sql_setup.py @@ -369,6 +369,11 @@ def column_from_json(table_name, col_name): ("jansStatEntry", "jansData"), ("jansSessId", "deviceSecret"), ("jansSsa", "jansState"), + ("jansClnt", "jansClntURILocalized"), + ("jansClnt", "jansLogoURILocalized"), + ("jansClnt", "jansPolicyURILocalized"), + ("jansClnt", "jansTosURILocalized"), + ("jansClnt", "displayNameLocalized"), ]: add_column(mod[0], mod[1]) From b725ec7178f6819897f3fc6a63275126639827b5 Mon Sep 17 00:00:00 2001 From: mzico Date: Wed, 9 Nov 2022 18:08:26 +0600 Subject: [PATCH 04/28] Update restarting-services.md (#2941) Restart command and output were merged which made "copy" / "paste" hard.... --- docs/admin/vm-ops/restarting-services.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/admin/vm-ops/restarting-services.md b/docs/admin/vm-ops/restarting-services.md index 135ae3b1c3b..522f56eb333 100644 --- a/docs/admin/vm-ops/restarting-services.md +++ b/docs/admin/vm-ops/restarting-services.md @@ -9,6 +9,10 @@ tags: ```bash $ sudo systemctl list-units --all "jans*" +``` + +Output should be like below: +``` UNIT LOAD ACTIVE SUB DESCRIPTION jans-auth.service loaded active running Janssen OAauth service jans-config-api.service loaded active running Janssen Config API service @@ -53,4 +57,4 @@ This command is used for the `apache2` and `httpd` services. ``` systemctl reload [service name] -``` \ No newline at end of file +``` From 3baba92a0daa39eb49553b34d5df3b1e7ba4c995 Mon Sep 17 00:00:00 2001 From: mzico Date: Wed, 9 Nov 2022 18:16:53 +0600 Subject: [PATCH 05/28] Update restarting-services.md (#2942) Removed "$" sign from command.... --- docs/admin/vm-ops/restarting-services.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/admin/vm-ops/restarting-services.md b/docs/admin/vm-ops/restarting-services.md index 522f56eb333..12b0d795592 100644 --- a/docs/admin/vm-ops/restarting-services.md +++ b/docs/admin/vm-ops/restarting-services.md @@ -8,7 +8,7 @@ tags: ## Getting list of Jans services ```bash -$ sudo systemctl list-units --all "jans*" +sudo systemctl list-units --all "jans*" ``` Output should be like below: From 90c549b618376e873a1b1ef3b358b0e471cef4c9 Mon Sep 17 00:00:00 2001 From: mzico Date: Wed, 9 Nov 2022 18:32:22 +0600 Subject: [PATCH 06/28] Update restarting-services.md (#2943) Adding some other service related info... --- docs/admin/vm-ops/restarting-services.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/admin/vm-ops/restarting-services.md b/docs/admin/vm-ops/restarting-services.md index 12b0d795592..6b5df74adc5 100644 --- a/docs/admin/vm-ops/restarting-services.md +++ b/docs/admin/vm-ops/restarting-services.md @@ -26,6 +26,15 @@ SUB = The low-level unit activation state, values depend on unit type. 5 loaded units listed. ``` +## Other Services + +There are more services other than Jans services like LDAP or Apache. To get the status of those services make sure you use command like + +```bash +sudo systemctl list-units --all "apache2*" +``` + + ## Commands (Ubuntu 20.04, RHEL 8, SUSE 15) ### Start From a26ef90c97b82be41d103aa6f923bda3f7f0d9ee Mon Sep 17 00:00:00 2001 From: Yuriy M <95305560+yuremm@users.noreply.github.com> Date: Wed, 9 Nov 2022 15:43:42 +0300 Subject: [PATCH 07/28] feat: allow to use like with lower together (#2944) Co-authored-by: Yuriy Movchan --- .../jans/orm/couchbase/CouchbaseSample.java | 16 ++++++++++++ .../impl/CouchbaseFilterConverter.java | 2 +- .../io/jans/orm/search/filter/Filter.java | 25 ++++++++++++++++--- .../orm/search/filter/FilterProcessor.java | 6 ++--- 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/jans-orm/couchbase-sample/src/main/java/io/jans/orm/couchbase/CouchbaseSample.java b/jans-orm/couchbase-sample/src/main/java/io/jans/orm/couchbase/CouchbaseSample.java index f0fd71fff0f..f03fde4692a 100644 --- a/jans-orm/couchbase-sample/src/main/java/io/jans/orm/couchbase/CouchbaseSample.java +++ b/jans-orm/couchbase-sample/src/main/java/io/jans/orm/couchbase/CouchbaseSample.java @@ -49,6 +49,22 @@ public static void main(String[] args) { newUser.getCustomAttributes().add(new CustomObjectAttribute("test", "test_value")); couchbaseEntryManager.persist(newUser); + // Find all with lower and or filters + Filter orFilterWithLower = Filter.createORFilter(Filter.createEqualityFilter(Filter.createLowercaseFilter("description"), "test1"), + Filter.createEqualityFilter(Filter.createLowercaseFilter("description"), "test2")); + List usersWithOrFilter = couchbaseEntryManager.findEntries("ou=sessions,o=gluu", SimpleUser.class, orFilterWithLower); + for (SimpleUser user : usersWithOrFilter) { + LOG.info("User with uid: '{}' with DN: '{}'", user.getUserId(), user.getDn()); + } + + // Find all with lower and or filters + Filter orFilterWithLower2 = Filter.createORFilter(Filter.createSubstringFilter(Filter.createLowercaseFilter("description"), null, new String[] { "test1" }, null), + Filter.createSubstringFilter(Filter.createLowercaseFilter("displayName"), null, new String[] { "test1" }, null)); + List usersWithOrFilter2 = couchbaseEntryManager.findEntries("ou=sessions,o=gluu", SimpleUser.class, orFilterWithLower2); + for (SimpleUser user : usersWithOrFilter2) { + LOG.info("User with uid: '{}' with DN: '{}'", user.getUserId(), user.getDn()); + } + // Find all users which have specified object classes defined in SimpleUser List users = couchbaseEntryManager.findEntries("ou=people,o=jans", SimpleUser.class, null); for (SimpleUser user : users) { diff --git a/jans-orm/couchbase/src/main/java/io/jans/orm/couchbase/impl/CouchbaseFilterConverter.java b/jans-orm/couchbase/src/main/java/io/jans/orm/couchbase/impl/CouchbaseFilterConverter.java index 8e81fe82603..a202f427df5 100644 --- a/jans-orm/couchbase/src/main/java/io/jans/orm/couchbase/impl/CouchbaseFilterConverter.java +++ b/jans-orm/couchbase/src/main/java/io/jans/orm/couchbase/impl/CouchbaseFilterConverter.java @@ -102,7 +102,7 @@ public ConvertedExpression convertToCouchbaseFilter(Filter genericFilter, Map Date: Wed, 9 Nov 2022 16:14:57 +0300 Subject: [PATCH 08/28] chore: remove unused merthod (#2945) Co-authored-by: Yuriy Movchan --- .../src/main/java/io/jans/orm/search/filter/Filter.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/jans-orm/filter/src/main/java/io/jans/orm/search/filter/Filter.java b/jans-orm/filter/src/main/java/io/jans/orm/search/filter/Filter.java index ed1c3fe70cc..25d8dfdd2c0 100644 --- a/jans-orm/filter/src/main/java/io/jans/orm/search/filter/Filter.java +++ b/jans-orm/filter/src/main/java/io/jans/orm/search/filter/Filter.java @@ -206,10 +206,6 @@ public final void setSubFinal(String subFinal) { this.subFinal = subFinal; } - protected void setMultiValued(Boolean multiValued) { - this.multiValued = multiValued; - } - public final Boolean getMultiValued() { return multiValued; } From dc9d6e325ed5df637adfadb921cd9197d62f5b97 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Wed, 9 Nov 2022 17:19:03 +0200 Subject: [PATCH 09/28] feat(jans-auth-server): corrected GluuOrganization - refactor getOrganizationName() #2947 (#2948) --- .../jans/as/persistence/model/GluuOrganization.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/jans-auth-server/persistence-model/src/main/java/io/jans/as/persistence/model/GluuOrganization.java b/jans-auth-server/persistence-model/src/main/java/io/jans/as/persistence/model/GluuOrganization.java index faa254386bc..0b6aaf79e05 100644 --- a/jans-auth-server/persistence-model/src/main/java/io/jans/as/persistence/model/GluuOrganization.java +++ b/jans-auth-server/persistence-model/src/main/java/io/jans/as/persistence/model/GluuOrganization.java @@ -16,6 +16,8 @@ import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; +import org.apache.tika.utils.StringUtils; + import java.io.Serializable; /** @@ -89,13 +91,6 @@ public void setJsFaviconPath(String jsFaviconPath) { this.jsFaviconPath = jsFaviconPath; } - public String getOrganizationTitle() { - if (title == null || title.trim().equals("")) { - return "Gluu"; - } - return title; - } - public String getCountryName() { return countryName; } @@ -177,6 +172,9 @@ public void setThemeColor(String themeColor) { } public String getTitle() { + if (StringUtils.isBlank(title)) { + title = "Gluu"; + } return title; } From f7a1b8326e99d19a884e5e741a4aafa90010ecbf Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Thu, 10 Nov 2022 23:26:03 +0530 Subject: [PATCH 10/28] feat(config-api): super scope implementation --- .../docs/jans-config-api-swagger-auto.yaml | 32 ++- .../java/io/jans/configapi/util/AuthUtil.java | 233 ++++++++---------- .../configapi/core/rest/ProtectedApi.java | 4 + .../configapi/core/util/ProtectionScope.java | 15 ++ 4 files changed, 136 insertions(+), 148 deletions(-) create mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScope.java diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index 4a0b2154c07..e20a0042a62 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7178,20 +7178,20 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string + whitePagesCanView: + type: boolean adminCanEdit: type: boolean userCanAccess: type: boolean - adminCanView: - type: boolean adminCanAccess: type: boolean + adminCanView: + type: boolean userCanView: type: boolean userCanEdit: type: boolean - whitePagesCanView: - type: boolean baseDn: type: string PatchRequest: @@ -8343,17 +8343,6 @@ components: $ref: '#/components/schemas/EngineConfig' ssaConfiguration: $ref: '#/components/schemas/SsaConfiguration' - allResponseTypesSupported: - uniqueItems: true - type: array - items: - type: string - enum: - - code - - token - - id_token - fapi: - type: boolean enabledFeatureFlags: uniqueItems: true type: array @@ -8381,6 +8370,17 @@ components: - STAT - PAR - SSA + allResponseTypesSupported: + uniqueItems: true + type: array + items: + type: string + enum: + - code + - token + - id_token + fapi: + type: boolean AuthenticationFilter: required: - baseDn @@ -8860,8 +8860,6 @@ components: type: string jsFaviconPath: type: string - organizationTitle: - type: string baseDn: type: string Scope: diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java index 9509d95fc69..983191349ec 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java @@ -14,6 +14,7 @@ import io.jans.configapi.security.client.AuthClientFactory; import io.jans.configapi.configuration.ConfigurationFactory; import io.jans.configapi.core.rest.ProtectedApi; +import io.jans.configapi.core.util.ProtectionScope; import io.jans.configapi.service.auth.ConfigurationService; import io.jans.configapi.service.auth.ClientService; import io.jans.configapi.service.auth.ScopeService; @@ -24,16 +25,16 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; + import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.container.ResourceInfo; -import jakarta.ws.rs.core.Response; import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; @@ -70,7 +71,7 @@ public String getAuthOpenidConfigurationUrl() { public String getIssuer() { return this.configurationService.find().getIssuer(); } - + public String getIntrospectionEndpoint() { return configurationService.find().getIntrospectionEndpoint(); } @@ -78,7 +79,7 @@ public String getIntrospectionEndpoint() { public String getTokenEndpoint() { return configurationService.find().getTokenEndpoint(); } - + public String getEndSessionEndpoint() { return this.configurationService.find().getEndSessionEndpoint(); } @@ -90,25 +91,24 @@ public String getServiceUrl(String url) { public String getClientId() { return this.configurationFactory.getApiClientId(); } - + public List getUserExclusionAttributes() { return this.configurationFactory.getApiAppConfiguration().getUserExclusionAttributes(); } - + public String getUserExclusionAttributesAsString() { List excludedAttributes = getUserExclusionAttributes(); return excludedAttributes == null ? null : excludedAttributes.stream().collect(Collectors.joining(",")); } - + public List getUserMandatoryAttributes() { return this.configurationFactory.getApiAppConfiguration().getUserMandatoryAttributes(); } - + public AgamaConfiguration getAgamaConfiguration() { return this.configurationFactory.getApiAppConfiguration().getAgamaConfiguration(); } - public String getTokenUrl() { return this.configurationService.find().getTokenEndpoint(); } @@ -153,58 +153,6 @@ public String encryptPassword(String clientPassword) { return encryptedPassword; } - public List getResourceScopeList(String method, String path) { - log.trace(" ResourceScopeList requested for method:{}, path:{}", method, path); - - // Verify in cache - Map> resources = ApiProtectionCache.getAllResources(); - - // Filter paths based on resource name - Set keys = resources.keySet(); - List filteredPaths = keys.stream().filter(k -> k.contains(path)).collect(Collectors.toList()); - - if (filteredPaths == null || filteredPaths.isEmpty()) { - throw new WebApplicationException("No matching resource found .", - Response.status(Response.Status.UNAUTHORIZED).build()); - } - - List scopeList = null; - for (String key : filteredPaths) { - String[] result = key.split(":::"); - if (result != null && result.length > 1) { - String httpmethod = result[0]; - String pathUrl = result[1]; - log.trace(" Resource Scopes - httpmethod:{} , pathUrl:{} ", httpmethod, pathUrl); - - if (pathUrl != null && pathUrl.contains(path)) { - // Matching url - log.trace(" Matching url with path:{} , pathUrl:{} ", path, pathUrl); - - // Verify Method - if (httpmethod.contains(method)) { - scopeList = ApiProtectionCache.getResourceScopes(key); - log.trace(" scopeList:{} for the method:{} ", scopeList, method); - break; - } - } - } - } - return scopeList; - } - - public List getAllResourceScopes() { - Map scopeMap = ApiProtectionCache.getAllScopes(); - log.trace("All Resource Scopes - scopeMap:{}", scopeMap); - - List scopeStrList = null; - if (scopeMap != null && !scopeMap.isEmpty()) { - Set scopeSet = scopeMap.keySet(); - scopeStrList = new ArrayList<>(scopeSet); - } - log.trace("All Resource Scopes - scopeStrList:{} ", scopeStrList); - return scopeStrList; - } - public List getRequestedScopes(String path) { List scopeList = ApiProtectionCache.getResourceScopes(path); log.trace("Requested scopes:{} for path:{} ", scopeList, path); @@ -219,33 +167,34 @@ public List getRequestedScopes(String path) { return scopeStrList; } - public List getRequestedScopes(String method, String path) { - log.trace("Requested scopes for path:{} and method:{} ", path, method); - List scopeList = this.getResourceScopeList(method, path); - log.trace("Requested scopeList:{} for path:{} and method:{} ", scopeList, path, method); - List scopeStrList = new ArrayList<>(); - if (scopeList != null && !scopeList.isEmpty()) { - for (Scope s : scopeList) { - scopeStrList.add(s.getId()); + public List getRequestedScopes(ResourceInfo resourceInfo) { + log.trace("Requested scopes for resourceInfo:{} ", resourceInfo); + Class resourceClass = resourceInfo.getResourceClass(); + ProtectedApi typeAnnotation = resourceClass.getAnnotation(ProtectedApi.class); + List scopes = new ArrayList<>(); + if (typeAnnotation != null) { + HashMap> scopeMap = new HashMap<>(); + addMethodScopes(resourceInfo, scopeMap, null); + for (Map.Entry> entry : scopeMap.entrySet()) { + scopes.addAll(entry.getValue()); + } } - log.trace("Final scopeStrList:{} for path:{} and method:{} ", scopeStrList, path, method); - return scopeStrList; + log.trace("Requested resourceInfo:{} for scope:{} ", resourceInfo, scopes); + return scopes; } - public List getRequestedScopes(ResourceInfo resourceInfo) { + public Map> getResourceScopes(ResourceInfo resourceInfo, ProtectionScope protectionScope) { log.trace("Requested scopes for resourceInfo:{} ", resourceInfo); Class resourceClass = resourceInfo.getResourceClass(); ProtectedApi typeAnnotation = resourceClass.getAnnotation(ProtectedApi.class); - List scopes = new ArrayList<>(); + HashMap> scopeMap = new HashMap<>(); if (typeAnnotation == null) { - addMethodScopes(resourceInfo, scopes); - } else { - scopes.addAll(Stream.of(typeAnnotation.scopes()).collect(Collectors.toList())); - addMethodScopes(resourceInfo, scopes); + addMethodScopes(resourceInfo, scopeMap, protectionScope); } - log.trace("Requested scopes:{} for resourceInfo:{} ", scopes, resourceInfo); - return scopes; + log.trace("Requested scopes:{} for resourceInfo:{} of type protectionScope:{} ", scopeMap, resourceInfo, + protectionScope); + return scopeMap; } public boolean validateScope(List authScopes, List resourceScopes) { @@ -254,14 +203,39 @@ public boolean validateScope(List authScopes, List resourceScope return authScopeSet.containsAll(resourceScopeSet); } - private void addMethodScopes(ResourceInfo resourceInfo, List scopes) { + private void addMethodScopes(ResourceInfo resourceInfo, HashMap> scopeMap, + ProtectionScope protectionScope) { + log.debug("Adding scopes for resourceInfo:{} for protectionScope:{} in scopeMap:{} ", resourceInfo, + protectionScope, scopeMap); Method resourceMethod = resourceInfo.getResourceMethod(); ProtectedApi methodAnnotation = resourceMethod.getAnnotation(ProtectedApi.class); if (methodAnnotation != null) { - scopes.addAll(Stream.of(methodAnnotation.scopes()).collect(Collectors.toList())); + if (scopeMap == null) { + scopeMap = new HashMap<>(); + } + if (protectionScope != null) { + if (ProtectionScope.SCOPE.equals(protectionScope)) { + scopeMap.put(ProtectionScope.SCOPE.name(), + Stream.of(methodAnnotation.scopes()).collect(Collectors.toList())); + } else if (ProtectionScope.GROUP.equals(protectionScope)) { + scopeMap.put(ProtectionScope.GROUP.name(), + Stream.of(methodAnnotation.groupScopes()).collect(Collectors.toList())); + } else { + scopeMap.put(ProtectionScope.SUPER.name(), + Stream.of(methodAnnotation.superScopes()).collect(Collectors.toList())); + } + } else { + List scopes = new ArrayList<>(); + scopes.addAll(Stream.of(methodAnnotation.scopes()).collect(Collectors.toList())); + scopes.addAll(Stream.of(methodAnnotation.groupScopes()).collect(Collectors.toList())); + scopes.addAll(Stream.of(methodAnnotation.superScopes()).collect(Collectors.toList())); + scopeMap.put("ALL", scopes); + } } + log.debug("Added scopes for resourceInfo:{} for protectionScope:{} in scopeMap:{} ", resourceInfo, + protectionScope, scopeMap); } - + public String requestAccessToken(final String clientId, final List scope) { log.info("Request for AccessToken - clientId:{}, scope:{} ", clientId, scope); String tokenUrl = getTokenEndpoint(); @@ -397,56 +371,53 @@ public List findMissingElements(List list1, List list2) public boolean isEqualCollection(List list1, List list2) { return CollectionUtils.isEqualCollection(list1, list2); } - + public boolean containsField(List allFields, String attribute) { - log.debug("allFields:{}, attribute:{}, allFields.contains(attribute):{} ", allFields , attribute, allFields.stream().anyMatch(f -> f.getName().equals(attribute))); - + log.debug("allFields:{}, attribute:{}, allFields.contains(attribute):{} ", allFields, attribute, + allFields.stream().anyMatch(f -> f.getName().equals(attribute))); + return allFields.stream().anyMatch(f -> f.getName().equals(attribute)); - } - - public List getAllFields(Class type) { - List allFields = new ArrayList<>(); - allFields = getAllFields(allFields, type); - log.debug("Fields:{} of type:{} ", allFields, type); - - return allFields; - } - - public List getAllFields(List fields, Class type) { - log.debug("fields:{} of type:{} ", fields, type); - fields.addAll(Arrays.asList(type.getDeclaredFields())); - - if (type.getSuperclass() != null) { - getAllFields(fields, type.getSuperclass()); - } - log.debug("Final fields:{} of type:{} ", fields, type); - return fields; - } - - public boolean isValidDn(String dn) { - return isValidDn(dn, false); - } - - - public boolean isValidDn(String dn, boolean strictNameChecking) { - return DN.isValidDN(dn, strictNameChecking); - } - - - public RevokeSessionResponse revokeSession(final String url,final String token, final String userId) { - log.debug("Revoke session Request - url:{}, token:{}, userId:{}", url, token, userId); - - - - RevokeSessionResponse revokeSessionResponse = AuthClientFactory.revokeSession(url, token,userId); - log.debug("revokeSessionResponse:{}",revokeSessionResponse); - if (revokeSessionResponse != null) { - - log.debug("revokeSessionResponse.getEntity():{}, revokeSessionResponse.getStatus():{} ", revokeSessionResponse.getEntity(), revokeSessionResponse.getStatus()); - - - } - return revokeSessionResponse; - } + } + + public List getAllFields(Class type) { + List allFields = new ArrayList<>(); + allFields = getAllFields(allFields, type); + log.debug("Fields:{} of type:{} ", allFields, type); + + return allFields; + } + + public List getAllFields(List fields, Class type) { + log.debug("fields:{} of type:{} ", fields, type); + fields.addAll(Arrays.asList(type.getDeclaredFields())); + + if (type.getSuperclass() != null) { + getAllFields(fields, type.getSuperclass()); + } + log.debug("Final fields:{} of type:{} ", fields, type); + return fields; + } + + public boolean isValidDn(String dn) { + return isValidDn(dn, false); + } + + public boolean isValidDn(String dn, boolean strictNameChecking) { + return DN.isValidDN(dn, strictNameChecking); + } + + public RevokeSessionResponse revokeSession(final String url, final String token, final String userId) { + log.debug("Revoke session Request - url:{}, token:{}, userId:{}", url, token, userId); + + RevokeSessionResponse revokeSessionResponse = AuthClientFactory.revokeSession(url, token, userId); + log.debug("revokeSessionResponse:{}", revokeSessionResponse); + if (revokeSessionResponse != null) { + + log.debug("revokeSessionResponse.getEntity():{}, revokeSessionResponse.getStatus():{} ", + revokeSessionResponse.getEntity(), revokeSessionResponse.getStatus()); + + } + return revokeSessionResponse; + } } diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/ProtectedApi.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/ProtectedApi.java index ea252b7c7d1..3ad1ec0be54 100644 --- a/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/ProtectedApi.java +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/ProtectedApi.java @@ -18,5 +18,9 @@ public @interface ProtectedApi { String[] scopes() default {}; + + String[] groupScopes() default {}; + + String[] superScopes() default {}; } diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScope.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScope.java new file mode 100644 index 00000000000..467e097d819 --- /dev/null +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScope.java @@ -0,0 +1,15 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.configapi.core.util; + +public enum ProtectionScope { + SCOPE, GROUP, SUPER; + + String getValue() { + return toString().toLowerCase(); + } +} From 7046426147bce2a2d4c6353a341707ac67f87d23 Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Fri, 11 Nov 2022 22:46:43 +0530 Subject: [PATCH 11/28] feat(config-api): static scope --- .../docs/jans-config-api-swagger-auto.yaml | 24 +++++++++---------- .../profiles/local/test.properties | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index e20a0042a62..37637256f1a 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7178,19 +7178,19 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - whitePagesCanView: + adminCanAccess: type: boolean - adminCanEdit: + userCanView: type: boolean - userCanAccess: + adminCanEdit: type: boolean - adminCanAccess: + userCanEdit: type: boolean adminCanView: type: boolean - userCanView: + userCanAccess: type: boolean - userCanEdit: + whitePagesCanView: type: boolean baseDn: type: string @@ -7528,6 +7528,8 @@ components: format: int32 displayName: type: string + tokenBindingSupported: + type: boolean authenticationMethod: type: string enum: @@ -7539,8 +7541,6 @@ components: - tls_client_auth - self_signed_tls_client_auth - none - tokenBindingSupported: - type: boolean baseDn: type: string inum: @@ -8343,6 +8343,8 @@ components: $ref: '#/components/schemas/EngineConfig' ssaConfiguration: $ref: '#/components/schemas/SsaConfiguration' + fapi: + type: boolean enabledFeatureFlags: uniqueItems: true type: array @@ -8379,8 +8381,6 @@ components: - code - token - id_token - fapi: - type: boolean AuthenticationFilter: required: - baseDn @@ -8637,13 +8637,13 @@ components: type: boolean internal: type: boolean + locationPath: + type: string locationType: type: string enum: - ldap - file - locationPath: - type: string baseDn: type: string ScriptError: diff --git a/jans-config-api/profiles/local/test.properties b/jans-config-api/profiles/local/test.properties index a323fa7ea3e..e862359e7bc 100644 --- a/jans-config-api/profiles/local/test.properties +++ b/jans-config-api/profiles/local/test.properties @@ -4,6 +4,6 @@ test.scopes=https://jans.io/oauth/config/acrs.readonly https://jans.io/oauth/con # jans.server token.endpoint=https://jans.server2/jans-auth/restv1/token token.grant.type=client_credentials -test.client.id=1800.768b3d38-a6e8-4be4-93d1-72df33d34fd6 -test.client.secret=vA2TTjAOTfQY +test.client.id=1800.0a6a17a0-0d3b-4ce5-881c-f98b2f2b75a7 +test.client.secret=6n1RxN9uEC7q test.issuer=https://jans.server2/ \ No newline at end of file From 5cb08578c4e708ee30d917d3ee6903024401300c Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Tue, 15 Nov 2022 22:00:42 +0530 Subject: [PATCH 12/28] feat(config-api): comprehensive claims for authurization --- .../docs/jans-config-api-swagger-auto.yaml | 28 +- .../plugins/docs/user-mgt-plugin-swagger.yaml | 4 +- .../main/resources/config-api-rs-protect.json | 1577 +++++++++++------ 3 files changed, 1099 insertions(+), 510 deletions(-) diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index 37637256f1a..cd1193c00c4 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7178,19 +7178,19 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - adminCanAccess: + whitePagesCanView: type: boolean - userCanView: + adminCanView: type: boolean - adminCanEdit: + adminCanAccess: type: boolean userCanEdit: type: boolean - adminCanView: + adminCanEdit: type: boolean - userCanAccess: + userCanView: type: boolean - whitePagesCanView: + userCanAccess: type: boolean baseDn: type: string @@ -7528,8 +7528,6 @@ components: format: int32 displayName: type: string - tokenBindingSupported: - type: boolean authenticationMethod: type: string enum: @@ -7541,6 +7539,8 @@ components: - tls_client_auth - self_signed_tls_client_auth - none + tokenBindingSupported: + type: boolean baseDn: type: string inum: @@ -7633,10 +7633,10 @@ components: type: array items: type: object - value: - type: object displayValue: type: string + value: + type: object LocalizedString: type: object properties: @@ -7644,13 +7644,13 @@ components: type: object additionalProperties: type: string - value: - type: string languageTags: uniqueItems: true type: array items: type: string + value: + type: string AppConfiguration: type: object properties: @@ -8343,8 +8343,6 @@ components: $ref: '#/components/schemas/EngineConfig' ssaConfiguration: $ref: '#/components/schemas/SsaConfiguration' - fapi: - type: boolean enabledFeatureFlags: uniqueItems: true type: array @@ -8381,6 +8379,8 @@ components: - code - token - id_token + fapi: + type: boolean AuthenticationFilter: required: - baseDn diff --git a/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml b/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml index 871aacaec5b..cfed2bc9a98 100644 --- a/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml +++ b/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml @@ -785,10 +785,10 @@ components: type: array items: type: object - value: - type: object displayValue: type: string + value: + type: object CustomUser: type: object properties: diff --git a/jans-config-api/server/src/main/resources/config-api-rs-protect.json b/jans-config-api/server/src/main/resources/config-api-rs-protect.json index dcacfbd867c..4e0077bbacc 100644 --- a/jans-config-api/server/src/main/resources/config-api-rs-protect.json +++ b/jans-config-api/server/src/main/resources/config-api-rs-protect.json @@ -1,620 +1,1209 @@ -{"resources":[ +{ + "resources": [ { - "path":"/jans-config-api/api/v1/acrs", - "conditions":[ + "path": "/jans-config-api/api/v1/acrs", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/acrs.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/acrs.readonly" - ] - }, + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.2", + "scope": "https://jans.io/oauth/config/acrs.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/acrs.write" - ] + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/attributes", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/attributes.readonly" - ] - }, - { - "httpMethods":["PATCH","POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/attributes.write" - ] + "path": "/jans-config-api/api/v1/attributes", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/attributes.readonly" } - , + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/attributes.delete" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH", + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/attributes.write" } - ] + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/attributes.delete" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/cache", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/cache.readonly" - ] - }, + "path": "/jans-config-api/api/v1/config/cache", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.write" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/cache/redis", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/cache.readonly" - ] - }, - { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] - }, + "path": "/jans-config-api/api/v1/config/cache/redis", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.write" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.write" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/cache/in-memory", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/cache.readonly" - ] - }, - { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] - }, + "path": "/jans-config-api/api/v1/config/cache/in-memory", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" } - ] + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.write" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.write" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/cache/native-persistence", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/cache.readonly" - ] - }, - { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] - }, + "path": "/jans-config-api/api/v1/config/cache/native-persistence", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.write" } - ] + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.write" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/cache/memcached", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/cache.readonly" - ] - }, - { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] - }, + "path": "/jans-config-api/api/v1/config/cache/memcached", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.write" } - ] + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/cache.write" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/openid/clients", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/openid/clients.readonly" - ] - }, - { - "httpMethods":["PATCH","POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/openid/clients.write" - ] - }, + "path": "/jans-config-api/api/v1/openid/clients", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/openid/clients.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/openid/clients.delete" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH", + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/openid/clients.write" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/openid/clients.delete" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/jans-auth-server/config", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/jans-auth-server/config/properties.readonly" - ] - }, + "path": "/jans-config-api/api/v1/jans-auth-server/config", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/jans-auth-server/config/properties.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/jans-auth-server/config/properties.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/jans-auth-server/config/properties.write" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/jans-auth-server/config/persistence", - "conditions":[ + "path": "/jans-config-api/api/v1/jans-auth-server/config/persistence", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/jans-auth-server/config/properties.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/jans-auth-server/config/properties.readonly" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/smtp", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/smtp.readonly" - ] - }, - { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/smtp.write" - ] - }, + "path": "/jans-config-api/api/v1/config/smtp", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/smtp.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/smtp.delete" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/smtp.write" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/smtp.delete" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/smtp/test", - "conditions":[ - { - "httpMethods":["POST"], - "scopes":[ - "https://jans.io/oauth/config/smtp.readonly" - ] + "path": "/jans-config-api/api/v1/config/smtp/test", + "conditions": [ + { + "httpMethods": [ + "POST" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/smtp.readonly" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/scripts", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/scripts.readonly" - ] - }, + "path": "/jans-config-api/api/v1/config/scripts", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/scripts.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/scripts.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/scripts.write" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/scripts/type/{type}", - "conditions":[ + "path": "/jans-config-api/api/v1/config/scripts/type/{type}", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/scripts.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/scripts.readonly" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/scripts/inum/{inum}", - "conditions":[ + "path": "/jans-config-api/api/v1/config/scripts/inum/{inum}", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/scripts.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/scripts.readonly" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/scripts/{inum}", - "conditions":[ - { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/scripts.delete" - ] - }, - { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/scripts.write" - ] + "path": "/jans-config-api/api/v1/config/scripts/{inum}", + "conditions": [ + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/scripts.delete" } - ] + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/scripts.write" + } + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/fido2/config", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/fido2.readonly" - ] - }, + { + "path": "/jans-config-api/api/v1/fido2/config", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/fido2.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/fido2.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" } - ] + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/fido2.write" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/jwks", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/jwks.readonly" - ] - }, - { - "httpMethods":["PATCH","PUT"], - "scopes":[ - "https://jans.io/oauth/config/jwks.write" - ] - }, + "path": "/jans-config-api/api/v1/config/jwks", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/jwks.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/jwks.delete" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/jwks.write" } - ] + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/jwks.delete" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/database/ldap", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.readonly" - ] - }, + "path": "/jans-config-api/api/v1/config/database/ldap", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/database/ldap.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/database/ldap.write" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/database/ldap/{name}", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.readonly" - ] - }, - { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.write" - ] - }, + "path": "/jans-config-api/api/v1/config/database/ldap/{name}", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/database/ldap.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.delete" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/database/ldap.write" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/database/ldap.delete" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/database/ldap/test", - "conditions":[ - { - "httpMethods":["POST"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.readonly" - ] + "path": "/jans-config-api/api/v1/config/database/ldap/test", + "conditions": [ + { + "httpMethods": [ + "POST" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/database/ldap.readonly" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/logging", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/logging.readonly" - ] - }, + "path": "/jans-config-api/api/v1/logging", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/logging.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/logging.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/logging.write" } - ] + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/scopes", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/scopes.readonly" - ] - }, + { + "path": "/jans-config-api/api/v1/scopes", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/scopes.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/scopes.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/scopes.write" } - ] + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/scopes/{inum}", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/scopes.readonly" - ] - }, - { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/scopes.write" - ] - }, + { + "path": "/jans-config-api/api/v1/scopes/{inum}", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/scopes.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/scopes.delete" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/scopes.write" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/scopes.delete" } - ] + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/uma/resources", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/uma/resources.readonly" - ] - }, + { + "path": "/jans-config-api/api/v1/uma/resources", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/uma/resources.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/uma/resources.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/uma/resources.write" } - ] + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/uma/resources/{id}", - "conditions":[ + { + "path": "/jans-config-api/api/v1/uma/resources/{id}", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/uma/resources.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/uma/resources.readonly" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/uma/resources.write" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/uma/resources.delete" + } + ] + } + ] + }, + { + "path": "/jans-config-api/api/v1/stat", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/stats.readonly" }, { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/uma/resources.write" - ] - }, + "inum": "", + "scope": "jans_stat" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/uma/resources.delete" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" } - - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/stat", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/stats.readonly", - "jans_stat" - ] - } - ] + "path": "/jans-config-api/api/v1/health", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [], + "groupScopes": [], + "superScopes": [] + } + ] }, { - "path":"/jans-config-api/api/v1/health", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ ] - } - ] + "path": "/jans-config-api/api/v1/health/live", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [] + } + ] }, { - "path":"/jans-config-api/api/v1/health/live", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ ] - } - ] + "path": "/jans-config-api/api/v1/health/ready", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [], + "groupScopes": [], + "superScopes": [] + } + ] }, { - "path":"/jans-config-api/api/v1/health/ready", - "conditions":[ + "path": "/jans-config-api/scim/scim-config", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/scim/config.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["GET"], - "scopes":[ ] - } - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/scim/config.write" + } + ] + } + ] }, { - "path":"/jans-config-api/scim/scim-config", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/scim/config.readonly" - ] - }, + "path": "/jans-config-api/api/v1/org", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/organization.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/scim/config.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/organization.write" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/org", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/organization.readonly" - ] - }, + "path": "/jans-config-api/mgt/configuser", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/user.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/organization.write" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" } - ] + ] + }, + { + "httpMethods": [ + "PATCH", + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/user.write" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/user.delete" + } + ] + } + ] }, - { - "path":"/jans-config-api/mgt/configuser", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/user.readonly" - ] - }, - { - "httpMethods":["PATCH","POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/user.write" - ] - }, + { + "path": "/jans-config-api/api/v1/agama", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/agama.readonly" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/user.delete" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/agama.write" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/config/agama.delete" } - ] + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/agama", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/agama.readonly" - ] - }, - { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/agama.write" - ] - }, - { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/agama.delete" - ] + { + "path": "/jans-config-api/api/v1/jans-auth-server/session", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/jans-auth-server/session.readonly" } - ] - } - , - { - "path":"/jans-config-api/api/v1/jans-auth-server/session", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/jans-auth-server/session.readonly" - ] - }, + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["POST"], - "scopes":[ - "https://jans.io/oauth/jans-auth-server/session.delete" - ] + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST" + ], + "scopes": [ + { + "inum": "1800.01.1", + "scope": "https://jans.io/oauth/jans-auth-server/session.delete" } - ] + ] + } + ] } -] + ] } \ No newline at end of file From 0f3c44d248bc12cbbc414c3640822df388cbfba0 Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Wed, 16 Nov 2022 15:43:54 +0530 Subject: [PATCH 13/28] feat(config-api): endpoint group and admin scope --- .../docs/jans-config-api-swagger-auto.yaml | 44 +- .../plugins/docs/user-mgt-plugin-swagger.yaml | 4 +- .../main/resources/config-api-rs-protect.json | 442 +++++++++++++++--- 3 files changed, 396 insertions(+), 94 deletions(-) diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index cd1193c00c4..f0f86ef0136 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7178,19 +7178,19 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - whitePagesCanView: + adminCanAccess: type: boolean adminCanView: type: boolean - adminCanAccess: + userCanView: + type: boolean + userCanAccess: type: boolean userCanEdit: type: boolean adminCanEdit: type: boolean - userCanView: - type: boolean - userCanAccess: + whitePagesCanView: type: boolean baseDn: type: string @@ -7528,6 +7528,8 @@ components: format: int32 displayName: type: string + tokenBindingSupported: + type: boolean authenticationMethod: type: string enum: @@ -7539,8 +7541,6 @@ components: - tls_client_auth - self_signed_tls_client_auth - none - tokenBindingSupported: - type: boolean baseDn: type: string inum: @@ -7633,10 +7633,10 @@ components: type: array items: type: object - displayValue: - type: string value: type: object + displayValue: + type: string LocalizedString: type: object properties: @@ -7644,13 +7644,13 @@ components: type: object additionalProperties: type: string + value: + type: string languageTags: uniqueItems: true type: array items: type: string - value: - type: string AppConfiguration: type: object properties: @@ -8343,6 +8343,17 @@ components: $ref: '#/components/schemas/EngineConfig' ssaConfiguration: $ref: '#/components/schemas/SsaConfiguration' + allResponseTypesSupported: + uniqueItems: true + type: array + items: + type: string + enum: + - code + - token + - id_token + fapi: + type: boolean enabledFeatureFlags: uniqueItems: true type: array @@ -8370,17 +8381,6 @@ components: - STAT - PAR - SSA - allResponseTypesSupported: - uniqueItems: true - type: array - items: - type: string - enum: - - code - - token - - id_token - fapi: - type: boolean AuthenticationFilter: required: - baseDn diff --git a/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml b/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml index cfed2bc9a98..871aacaec5b 100644 --- a/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml +++ b/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml @@ -785,10 +785,10 @@ components: type: array items: type: object - displayValue: - type: string value: type: object + displayValue: + type: string CustomUser: type: object properties: diff --git a/jans-config-api/server/src/main/resources/config-api-rs-protect.json b/jans-config-api/server/src/main/resources/config-api-rs-protect.json index 4e0077bbacc..7b34ecce736 100644 --- a/jans-config-api/server/src/main/resources/config-api-rs-protect.json +++ b/jans-config-api/server/src/main/resources/config-api-rs-protect.json @@ -50,7 +50,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.3", "scope": "https://jans.io/oauth/config/attributes.readonly" } ], @@ -70,9 +70,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.4", "scope": "https://jans.io/oauth/config/attributes.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -81,9 +88,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.5", "scope": "https://jans.io/oauth/config/attributes.delete" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "scope": "https://jans.io/oauth/config/delete-all" + } ] } ] @@ -97,7 +111,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.6", "scope": "https://jans.io/oauth/config/cache.readonly" } ], @@ -115,9 +129,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.7", "scope": "https://jans.io/oauth/config/cache.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -131,7 +152,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.6", "scope": "https://jans.io/oauth/config/cache.readonly" } ], @@ -149,9 +170,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.7", "scope": "https://jans.io/oauth/config/cache.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -160,9 +188,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.7", "scope": "https://jans.io/oauth/config/cache.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -176,7 +211,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.6", "scope": "https://jans.io/oauth/config/cache.readonly" } ], @@ -194,9 +229,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.7", "scope": "https://jans.io/oauth/config/cache.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -205,9 +247,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.7", "scope": "https://jans.io/oauth/config/cache.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -221,7 +270,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.6", "scope": "https://jans.io/oauth/config/cache.readonly" } ], @@ -239,9 +288,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.7", "scope": "https://jans.io/oauth/config/cache.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -250,9 +306,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.7", "scope": "https://jans.io/oauth/config/cache.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -266,7 +329,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.6", "scope": "https://jans.io/oauth/config/cache.readonly" } ], @@ -284,9 +347,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.7", "scope": "https://jans.io/oauth/config/cache.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -295,9 +365,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.7", "scope": "https://jans.io/oauth/config/cache.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -311,11 +388,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.8", "scope": "https://jans.io/oauth/config/openid/clients.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.02.1", + "scope": "https://jans.io/oauth/config/openid-read" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -331,9 +413,21 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.9", "scope": "https://jans.io/oauth/config/openid/clients.write" } + ], + "groupScopes": [ + { + "inum": "1800.02.2", + "scope": "https://jans.io/oauth/config/openid-write" + } + ], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -342,9 +436,21 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.10", "scope": "https://jans.io/oauth/config/openid/clients.delete" } + ], + "groupScopes": [ + { + "inum": "1800.02.3", + "scope": "https://jans.io/oauth/config/openid-delete" + } + ], + "superScopes": [ + { + "inum": "1800.03.3", + "scope": "https://jans.io/oauth/config/delete-all" + } ] } ] @@ -358,7 +464,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.11", "scope": "https://jans.io/oauth/jans-auth-server/config/properties.readonly" } ], @@ -376,9 +482,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.12", "scope": "https://jans.io/oauth/jans-auth-server/config/properties.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -392,7 +505,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.11", "scope": "https://jans.io/oauth/jans-auth-server/config/properties.readonly" } ], @@ -415,7 +528,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.13", "scope": "https://jans.io/oauth/config/smtp.readonly" } ], @@ -434,9 +547,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.14", "scope": "https://jans.io/oauth/config/smtp.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -445,9 +565,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.15", "scope": "https://jans.io/oauth/config/smtp.delete" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "scope": "https://jans.io/oauth/config/delete-all" + } ] } ] @@ -461,9 +588,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.13", "scope": "https://jans.io/oauth/config/smtp.readonly" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } ] } ] @@ -477,7 +611,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.16", "scope": "https://jans.io/oauth/config/scripts.readonly" } ], @@ -496,9 +630,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.17", "scope": "https://jans.io/oauth/config/scripts.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -512,7 +653,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.16", "scope": "https://jans.io/oauth/config/scripts.readonly" } ], @@ -535,7 +676,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.16", "scope": "https://jans.io/oauth/config/scripts.readonly" } ], @@ -558,9 +699,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.18", "scope": "https://jans.io/oauth/config/scripts.delete" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "scope": "https://jans.io/oauth/config/delete-all" + } ] }, { @@ -569,9 +717,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.17", "scope": "https://jans.io/oauth/config/scripts.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -585,7 +740,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.19", "scope": "https://jans.io/oauth/config/fido2.readonly" } ], @@ -603,9 +758,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.20", "scope": "https://jans.io/oauth/config/fido2.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -619,7 +781,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.21", "scope": "https://jans.io/oauth/config/jwks.readonly" } ], @@ -638,9 +800,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.22", "scope": "https://jans.io/oauth/config/jwks.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -649,9 +818,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.23", "scope": "https://jans.io/oauth/config/jwks.delete" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "scope": "https://jans.io/oauth/config/delete-all" + } ] } ] @@ -665,7 +841,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.24", "scope": "https://jans.io/oauth/config/database/ldap.readonly" } ], @@ -684,9 +860,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.25", "scope": "https://jans.io/oauth/config/database/ldap.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -700,7 +883,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.24", "scope": "https://jans.io/oauth/config/database/ldap.readonly" } ], @@ -718,9 +901,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.25", "scope": "https://jans.io/oauth/config/database/ldap.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -729,9 +919,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.26", "scope": "https://jans.io/oauth/config/database/ldap.delete" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "scope": "https://jans.io/oauth/config/delete-all" + } ] } ] @@ -745,9 +942,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.24", "scope": "https://jans.io/oauth/config/database/ldap.readonly" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.1", + "scope": "https://jans.io/oauth/config/read-all" + } ] } ] @@ -761,7 +965,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.27", "scope": "https://jans.io/oauth/config/logging.readonly" } ], @@ -779,9 +983,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.28", "scope": "https://jans.io/oauth/config/logging.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -795,7 +1006,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.29", "scope": "https://jans.io/oauth/config/scopes.readonly" } ], @@ -814,9 +1025,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.30", "scope": "https://jans.io/oauth/config/scopes.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -830,7 +1048,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.29", "scope": "https://jans.io/oauth/config/scopes.readonly" } ], @@ -848,9 +1066,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.30", "scope": "https://jans.io/oauth/config/scopes.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -859,9 +1084,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.31", "scope": "https://jans.io/oauth/config/scopes.delete" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "scope": "https://jans.io/oauth/config/delete-all" + } ] } ] @@ -875,7 +1107,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.32", "scope": "https://jans.io/oauth/config/uma/resources.readonly" } ], @@ -894,9 +1126,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.33", "scope": "https://jans.io/oauth/config/uma/resources.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -910,7 +1149,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.32", "scope": "https://jans.io/oauth/config/uma/resources.readonly" } ], @@ -928,9 +1167,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.33", "scope": "https://jans.io/oauth/config/uma/resources.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -939,9 +1185,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.34", "scope": "https://jans.io/oauth/config/uma/resources.delete" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "scope": "https://jans.io/oauth/config/delete-all" + } ] } ] @@ -955,7 +1208,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.35", "scope": "https://jans.io/oauth/config/stats.readonly" }, { @@ -1019,7 +1272,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.36", "scope": "https://jans.io/scim/config.readonly" } ], @@ -1037,9 +1290,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.37", "scope": "https://jans.io/scim/config.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -1053,7 +1313,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.38", "scope": "https://jans.io/oauth/config/organization.readonly" } ], @@ -1071,9 +1331,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.39", "scope": "https://jans.io/oauth/config/organization.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] } ] @@ -1087,7 +1354,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.40", "scope": "https://jans.io/oauth/config/user.readonly" } ], @@ -1107,9 +1374,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.41", "scope": "https://jans.io/oauth/config/user.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -1118,9 +1392,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.42", "scope": "https://jans.io/oauth/config/user.delete" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "scope": "https://jans.io/oauth/config/delete-all" + } ] } ] @@ -1134,7 +1415,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.43", "scope": "https://jans.io/oauth/config/agama.readonly" } ], @@ -1153,9 +1434,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.44", "scope": "https://jans.io/oauth/config/agama.write" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "scope": "https://jans.io/oauth/config/write-all" + } ] }, { @@ -1164,9 +1452,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.45", "scope": "https://jans.io/oauth/config/agama.delete" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "scope": "https://jans.io/oauth/config/delete-all" + } ] } ] @@ -1180,7 +1475,7 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.46", "scope": "https://jans.io/oauth/jans-auth-server/session.readonly" } ], @@ -1198,9 +1493,16 @@ ], "scopes": [ { - "inum": "1800.01.1", + "inum": "1800.01.47", "scope": "https://jans.io/oauth/jans-auth-server/session.delete" } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "scope": "https://jans.io/oauth/config/delete-all" + } ] } ] From 30578ea9ac6191b0d5391e1a151d3e2753590b50 Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Wed, 16 Nov 2022 15:46:46 +0530 Subject: [PATCH 14/28] feat(config-api): sync with main --- ; | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 ; diff --git a/; b/; new file mode 100644 index 00000000000..8982a76312a --- /dev/null +++ b/; @@ -0,0 +1,6 @@ +Merge branch 'main' of https://github.com/JanssenProject/jans into jans-config-fixes +# Please enter a commit message to explain why this merge is necessary, +# especially if it merges an updated upstream into a topic branch. +# +# Lines starting with '#' will be ignored, and an empty message aborts +# the commit. From d125213110a8356586842e8d9e9fd82f126cac2f Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Wed, 16 Nov 2022 22:31:06 +0530 Subject: [PATCH 15/28] feat(config-api): endpoint group and admin scope --- .../security/api/ApiProtectionCache.java | 29 ++++- .../security/api/ApiProtectionService.java | 118 ++++++++++-------- .../configapi/service/auth/ScopeService.java | 10 ++ .../main/resources/config-api-rs-protect.json | 6 +- .../configapi/core/protect/Condition.java | 59 +++++++++ .../configapi/core/protect/RsResource.java | 96 ++++++++++++++ .../core/protect/RsResourceList.java | 37 ++++++ .../io/jans/configapi/core/protect/Scope.java | 36 ++++++ 8 files changed, 335 insertions(+), 56 deletions(-) create mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Condition.java create mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResource.java create mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResourceList.java create mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Scope.java diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java index 45fe6bd1896..de3df0199cf 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java @@ -9,6 +9,7 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Named; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -24,6 +25,9 @@ public class ApiProtectionCache { private static final Cache> resourceCache = CacheBuilder.newBuilder() .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); + + private static final Cache>> resourceScopeCache = CacheBuilder.newBuilder() + .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); // Scope public static void removeAllScopes() { @@ -63,11 +67,34 @@ public static List getResourceScopes(String resourceName) { public static void putResource(String resourceName, List scopeList) { Preconditions.checkNotNull(resourceName); resourceCache.put(resourceName, scopeList); - } public static Map> getAllResources() { return Maps.newHashMap(resourceCache.asMap()); } + + public static void putResource(String resourceName, Map> scopeMap) { + Preconditions.checkNotNull(resourceName); + resourceScopeCache.put(resourceName, scopeMap); + } + + public static void putResourceScopeByType(String resourceName, String scopeType, List scopes) { + Preconditions.checkNotNull(resourceName); + Preconditions.checkNotNull(scopeType); + Map> scopeMap = resourceScopeCache.getIfPresent(resourceName); + if(scopeMap==null) { + scopeMap = new HashMap<>(); + } + scopeMap.put(scopeType, scopes); + } + public static List getResourceScopeByType(String resourceName, String scopeType) { + Preconditions.checkNotNull(resourceName); + Preconditions.checkNotNull(scopeType); + Map> scopeMap = resourceScopeCache.getIfPresent(resourceName); + if(scopeMap==null) { + return null; + } + return scopeMap.get(scopeType); + } } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java index 334e565cf2c..570a66a2640 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java @@ -3,14 +3,15 @@ import com.google.common.base.Preconditions; import io.jans.as.common.model.registration.Client; import io.jans.as.model.common.ScopeType; -import io.jans.ca.rs.protect.Condition; -import io.jans.ca.rs.protect.RsResource; -import io.jans.ca.rs.protect.RsResourceList; +import io.jans.configapi.core.protect.Condition; +import io.jans.configapi.core.protect.RsResource; +import io.jans.configapi.core.protect.RsResourceList; import io.jans.as.persistence.model.Scope; import io.jans.configapi.configuration.ConfigurationFactory; import io.jans.configapi.service.auth.ClientService; import io.jans.configapi.service.auth.ScopeService; import io.jans.configapi.core.util.Jackson; +import io.jans.configapi.core.util.ProtectionScope; import java.io.IOException; import java.io.InputStream; @@ -78,82 +79,95 @@ public void verifyResources(String apiProtectionType, String clientId) throws IO private void createScopeIfNeeded(String apiProtectionType) { log.debug("ApiProtectionService:::createScopeIfNeeded() - apiProtectionType:{}", apiProtectionType); - List rsScopes = null; + List scopeList = new ArrayList<>(); for (RsResource rsResource : rsResourceList) { for (Condition condition : rsResource.getConditions()) { String resourceName = condition.getHttpMethods() + ":::" + rsResource.getPath(); - rsScopes = condition.getScopes(); - log.trace("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, rsScopes:{} ", resourceName, - rsScopes); + + log.trace("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, condition.getScopes():{}, condition.getGroupScopes():{}, condition.getSuperScopes():{}", resourceName, + condition.getScopes(), condition.getGroupScopes(), condition.getSuperScopes()); + // Process Scopes // If no scopes for the path then skip validation - if (rsScopes == null || rsScopes.isEmpty()) { - break; + List rsScopes = condition.getScopes(); + if (rsScopes != null && !rsScopes.isEmpty()) { + processScope(resourceName, ProtectionScope.SCOPE, rsScopes); } - - for (String scopeName : rsScopes) { - log.debug("ApiProtectionService:::createScopeIfNeeded() - scopeName:{} ", scopeName); - - // Check in cache - Scope scope = ApiProtectionCache.getScope(scopeName); - log.debug( - "ApiProtectionService:::createScopeIfNeeded() - ApiProtectionCache.getScope(scopeName):{}", - ApiProtectionCache.getScope(scopeName)); - - if (scope != null) { - log.debug("Scope - '{}' exists in cache.", scopeName); - scopeList.add(scope); - break; - } - - // validate scope - scopeList = validateScope(scopeName); - - } // for scopes - - // Add to resource cache - ApiProtectionCache.putResource(resourceName, scopeList); + + // If no group scopes for the path then skip validation + List groupScopes = condition.getGroupScopes(); + if (groupScopes != null && !groupScopes.isEmpty()) { + processScope(resourceName, ProtectionScope.GROUP, groupScopes); + } + + // If no super scopes for the path then skip validation + List superScopes = condition.getSuperScopes(); + if (superScopes != null && !superScopes.isEmpty()) { + processScope(resourceName, ProtectionScope.SUPER, superScopes); + } + log.debug("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, scopeList:{}", resourceName, scopeList); } // condition } } + + private void processScope(String resourceName, ProtectionScope scopeType, List scopeList){ + log.debug("ApiProtectionService:::processScope() - resourceName:{}, scopeType:{}, scopeList:{}", resourceName, scopeType, scopeList); + + //return if no scopes + if(scopeList==null || scopeList.isEmpty()) { + return; + } + + for(io.jans.configapi.core.protect.Scope rsScope : scopeList) { + String inum = rsScope.getInum(); + String scopeName = rsScope.getInum(); + + //return if no scope details + if(StringUtils.isBlank(inum) || StringUtils.isBlank(scopeName)){ + return; + } + + List scopes = validateScope(rsScope); + ApiProtectionCache.putResourceScopeByType(resourceName, scopeType.toString().toUpperCase(), scopes); + } + } - private List validateScope(String scopeName) { + private List validateScope(io.jans.configapi.core.protect.Scope rsScope) { + log.debug("Verify Scope in DB - {} ", rsScope); List scopeList = new ArrayList<>(); - Scope scope = null; + // Check in DB - log.debug("Verify Scope in DB - {} ", scopeName); - List scopes = scopeService.searchScopesById(scopeName); - log.debug("Scopes from DB - {}'", scopes); + Scope scope = scopeService.getScope(rsScope.getInum()); + log.debug("Scopes from DB - {}'", scope); - if (scopes != null && !scopes.isEmpty()) { + if (scope != null) { // Fetch existing scope to store in cache - scope = scopes.get(0); log.debug("Scope from DB is - {}", scope.getId()); scopeList.add(scope); } ScopeType scopeType = ScopeType.OAUTH; - log.trace("Scope details - scopes:{}, scopeName:{}, exclusiveAuthScopes:{}, isConfigApiScope(scopeName):{} '", - scopes, scopeName, configurationFactory.getApiAppConfiguration().getExclusiveAuthScopes(), - isConfigApiScope(scopeName)); + log.trace("Scope details - scope:{}, rsScope.getName():{}, exclusiveAuthScopes:{}, isConfigApiScope(scopeName):{} '", + scope, rsScope.getName(), configurationFactory.getApiAppConfiguration().getExclusiveAuthScopes(), + isConfigApiScope(rsScope.getName())); // Create/Update scope only if they are config-api-resource scopes - if (isConfigApiScope(scopeName)) { + if (isConfigApiScope(rsScope.getName())) { //ensure scope does not exists - scopes = scopeService.searchScopesById(scopeName); - log.debug("ConfigApiScope scopeName:{} in DB - scopes:{} ", scopeName, scopes); - if (scopes == null || scopes.isEmpty()) { - log.debug("Scope - '{}' does not exist, hence creating it.", scopeName); + scope = scopeService.getScope(rsScope.getInum()); + log.debug("Re-verify ConfigApiScope rsScope.getName():{} with rsScope.getInum():{} in DB - scope:{} ", rsScope.getName(), rsScope.getInum(), scope); + if (scope == null) { + log.debug("Scope - '{}' does not exist, hence creating it.", scope); // Scope does not exists hence create Scope scope = new Scope(); - String inum = UUID.randomUUID().toString(); - scope.setId(scopeName); - scope.setDisplayName(scopeName); + String inum = rsScope.getInum(); + scope.setId(rsScope.getName()); + scope.setDisplayName(rsScope.getName()); scope.setInum(inum); scope.setDn(scopeService.getDnForScope(inum)); scope.setScopeType(scopeType); @@ -161,8 +175,8 @@ private List validateScope(String scopeName) { } if (scope != null) { // Update resource - log.debug("Scope - '{}' already exists, hence updating it.", scopeName); - scope.setId(scopeName); + log.debug("Scope - '{}' already exists, hence updating it.", rsScope.getName()); + scope.setId(rsScope.getName()); scope.setScopeType(scopeType); scopeService.updateScope(scope); } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java index c0a71d98b37..991bc1c1257 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java @@ -24,6 +24,7 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import org.apache.commons.lang.StringUtils; +import org.python.jline.internal.Log; import org.slf4j.Logger; import java.util.ArrayList; @@ -88,6 +89,15 @@ public void updateScope(Scope scope) { persistenceEntryManager.merge(scope); } + public Scope getScope(String inum) { + try { + return persistenceEntryManager.find(Scope.class, getDnForScope(inum)); + } catch (Exception ex) { + Log.error("Error while finding scope is : {}", ex); + } + return null; + } + public CustomScope getScopeByInum(String inum) { return getScopeByInum(inum, false); } diff --git a/jans-config-api/server/src/main/resources/config-api-rs-protect.json b/jans-config-api/server/src/main/resources/config-api-rs-protect.json index 7b34ecce736..bf92927f2e8 100644 --- a/jans-config-api/server/src/main/resources/config-api-rs-protect.json +++ b/jans-config-api/server/src/main/resources/config-api-rs-protect.json @@ -1483,7 +1483,7 @@ "superScopes": [ { "inum": "1800.03.1", - "scope": "https://jans.io/oauth/config/read-all" + "name": "https://jans.io/oauth/config/read-all" } ] }, @@ -1494,14 +1494,14 @@ "scopes": [ { "inum": "1800.01.47", - "scope": "https://jans.io/oauth/jans-auth-server/session.delete" + "name": "https://jans.io/oauth/jans-auth-server/session.delete" } ], "groupScopes": [], "superScopes": [ { "inum": "1800.03.3", - "scope": "https://jans.io/oauth/config/delete-all" + "name": "https://jans.io/oauth/config/delete-all" } ] } diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Condition.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Condition.java new file mode 100644 index 00000000000..a1bcfdd48da --- /dev/null +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Condition.java @@ -0,0 +1,59 @@ +package io.jans.configapi.core.protect; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Condition { + + @JsonProperty(value = "httpMethods") + List httpMethods; + @JsonProperty(value = "scopes") + List scopes; + @JsonProperty(value = "groupScopes") + List groupScopes; + @JsonProperty(value = "superScopes") + List superScopes; + + public List getHttpMethods() { + return httpMethods; + } + + public void setHttpMethods(List httpMethods) { + this.httpMethods = httpMethods; + } + + public List getScopes() { + return scopes; + } + + public void setScopes(List scopes) { + this.scopes = scopes; + } + + public List getGroupScopes() { + return groupScopes; + } + + public void setGroupScopes(List groupScopes) { + this.groupScopes = groupScopes; + } + + public List getSuperScopes() { + return superScopes; + } + + public void setSuperScopes(List superScopes) { + this.superScopes = superScopes; + } + + @Override + public String toString() { + return "Condition [httpMethods=" + httpMethods + ", scopes=" + scopes + ", groupScopes=" + groupScopes + + ", superScopes=" + superScopes + "]"; + } + + } diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResource.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResource.java new file mode 100644 index 00000000000..b697ee8eca6 --- /dev/null +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResource.java @@ -0,0 +1,96 @@ +package io.jans.configapi.core.protect; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.Maps; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + + +@JsonIgnoreProperties(ignoreUnknown = true) +public class RsResource implements Serializable { + + @JsonProperty(value = "path") + String path; + @JsonProperty(value = "conditions") + List conditions; + @JsonProperty(value = "iat") + private Integer iat; + @JsonProperty(value = "exp") + private Integer exp; + + private Map httpMethodToCondition = null; + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public List getConditions() { + return conditions; + } + + public void setConditions(List conditions) { + this.conditions = conditions; + } + + public List scopes(String httpMethod) { + return getConditionMap().get(httpMethod).getScopes(); + } + + public Integer getIat() { + return iat; + } + + public void setIat(Integer iat) { + this.iat = iat; + } + + public Integer getExp() { + return exp; + } + + public void setExp(Integer exp) { + this.exp = exp; + } + + + + public Map getConditionMap() { + if (httpMethodToCondition == null) { + initMap(); + } + return httpMethodToCondition; + } + + private void initMap() { + httpMethodToCondition = Maps.newHashMap(); + if (conditions != null) { + for (Condition condition : conditions) { + if (condition.getHttpMethods() != null) { + for (String httpMethod : condition.getHttpMethods()) { + httpMethodToCondition.put(httpMethod, condition); + } + } + } + } + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("RsResource"); + sb.append("{path='").append(path).append('\''); + sb.append(", conditions=").append(conditions); + sb.append(", httpMethodToCondition=").append(httpMethodToCondition); + sb.append(", iat=").append(iat); + sb.append(", exp=").append(exp); + sb.append('}'); + return sb.toString(); + } +} diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResourceList.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResourceList.java new file mode 100644 index 00000000000..af61652f335 --- /dev/null +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResourceList.java @@ -0,0 +1,37 @@ +package io.jans.configapi.core.protect; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.Lists; + +import java.io.Serializable; +import java.util.List; + +public class RsResourceList implements Serializable { + + @JsonProperty(value = "resources") + private List resources = Lists.newArrayList(); + + public RsResourceList() { + } + + public RsResourceList(List resources) { + this.resources = resources; + } + + public List getResources() { + return resources; + } + + public void setResources(List resources) { + this.resources = resources; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("RsResourceList"); + sb.append("{resources=").append(resources); + sb.append('}'); + return sb.toString(); + } +} diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Scope.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Scope.java new file mode 100644 index 00000000000..3bdc29c61a8 --- /dev/null +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Scope.java @@ -0,0 +1,36 @@ +package io.jans.configapi.core.protect; + + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Scope { + + @JsonProperty(value = "inum") + private String inum; + @JsonProperty(value = "name") + private String name; + + public String getInum() { + return inum; + } + + public void setInum(String inum) { + this.inum = inum; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Scope [inum=" + inum + ", name=" + name + "]"; + } + + } From 7b28e685b30e70a9ce6710d378e86c4929bb386e Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Tue, 22 Nov 2022 13:55:32 +0530 Subject: [PATCH 16/28] feat(config-api): scope change - wip --- .../docs/jans-config-api-swagger-auto.yaml | 36 ++++++++++--------- .../docs/jans-admin-ui-plugin-swagger.yaml | 6 ++-- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index f0f86ef0136..1b86dfa8ace 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7178,19 +7178,19 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - adminCanAccess: - type: boolean - adminCanView: + whitePagesCanView: type: boolean - userCanView: + adminCanAccess: type: boolean userCanAccess: type: boolean - userCanEdit: + userCanView: type: boolean adminCanEdit: type: boolean - whitePagesCanView: + adminCanView: + type: boolean + userCanEdit: type: boolean baseDn: type: string @@ -7622,6 +7622,8 @@ components: idTokenLifetime: type: integer format: int32 + allowOfflineAccessWithoutConsent: + type: boolean CustomObjectAttribute: type: object properties: @@ -8343,15 +8345,6 @@ components: $ref: '#/components/schemas/EngineConfig' ssaConfiguration: $ref: '#/components/schemas/SsaConfiguration' - allResponseTypesSupported: - uniqueItems: true - type: array - items: - type: string - enum: - - code - - token - - id_token fapi: type: boolean enabledFeatureFlags: @@ -8381,6 +8374,15 @@ components: - STAT - PAR - SSA + allResponseTypesSupported: + uniqueItems: true + type: array + items: + type: string + enum: + - code + - token + - id_token AuthenticationFilter: required: - baseDn @@ -8637,13 +8639,13 @@ components: type: boolean internal: type: boolean - locationPath: - type: string locationType: type: string enum: - ldap - file + locationPath: + type: string baseDn: type: string ScriptError: diff --git a/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml b/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml index e3c9c9b3e63..a03ee668a5d 100644 --- a/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml +++ b/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml @@ -462,7 +462,7 @@ paths: description: InternalServerError security: - oauth2: - - https://jans.io/oauth/jans-auth-server/config/adminui/user/permission.write + - https://jans.io/oauth/jans-auth-server/config/adminui/user/permission.delete /admin-ui/adminUIRoles/{adminUIRole}: get: tags: @@ -523,7 +523,7 @@ paths: description: InternalServerError security: - oauth2: - - https://jans.io/oauth/jans-auth-server/config/adminui/user/role.write + - https://jans.io/oauth/jans-auth-server/config/adminui/user/role.delete /admin-ui/adminUIRolePermissionsMapping/{adminUIRole}: get: tags: @@ -584,7 +584,7 @@ paths: description: InternalServerError security: - oauth2: - - https://jans.io/oauth/jans-auth-server/config/adminui/user/rolePermissionMapping.write + - https://jans.io/oauth/jans-auth-server/config/adminui/user/rolePermissionMapping.delete components: schemas: LicenseRequest: From 7a29e9dfe3e3bea2425d1c90455a58ccaa756eaf Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Tue, 22 Nov 2022 17:59:19 +0530 Subject: [PATCH 17/28] feat(config-api): scope change - wip --- .../docs/jans-config-api-swagger-auto.yaml | 22 +-- .../security/api/ApiProtectionCache.java | 142 +++++++++++++++--- .../security/api/ApiProtectionService.java | 29 ++-- .../java/io/jans/configapi/util/AuthUtil.java | 18 +-- .../configapi/core/util/ProtectionScope.java | 15 -- .../core/util/ProtectionScopeType.java | 37 +++++ 6 files changed, 194 insertions(+), 69 deletions(-) delete mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScope.java create mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScopeType.java diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index 2bcba276d05..fd4a56b7ce6 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7178,19 +7178,19 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - adminCanAccess: - type: boolean - userCanAccess: - type: boolean - userCanView: + whitePagesCanView: type: boolean adminCanView: type: boolean + adminCanEdit: + type: boolean userCanEdit: type: boolean - adminCanEdit: + userCanAccess: type: boolean - whitePagesCanView: + adminCanAccess: + type: boolean + userCanView: type: boolean baseDn: type: string @@ -7526,8 +7526,6 @@ components: ttl: type: integer format: int32 - displayName: - type: string tokenBindingSupported: type: boolean authenticationMethod: @@ -7541,6 +7539,8 @@ components: - tls_client_auth - self_signed_tls_client_auth - none + displayName: + type: string baseDn: type: string inum: @@ -8639,13 +8639,13 @@ components: type: boolean internal: type: boolean + locationPath: + type: string locationType: type: string enum: - ldap - file - locationPath: - type: string baseDn: type: string ScriptError: diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java index de3df0199cf..3fbfc5f6ed8 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java @@ -6,9 +6,11 @@ import com.google.common.cache.CacheBuilder; import com.google.common.collect.Maps; import io.jans.as.persistence.model.Scope; +import io.jans.configapi.core.util.ProtectionScopeType; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Named; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -25,10 +27,18 @@ public class ApiProtectionCache { private static final Cache> resourceCache = CacheBuilder.newBuilder() .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); - - private static final Cache>> resourceScopeCache = CacheBuilder.newBuilder() + + private static final Cache groupScopeCache = CacheBuilder.newBuilder() + .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); + + private static final Cache superScopeCache = CacheBuilder.newBuilder() .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); + private static final Cache>> resourceScopeCache = CacheBuilder + .newBuilder().expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); + + ApiProtectionCache(){} + // Scope public static void removeAllScopes() { scopeCache.invalidateAll(); @@ -48,10 +58,72 @@ public static void putScope(Scope scope) { } } - public static Map getAllScopes() { + public static Map getScopes() { return Maps.newHashMap(scopeCache.asMap()); } + // Group Scope + public static Scope getGroupScope(String scopeName) { + Preconditions.checkNotNull(scopeName); + Preconditions.checkState(!Strings.isNullOrEmpty(scopeName)); + return groupScopeCache.getIfPresent(scopeName); + + } + + public static void putGroupScope(Scope scope) { + Preconditions.checkNotNull(scope); + if (groupScopeCache.getIfPresent(scope.getId()) == null) { + groupScopeCache.put(scope.getId(), scope); + } + } + + public static void removeAllGroupScopes() { + groupScopeCache.invalidateAll(); + } + + public static Map getAllGroupScopes() { + return Maps.newHashMap(groupScopeCache.asMap()); + } + + // Super Scope + public static Scope getSuperScope(String scopeName) { + Preconditions.checkNotNull(scopeName); + Preconditions.checkState(!Strings.isNullOrEmpty(scopeName)); + return superScopeCache.getIfPresent(scopeName); + + } + + public static void putSuperScope(Scope scope) { + Preconditions.checkNotNull(scope); + if (superScopeCache.getIfPresent(scope.getId()) == null) { + superScopeCache.put(scope.getId(), scope); + } + } + + public static void removeAllSuperScopes() { + superScopeCache.invalidateAll(); + } + + public static Map getAllSuperScopes() { + return Maps.newHashMap(superScopeCache.asMap()); + } + + // All Scope + public static Map getAllTypesOfScopes() { + Map scopes = Maps.newHashMap(scopeCache.asMap()); + scopes.putAll(Maps.newHashMap(groupScopeCache.asMap())); + scopes.putAll(Maps.newHashMap(superScopeCache.asMap())); + return scopes; + } + + + public static Map getAllScopesMap() { + Map scopes = Maps.newHashMap(scopeCache.asMap()); + scopes.putAll(Maps.newHashMap(groupScopeCache.asMap())); + scopes.putAll(Maps.newHashMap(superScopeCache.asMap())); + return scopes; + } + // Resource public static void removeAllResources() { resourceCache.invalidateAll(); @@ -67,34 +139,64 @@ public static List getResourceScopes(String resourceName) { public static void putResource(String resourceName, List scopeList) { Preconditions.checkNotNull(resourceName); resourceCache.put(resourceName, scopeList); + } public static Map> getAllResources() { return Maps.newHashMap(resourceCache.asMap()); } - - public static void putResource(String resourceName, Map> scopeMap) { + + // ResourceScopeCache + + public static void putResource(String resourceName, Map> scopeMap) { Preconditions.checkNotNull(resourceName); resourceScopeCache.put(resourceName, scopeMap); } - - public static void putResourceScopeByType(String resourceName, String scopeType, List scopes) { + + public static void putResourceScopeByType(String resourceName, ProtectionScopeType protectionScopeType, + List scopes) { Preconditions.checkNotNull(resourceName); - Preconditions.checkNotNull(scopeType); - Map> scopeMap = resourceScopeCache.getIfPresent(resourceName); - if(scopeMap==null) { - scopeMap = new HashMap<>(); - } - scopeMap.put(scopeType, scopes); + Preconditions.checkNotNull(protectionScopeType); + Map> scopeMap = resourceScopeCache.getIfPresent(resourceName); + if (scopeMap == null) { + scopeMap = new HashMap<>(); + } + scopeMap.put(protectionScopeType, scopes); + resourceScopeCache.put(resourceName, scopeMap); + } + + public static List getResourceScopeByType(String resourceName, ProtectionScopeType protectionScopeType) { + Preconditions.checkNotNull(resourceName); + Preconditions.checkNotNull(protectionScopeType); + Map> scopeMap = resourceScopeCache.getIfPresent(resourceName); + if (scopeMap == null) { + return Collections.emptyList(); + } + return scopeMap.get(protectionScopeType); + } + + public static Map>> getAllResourcesMap() { + return Maps.newHashMap(resourceScopeCache.asMap()); } - public static List getResourceScopeByType(String resourceName, String scopeType) { + public static void addScope(String resourceName, ProtectionScopeType protectionScopeType, Scope scope) { Preconditions.checkNotNull(resourceName); - Preconditions.checkNotNull(scopeType); - Map> scopeMap = resourceScopeCache.getIfPresent(resourceName); - if(scopeMap==null) { - return null; - } - return scopeMap.get(scopeType); + Preconditions.checkNotNull(protectionScopeType); + Preconditions.checkNotNull(scope); + + switch (protectionScopeType) { + case GROUP: + putGroupScope(scope); + break; + + case SUPER: + putSuperScope(scope); + break; + + default: + putScope(scope); + break; + + } } } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java index 570a66a2640..63619fe49c1 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java @@ -11,7 +11,7 @@ import io.jans.configapi.service.auth.ClientService; import io.jans.configapi.service.auth.ScopeService; import io.jans.configapi.core.util.Jackson; -import io.jans.configapi.core.util.ProtectionScope; +import io.jans.configapi.core.util.ProtectionScopeType; import java.io.IOException; import java.io.InputStream; @@ -69,8 +69,8 @@ public void verifyResources(String apiProtectionType, String clientId) throws IO Preconditions.checkNotNull(rsResourceList, "Config Api Resource list cannot be null !!!"); createScopeIfNeeded(apiProtectionType); - log.trace("ApiProtectionService:::verifyResources() - allScopes:{}, allResources:{} ", - ApiProtectionCache.getAllScopes(), ApiProtectionCache.getAllResources()); + log.trace("ApiProtectionService:::verifyResources() - getAllTypesOfScopes:{}, allResources:{}, getAllResourcesMap:{} ", + ApiProtectionCache.getAllTypesOfScopes(), ApiProtectionCache.getAllResources(), ApiProtectionCache.getAllResourcesMap()); updateScopeForClientIfNeeded(clientId); @@ -92,19 +92,19 @@ private void createScopeIfNeeded(String apiProtectionType) { // If no scopes for the path then skip validation List rsScopes = condition.getScopes(); if (rsScopes != null && !rsScopes.isEmpty()) { - processScope(resourceName, ProtectionScope.SCOPE, rsScopes); + processScope(resourceName, ProtectionScopeType.SCOPE, rsScopes); } // If no group scopes for the path then skip validation List groupScopes = condition.getGroupScopes(); if (groupScopes != null && !groupScopes.isEmpty()) { - processScope(resourceName, ProtectionScope.GROUP, groupScopes); + processScope(resourceName, ProtectionScopeType.GROUP, groupScopes); } // If no super scopes for the path then skip validation List superScopes = condition.getSuperScopes(); if (superScopes != null && !superScopes.isEmpty()) { - processScope(resourceName, ProtectionScope.SUPER, superScopes); + processScope(resourceName, ProtectionScopeType.SUPER, superScopes); } log.debug("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, scopeList:{}", resourceName, @@ -114,8 +114,8 @@ private void createScopeIfNeeded(String apiProtectionType) { } } - private void processScope(String resourceName, ProtectionScope scopeType, List scopeList){ - log.debug("ApiProtectionService:::processScope() - resourceName:{}, scopeType:{}, scopeList:{}", resourceName, scopeType, scopeList); + private void processScope(String resourceName, ProtectionScopeType protectionScopeType, List scopeList){ + log.debug("ApiProtectionService:::processScope() - resourceName:{}, protectionScopeType:{}, scopeList:{}", resourceName, protectionScopeType, scopeList); //return if no scopes if(scopeList==null || scopeList.isEmpty()) { @@ -131,13 +131,14 @@ private void processScope(String resourceName, ProtectionScope scopeType, List scopes = validateScope(rsScope); - ApiProtectionCache.putResourceScopeByType(resourceName, scopeType.toString().toUpperCase(), scopes); + List scopes = validateScope(resourceName, protectionScopeType, rsScope); + ApiProtectionCache.putResource(resourceName, scopes); + ApiProtectionCache.putResourceScopeByType(resourceName, protectionScopeType, scopes); } } - private List validateScope(io.jans.configapi.core.protect.Scope rsScope) { - log.debug("Verify Scope in DB - {} ", rsScope); + private List validateScope(String resourceName, ProtectionScopeType protectionScopeType, io.jans.configapi.core.protect.Scope rsScope) { + log.debug("Verify Scope in DB - protectionScopeType:{}, rsScope:{} ", protectionScopeType, rsScope); List scopeList = new ArrayList<>(); // Check in DB @@ -185,7 +186,7 @@ private List validateScope(io.jans.configapi.core.protect.Scope rsScope) // Add to scope if not null if (scope != null) { scopeList.add(scope); - ApiProtectionCache.putScope(scope); + ApiProtectionCache.addScope(resourceName, protectionScopeType, scope); } return scopeList; } @@ -245,7 +246,7 @@ private List getAllScopes() { List scopes = new ArrayList<>(); // Verify in cache - Map scopeMap = ApiProtectionCache.getAllScopes(); + Map scopeMap = ApiProtectionCache.getAllTypesOfScopes(); Set keys = scopeMap.keySet(); for (String id : keys) { diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java index 983191349ec..04e0d7998dc 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java @@ -14,7 +14,7 @@ import io.jans.configapi.security.client.AuthClientFactory; import io.jans.configapi.configuration.ConfigurationFactory; import io.jans.configapi.core.rest.ProtectedApi; -import io.jans.configapi.core.util.ProtectionScope; +import io.jans.configapi.core.util.ProtectionScopeType; import io.jans.configapi.service.auth.ConfigurationService; import io.jans.configapi.service.auth.ClientService; import io.jans.configapi.service.auth.ScopeService; @@ -184,7 +184,7 @@ public List getRequestedScopes(ResourceInfo resourceInfo) { return scopes; } - public Map> getResourceScopes(ResourceInfo resourceInfo, ProtectionScope protectionScope) { + public Map> getResourceScopes(ResourceInfo resourceInfo, ProtectionScopeType protectionScope) { log.trace("Requested scopes for resourceInfo:{} ", resourceInfo); Class resourceClass = resourceInfo.getResourceClass(); ProtectedApi typeAnnotation = resourceClass.getAnnotation(ProtectedApi.class); @@ -204,7 +204,7 @@ public boolean validateScope(List authScopes, List resourceScope } private void addMethodScopes(ResourceInfo resourceInfo, HashMap> scopeMap, - ProtectionScope protectionScope) { + ProtectionScopeType protectionScope) { log.debug("Adding scopes for resourceInfo:{} for protectionScope:{} in scopeMap:{} ", resourceInfo, protectionScope, scopeMap); Method resourceMethod = resourceInfo.getResourceMethod(); @@ -214,14 +214,14 @@ private void addMethodScopes(ResourceInfo resourceInfo, HashMap(); } if (protectionScope != null) { - if (ProtectionScope.SCOPE.equals(protectionScope)) { - scopeMap.put(ProtectionScope.SCOPE.name(), + if (ProtectionScopeType.SCOPE.equals(protectionScope)) { + scopeMap.put(ProtectionScopeType.SCOPE.name(), Stream.of(methodAnnotation.scopes()).collect(Collectors.toList())); - } else if (ProtectionScope.GROUP.equals(protectionScope)) { - scopeMap.put(ProtectionScope.GROUP.name(), + } else if (ProtectionScopeType.GROUP.equals(protectionScope)) { + scopeMap.put(ProtectionScopeType.GROUP.name(), Stream.of(methodAnnotation.groupScopes()).collect(Collectors.toList())); } else { - scopeMap.put(ProtectionScope.SUPER.name(), + scopeMap.put(ProtectionScopeType.SUPER.name(), Stream.of(methodAnnotation.superScopes()).collect(Collectors.toList())); } } else { @@ -303,7 +303,7 @@ public List getAllScopes() { List scopes = new ArrayList<>(); // Verify in cache - Map scopeMap = ApiProtectionCache.getAllScopes(); + Map scopeMap = ApiProtectionCache.getAllTypesOfScopes(); Set keys = scopeMap.keySet(); for (String id : keys) { diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScope.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScope.java deleted file mode 100644 index 467e097d819..00000000000 --- a/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScope.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. - * - * Copyright (c) 2020, Janssen Project - */ - -package io.jans.configapi.core.util; - -public enum ProtectionScope { - SCOPE, GROUP, SUPER; - - String getValue() { - return toString().toLowerCase(); - } -} diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScopeType.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScopeType.java new file mode 100644 index 00000000000..8c942c7154f --- /dev/null +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScopeType.java @@ -0,0 +1,37 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.configapi.core.util; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import org.apache.commons.lang.StringUtils; + +public enum ProtectionScopeType { + SCOPE, GROUP, SUPER; + + String getValue() { + return toString().toLowerCase(); + } + + @JsonCreator + public static ProtectionScopeType fromString(String scopeType) { + if (StringUtils.isNotBlank(scopeType)) { + for (ProtectionScopeType type : ProtectionScopeType.values()) { + if (scopeType.equalsIgnoreCase(type.getValue())) { + return type; + } + } + } + return null; + } + + @Override + @JsonValue + public String toString() { + return getValue(); + } +} From a1453181493ae91db3463b73dbec114fe52e9985 Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Wed, 23 Nov 2022 21:46:18 +0530 Subject: [PATCH 18/28] feat(config-api): scope enhancements --- .../docs/jans-config-api-swagger-auto.yaml | 30 +-- .../security/api/ApiProtectionCache.java | 16 +- .../security/api/ApiProtectionService.java | 96 +++++----- .../service/AuthorizationService.java | 10 +- .../service/OpenIdAuthorizationService.java | 60 +++++- .../configapi/service/auth/ScopeService.java | 3 +- .../java/io/jans/configapi/util/AuthUtil.java | 173 ++++++++++++------ 7 files changed, 250 insertions(+), 138 deletions(-) diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index fd4a56b7ce6..1bb054ef451 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7180,17 +7180,17 @@ components: type: string whitePagesCanView: type: boolean - adminCanView: - type: boolean - adminCanEdit: + userCanView: type: boolean userCanEdit: type: boolean + adminCanEdit: + type: boolean userCanAccess: type: boolean adminCanAccess: type: boolean - userCanView: + adminCanView: type: boolean baseDn: type: string @@ -7526,6 +7526,8 @@ components: ttl: type: integer format: int32 + displayName: + type: string tokenBindingSupported: type: boolean authenticationMethod: @@ -7539,8 +7541,6 @@ components: - tls_client_auth - self_signed_tls_client_auth - none - displayName: - type: string baseDn: type: string inum: @@ -8347,15 +8347,6 @@ components: $ref: '#/components/schemas/SsaConfiguration' fapi: type: boolean - allResponseTypesSupported: - uniqueItems: true - type: array - items: - type: string - enum: - - code - - token - - id_token enabledFeatureFlags: uniqueItems: true type: array @@ -8383,6 +8374,15 @@ components: - STAT - PAR - SSA + allResponseTypesSupported: + uniqueItems: true + type: array + items: + type: string + enum: + - code + - token + - id_token AuthenticationFilter: required: - baseDn diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java index 3fbfc5f6ed8..088aeb35f07 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java @@ -36,8 +36,9 @@ public class ApiProtectionCache { private static final Cache>> resourceScopeCache = CacheBuilder .newBuilder().expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); - - ApiProtectionCache(){} + + ApiProtectionCache() { + } // Scope public static void removeAllScopes() { @@ -115,17 +116,9 @@ public static Map getAllTypesOfScopes() { scopes.putAll(Maps.newHashMap(superScopeCache.asMap())); return scopes; } - - public static Map getAllScopesMap() { - Map scopes = Maps.newHashMap(scopeCache.asMap()); - scopes.putAll(Maps.newHashMap(groupScopeCache.asMap())); - scopes.putAll(Maps.newHashMap(superScopeCache.asMap())); - return scopes; - } - // Resource - public static void removeAllResources() { + public static void raemoveAllResources() { resourceCache.invalidateAll(); } @@ -147,7 +140,6 @@ public static Map> getAllResources() { } // ResourceScopeCache - public static void putResource(String resourceName, Map> scopeMap) { Preconditions.checkNotNull(resourceName); resourceScopeCache.put(resourceName, scopeMap); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java index 63619fe49c1..9be8e363608 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java @@ -22,7 +22,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.UUID; import java.util.stream.Collectors; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -69,8 +68,10 @@ public void verifyResources(String apiProtectionType, String clientId) throws IO Preconditions.checkNotNull(rsResourceList, "Config Api Resource list cannot be null !!!"); createScopeIfNeeded(apiProtectionType); - log.trace("ApiProtectionService:::verifyResources() - getAllTypesOfScopes:{}, allResources:{}, getAllResourcesMap:{} ", - ApiProtectionCache.getAllTypesOfScopes(), ApiProtectionCache.getAllResources(), ApiProtectionCache.getAllResourcesMap()); + log.trace( + "ApiProtectionService:::verifyResources() - getAllTypesOfScopes:{}, allResources:{}, getAllResourcesMap:{} ", + ApiProtectionCache.getAllTypesOfScopes(), ApiProtectionCache.getAllResources(), + ApiProtectionCache.getAllResourcesMap()); updateScopeForClientIfNeeded(clientId); @@ -79,14 +80,14 @@ public void verifyResources(String apiProtectionType, String clientId) throws IO private void createScopeIfNeeded(String apiProtectionType) { log.debug("ApiProtectionService:::createScopeIfNeeded() - apiProtectionType:{}", apiProtectionType); - List scopeList = new ArrayList<>(); for (RsResource rsResource : rsResourceList) { for (Condition condition : rsResource.getConditions()) { String resourceName = condition.getHttpMethods() + ":::" + rsResource.getPath(); - - log.trace("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, condition.getScopes():{}, condition.getGroupScopes():{}, condition.getSuperScopes():{}", resourceName, - condition.getScopes(), condition.getGroupScopes(), condition.getSuperScopes()); + + log.trace( + "ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, condition.getScopes():{}, condition.getGroupScopes():{}, condition.getSuperScopes():{}", + resourceName, condition.getScopes(), condition.getGroupScopes(), condition.getSuperScopes()); // Process Scopes // If no scopes for the path then skip validation @@ -94,53 +95,56 @@ private void createScopeIfNeeded(String apiProtectionType) { if (rsScopes != null && !rsScopes.isEmpty()) { processScope(resourceName, ProtectionScopeType.SCOPE, rsScopes); } - + // If no group scopes for the path then skip validation - List groupScopes = condition.getGroupScopes(); + List groupScopes = condition.getGroupScopes(); if (groupScopes != null && !groupScopes.isEmpty()) { processScope(resourceName, ProtectionScopeType.GROUP, groupScopes); } - + // If no super scopes for the path then skip validation List superScopes = condition.getSuperScopes(); if (superScopes != null && !superScopes.isEmpty()) { processScope(resourceName, ProtectionScopeType.SUPER, superScopes); } - + log.debug("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, scopeList:{}", resourceName, scopeList); } // condition } } - - private void processScope(String resourceName, ProtectionScopeType protectionScopeType, List scopeList){ - log.debug("ApiProtectionService:::processScope() - resourceName:{}, protectionScopeType:{}, scopeList:{}", resourceName, protectionScopeType, scopeList); - - //return if no scopes - if(scopeList==null || scopeList.isEmpty()) { + + private void processScope(String resourceName, ProtectionScopeType protectionScopeType, + List scopeList) { + log.debug("ApiProtectionService:::processScope() - resourceName:{}, protectionScopeType:{}, scopeList:{}", + resourceName, protectionScopeType, scopeList); + + // return if no scopes + if (scopeList == null || scopeList.isEmpty()) { return; } - - for(io.jans.configapi.core.protect.Scope rsScope : scopeList) { + + for (io.jans.configapi.core.protect.Scope rsScope : scopeList) { String inum = rsScope.getInum(); - String scopeName = rsScope.getInum(); - - //return if no scope details - if(StringUtils.isBlank(inum) || StringUtils.isBlank(scopeName)){ + String scopeName = rsScope.getInum(); + + // return if no scope details + if (StringUtils.isBlank(inum) || StringUtils.isBlank(scopeName)) { return; - } - + } + List scopes = validateScope(resourceName, protectionScopeType, rsScope); ApiProtectionCache.putResource(resourceName, scopes); ApiProtectionCache.putResourceScopeByType(resourceName, protectionScopeType, scopes); } } - private List validateScope(String resourceName, ProtectionScopeType protectionScopeType, io.jans.configapi.core.protect.Scope rsScope) { + private List validateScope(String resourceName, ProtectionScopeType protectionScopeType, + io.jans.configapi.core.protect.Scope rsScope) { log.debug("Verify Scope in DB - protectionScopeType:{}, rsScope:{} ", protectionScopeType, rsScope); List scopeList = new ArrayList<>(); - + // Check in DB Scope scope = scopeService.getScope(rsScope.getInum()); log.debug("Scopes from DB - {}'", scope); @@ -152,35 +156,37 @@ private List validateScope(String resourceName, ProtectionScopeType prote } ScopeType scopeType = ScopeType.OAUTH; - log.trace("Scope details - scope:{}, rsScope.getName():{}, exclusiveAuthScopes:{}, isConfigApiScope(scopeName):{} '", + log.trace( + "Scope details - scope:{}, rsScope.getName():{}, exclusiveAuthScopes:{}, isConfigApiScope(scopeName):{} '", scope, rsScope.getName(), configurationFactory.getApiAppConfiguration().getExclusiveAuthScopes(), isConfigApiScope(rsScope.getName())); // Create/Update scope only if they are config-api-resource scopes if (isConfigApiScope(rsScope.getName())) { - //ensure scope does not exists + // ensure scope does not exists scope = scopeService.getScope(rsScope.getInum()); - log.debug("Re-verify ConfigApiScope rsScope.getName():{} with rsScope.getInum():{} in DB - scope:{} ", rsScope.getName(), rsScope.getInum(), scope); + log.debug("Re-verify ConfigApiScope rsScope.getName():{} with rsScope.getInum():{} in DB - scope:{} ", + rsScope.getName(), rsScope.getInum(), scope); if (scope == null) { - log.debug("Scope - '{}' does not exist, hence creating it.", scope); - // Scope does not exists hence create Scope - scope = new Scope(); - String inum = rsScope.getInum(); - scope.setId(rsScope.getName()); - scope.setDisplayName(rsScope.getName()); - scope.setInum(inum); - scope.setDn(scopeService.getDnForScope(inum)); - scope.setScopeType(scopeType); - scopeService.addScope(scope); - } - if (scope != null) { - // Update resource - log.debug("Scope - '{}' already exists, hence updating it.", rsScope.getName()); + log.debug("Scope - '{}' does not exist, hence creating it.", scope); + // Scope does not exists hence create Scope + scope = new Scope(); + String inum = rsScope.getInum(); scope.setId(rsScope.getName()); + scope.setDisplayName(rsScope.getName()); + scope.setInum(inum); + scope.setDn(scopeService.getDnForScope(inum)); scope.setScopeType(scopeType); - scopeService.updateScope(scope); + scopeService.addScope(scope); } + + // Update resource + log.debug("Scope - '{}' already exists, hence updating it.", rsScope.getName()); + scope.setId(rsScope.getName()); + scope.setScopeType(scopeType); + scopeService.updateScope(scope); + } // Add to scope if not null diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java index cc01f78ce1c..a354fac37fd 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java @@ -7,7 +7,10 @@ package io.jans.configapi.security.service; import io.jans.configapi.util.AuthUtil; +import io.jans.as.persistence.model.Scope; import io.jans.configapi.configuration.ConfigurationFactory; +import io.jans.configapi.core.util.ProtectionScopeType; + import org.slf4j.Logger; import jakarta.inject.Inject; @@ -15,6 +18,7 @@ import jakarta.ws.rs.container.ResourceInfo; import java.io.Serializable; import java.util.List; +import java.util.Map; public abstract class AuthorizationService implements Serializable { @@ -40,13 +44,17 @@ public List getRequestedScopes(String path) { return authUtil.getRequestedScopes(path); } - public List getRequestedScopes(ResourceInfo resourceInfo) { + public Map> getRequestedScopes(ResourceInfo resourceInfo) { return authUtil.getRequestedScopes(resourceInfo); } public boolean validateScope(List authScopes, List resourceScopes) { return authUtil.validateScope(authScopes, resourceScopes); } + + public List getAllScopeList(Map> scopeMap) { + return authUtil.getAllScopeList(scopeMap); + } public List getApiApprovedIssuer() { return this.configurationFactory.getApiApprovedIssuer(); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java index fca7abdd1a2..a622436b4b7 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java @@ -8,6 +8,7 @@ import io.jans.as.model.exception.InvalidJwtException; import io.jans.configapi.core.util.Jackson; +import io.jans.configapi.core.util.ProtectionScopeType; import io.jans.configapi.util.*; import io.jans.as.model.common.IntrospectionResponse; @@ -23,6 +24,7 @@ import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.Response; import java.io.Serializable; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -118,19 +120,22 @@ public String processAuthorization(String token, String issuer, ResourceInfo res private String validateScope(String accessToken, List tokenScopes, ResourceInfo resourceInfo, String issuer) throws WebApplicationException { - logger.debug("Validate scope, accessToken:{}, tokenScopes:{}, resourceInfo: {}, issuer: {}", accessToken, + logger.error("Validate scope, accessToken:{}, tokenScopes:{}, resourceInfo: {}, issuer: {}", accessToken, tokenScopes, resourceInfo, issuer); try { // Get resource scope - List resourceScopes = getRequestedScopes(resourceInfo); + Map> resourceScopesByType = getRequestedScopes(resourceInfo); + List resourceScopes = getAllScopeList(resourceScopesByType); + logger.error("Validate scope, accessresourceScopesByType: {}, resourceScopes: {}", resourceScopesByType, + resourceScopes); // Check if resource requires auth server specific scope List authSpecificScope = getAuthSpecificScopeRequired(resourceInfo); - logger.debug(" resourceScopes:{}, authSpecificScope:{} ", resourceScopes, authSpecificScope); + logger.error(" resourceScopes:{}, authSpecificScope:{} ", resourceScopes, authSpecificScope); // If No auth scope required OR if token contains the authSpecificScope if ((authSpecificScope == null || authSpecificScope.isEmpty())) { - logger.debug("Validating token scopes as no authSpecificScope required"); + logger.error("Validating token scopes as no authSpecificScope required"); if (!validateScope(tokenScopes, resourceScopes)) { logger.error("Insufficient scopes! Required scope:{} - however token scopes:{}", resourceScopes, tokenScopes); @@ -142,8 +147,8 @@ private String validateScope(String accessToken, List tokenScopes, Resou } // find missing scopes - List missingScopes = findMissingElements(resourceScopes, tokenScopes); - logger.debug("missingScopes:{}", missingScopes); + List missingScopes = findMissingScopes(resourceScopesByType, tokenScopes); + logger.error("missingScopes:{}", missingScopes); // If only authSpecificScope missing then proceed with token creation else throw // error @@ -159,7 +164,7 @@ private String validateScope(String accessToken, List tokenScopes, Resou // Generate token with required resourceScopes resourceScopes.addAll(authSpecificScope); accessToken = openIdService.requestAccessToken(authUtil.getClientId(), resourceScopes); - logger.debug("Introspecting new accessToken:{}", accessToken); + logger.error("Introspecting new accessToken:{}", accessToken); // Introspect IntrospectionResponse introspectionResponse = openIdService @@ -200,4 +205,45 @@ private boolean externalAuthorization(String token, String issuer, String method this.configurationFactory.getApiAppConfiguration(), requestParameters, responseAsJsonObject); } + private List findMissingScopes(Map> scopeMap, List tokenScopes) { + logger.error("Check scopeMap:{}, tokenScopes:{}", scopeMap, tokenScopes); + List scopeList = new ArrayList<>(); + if (tokenScopes == null || tokenScopes.isEmpty() || scopeMap == null || scopeMap.isEmpty()) { + return scopeList; + } + + for (Map.Entry> entry : scopeMap.entrySet()) { + log.error("Get all entry.getKey():{}, entry.getValue():{} ", entry.getKey(), entry.getValue()); + } + + // Super scope + scopeList = scopeMap.get(ProtectionScopeType.SUPER); + // find missing scopes + List missingScopes = findMissingElements(scopeList, tokenScopes); + logger.error("SUPER Missing Scopes:{}", missingScopes); + + // If + if (missingScopes == null || missingScopes.isEmpty()) { + return missingScopes; + } + + // Group scope + scopeList = scopeMap.get(ProtectionScopeType.GROUP); + // find missing scopes + missingScopes = findMissingElements(scopeList, tokenScopes); + logger.error("GROUP Missing Scopes:{}", missingScopes); + + if (missingScopes == null || missingScopes.isEmpty()) { + return missingScopes; + } + + // Normal scope + scopeList = scopeMap.get(ProtectionScopeType.SCOPE); + // find missing scopes + missingScopes = findMissingElements(scopeList, tokenScopes); + logger.error("SCOPE Missing Scopes:{}", missingScopes); + return missingScopes; + + } + } \ No newline at end of file diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java index 991bc1c1257..720a098ecba 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java @@ -24,7 +24,6 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import org.apache.commons.lang.StringUtils; -import org.python.jline.internal.Log; import org.slf4j.Logger; import java.util.ArrayList; @@ -93,7 +92,7 @@ public Scope getScope(String inum) { try { return persistenceEntryManager.find(Scope.class, getDnForScope(inum)); } catch (Exception ex) { - Log.error("Error while finding scope is : {}", ex); + logger.error("Error while finding scope with inum:{} is:{}", inum, ex); } return null; } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java index 04e0d7998dc..0d1bbcac12c 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java @@ -23,18 +23,19 @@ import java.lang.reflect.Method; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.HashSet; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; - import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; +import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.container.ResourceInfo; +import jakarta.ws.rs.core.Response; import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; @@ -153,6 +154,58 @@ public String encryptPassword(String clientPassword) { return encryptedPassword; } + public List getResourceScopeList(String method, String path) { + log.trace(" ResourceScopeList requested for method:{}, path:{}", method, path); + + // Verify in cache + Map> resources = ApiProtectionCache.getAllResources(); + + // Filter paths based on resource name + Set keys = resources.keySet(); + List filteredPaths = keys.stream().filter(k -> k.contains(path)).collect(Collectors.toList()); + + if (filteredPaths == null || filteredPaths.isEmpty()) { + throw new WebApplicationException("No matching resource found .", + Response.status(Response.Status.UNAUTHORIZED).build()); + } + + List scopeList = null; + for (String key : filteredPaths) { + String[] result = key.split(":::"); + if (result != null && result.length > 1) { + String httpmethod = result[0]; + String pathUrl = result[1]; + log.trace(" Resource Scopes - httpmethod:{} , pathUrl:{} ", httpmethod, pathUrl); + + if (pathUrl != null && pathUrl.contains(path)) { + // Matching url + log.trace(" Matching url with path:{} , pathUrl:{} ", path, pathUrl); + + // Verify Method + if (httpmethod.contains(method)) { + scopeList = ApiProtectionCache.getResourceScopes(key); + log.trace(" scopeList:{} for the method:{} ", scopeList, method); + break; + } + } + } + } + return scopeList; + } + + public List getAllResourceScopes() { + Map scopeMap = ApiProtectionCache.getAllTypesOfScopes(); + log.trace("All Resource Scopes - scopeMap:{}", scopeMap); + + List scopeStrList = null; + if (scopeMap != null && !scopeMap.isEmpty()) { + Set scopeSet = scopeMap.keySet(); + scopeStrList = new ArrayList<>(scopeSet); + } + log.trace("All Resource Scopes - scopeStrList:{} ", scopeStrList); + return scopeStrList; + } + public List getRequestedScopes(String path) { List scopeList = ApiProtectionCache.getResourceScopes(path); log.trace("Requested scopes:{} for path:{} ", scopeList, path); @@ -167,73 +220,65 @@ public List getRequestedScopes(String path) { return scopeStrList; } - public List getRequestedScopes(ResourceInfo resourceInfo) { - log.trace("Requested scopes for resourceInfo:{} ", resourceInfo); - Class resourceClass = resourceInfo.getResourceClass(); - ProtectedApi typeAnnotation = resourceClass.getAnnotation(ProtectedApi.class); - List scopes = new ArrayList<>(); - if (typeAnnotation != null) { - HashMap> scopeMap = new HashMap<>(); - addMethodScopes(resourceInfo, scopeMap, null); - for (Map.Entry> entry : scopeMap.entrySet()) { - scopes.addAll(entry.getValue()); - + public List getRequestedScopes(String method, String path) { + log.trace("Requested scopes for path:{} and method:{} ", path, method); + List scopeList = this.getResourceScopeList(method, path); + log.trace("Requested scopeList:{} for path:{} and method:{} ", scopeList, path, method); + List scopeStrList = new ArrayList<>(); + if (scopeList != null && !scopeList.isEmpty()) { + for (Scope s : scopeList) { + scopeStrList.add(s.getId()); } } - log.trace("Requested resourceInfo:{} for scope:{} ", resourceInfo, scopes); - return scopes; + log.trace("Final scopeStrList:{} for path:{} and method:{} ", scopeStrList, path, method); + return scopeStrList; } - public Map> getResourceScopes(ResourceInfo resourceInfo, ProtectionScopeType protectionScope) { - log.trace("Requested scopes for resourceInfo:{} ", resourceInfo); + public Map> getRequestedScopes(ResourceInfo resourceInfo) { + log.error("Requested scopes for resourceInfo:{} ", resourceInfo); Class resourceClass = resourceInfo.getResourceClass(); ProtectedApi typeAnnotation = resourceClass.getAnnotation(ProtectedApi.class); - HashMap> scopeMap = new HashMap<>(); + Map> scopes = new HashMap<>(); + log.error("Requested scopes for resourceClass:{}, typeAnnotation:{} ", resourceClass, typeAnnotation); if (typeAnnotation == null) { - addMethodScopes(resourceInfo, scopeMap, protectionScope); + log.error("Requested scopes for resourceClass:{}, typeAnnotation == null ", resourceClass); + addMethodScopes(resourceInfo, scopes); + } else { + log.error("Requested scopes for resourceClass:{}, typeAnnotation is not null ", resourceClass); + scopes.put(ProtectionScopeType.SCOPE, Stream.of(typeAnnotation.scopes()).collect(Collectors.toList())); + scopes.put(ProtectionScopeType.GROUP, Stream.of(typeAnnotation.groupScopes()).collect(Collectors.toList())); + scopes.put(ProtectionScopeType.SUPER, Stream.of(typeAnnotation.superScopes()).collect(Collectors.toList())); + log.error("ProtectionScopeType.SCOPE:{} ", Stream.of(typeAnnotation.scopes()).collect(Collectors.toList())); + log.error("ProtectionScopeType.GROUP:{} ", + Stream.of(typeAnnotation.groupScopes()).collect(Collectors.toList())); + log.error("ProtectionScopeType.SUPER:{} ", + Stream.of(typeAnnotation.superScopes()).collect(Collectors.toList())); + log.error("All scopes:{} ", scopes); + addMethodScopes(resourceInfo, scopes); } - log.trace("Requested scopes:{} for resourceInfo:{} of type protectionScope:{} ", scopeMap, resourceInfo, - protectionScope); - return scopeMap; + log.trace("Requested scopes:{} for resourceInfo:{} ", scopes, resourceInfo); + return scopes; } public boolean validateScope(List authScopes, List resourceScopes) { + log.error("Validate Scopes for authScopes:{}, resourceScopes:{} ", authScopes, resourceScopes); Set authScopeSet = new HashSet<>(authScopes); Set resourceScopeSet = new HashSet<>(resourceScopes); return authScopeSet.containsAll(resourceScopeSet); } - private void addMethodScopes(ResourceInfo resourceInfo, HashMap> scopeMap, - ProtectionScopeType protectionScope) { - log.debug("Adding scopes for resourceInfo:{} for protectionScope:{} in scopeMap:{} ", resourceInfo, - protectionScope, scopeMap); + private void addMethodScopes(ResourceInfo resourceInfo, Map> scopes) { + log.error("Method Scopes for resourceInfo:{}, scopes:{} ", resourceInfo, scopes); Method resourceMethod = resourceInfo.getResourceMethod(); ProtectedApi methodAnnotation = resourceMethod.getAnnotation(ProtectedApi.class); if (methodAnnotation != null) { - if (scopeMap == null) { - scopeMap = new HashMap<>(); - } - if (protectionScope != null) { - if (ProtectionScopeType.SCOPE.equals(protectionScope)) { - scopeMap.put(ProtectionScopeType.SCOPE.name(), - Stream.of(methodAnnotation.scopes()).collect(Collectors.toList())); - } else if (ProtectionScopeType.GROUP.equals(protectionScope)) { - scopeMap.put(ProtectionScopeType.GROUP.name(), - Stream.of(methodAnnotation.groupScopes()).collect(Collectors.toList())); - } else { - scopeMap.put(ProtectionScopeType.SUPER.name(), - Stream.of(methodAnnotation.superScopes()).collect(Collectors.toList())); - } - } else { - List scopes = new ArrayList<>(); - scopes.addAll(Stream.of(methodAnnotation.scopes()).collect(Collectors.toList())); - scopes.addAll(Stream.of(methodAnnotation.groupScopes()).collect(Collectors.toList())); - scopes.addAll(Stream.of(methodAnnotation.superScopes()).collect(Collectors.toList())); - scopeMap.put("ALL", scopes); - } + scopes.put(ProtectionScopeType.SCOPE, Stream.of(methodAnnotation.scopes()).collect(Collectors.toList())); + scopes.put(ProtectionScopeType.GROUP, + Stream.of(methodAnnotation.groupScopes()).collect(Collectors.toList())); + scopes.put(ProtectionScopeType.SUPER, + Stream.of(methodAnnotation.superScopes()).collect(Collectors.toList())); } - log.debug("Added scopes for resourceInfo:{} for protectionScope:{} in scopeMap:{} ", resourceInfo, - protectionScope, scopeMap); + log.error("Final Method Scopes for resourceInfo:{}, scopes:{} ", resourceInfo, scopes); } public String requestAccessToken(final String clientId, final List scope) { @@ -343,11 +388,11 @@ public boolean isValidIssuer(String issuer) { } public List getAuthSpecificScopeRequired(ResourceInfo resourceInfo) { - log.debug("Fetch Auth server specific scope for resourceInfo:{} ", resourceInfo); + log.error("Fetch Auth server specific scope for resourceInfo:{} ", resourceInfo); // Get required oauth scopes for the endpoint - List resourceScopes = getRequestedScopes(resourceInfo); - log.debug(" resource:{} has these scopes:{} and configured exclusiveAuthScopes are {}", resourceInfo, + List resourceScopes = getAllScopeList(getRequestedScopes(resourceInfo)); + log.error(" resource:{} has these scopes:{} and configured exclusiveAuthScopes are {}", resourceInfo, resourceScopes, this.configurationFactory.getApiAppConfiguration().getExclusiveAuthScopes()); // Check if the path has any exclusiveAuthScopes requirement @@ -360,7 +405,7 @@ public List getAuthSpecificScopeRequired(ResourceInfo resourceInfo) { .collect(Collectors.toList()); } - log.debug("Applicable exclusiveAuthScopes for resourceInfo:{} are {} ", resourceInfo, exclusiveAuthScopesToReq); + log.error("Applicable exclusiveAuthScopes for resourceInfo:{} are {} ", resourceInfo, exclusiveAuthScopesToReq); return exclusiveAuthScopesToReq; } @@ -407,17 +452,33 @@ public boolean isValidDn(String dn, boolean strictNameChecking) { } public RevokeSessionResponse revokeSession(final String url, final String token, final String userId) { - log.debug("Revoke session Request - url:{}, token:{}, userId:{}", url, token, userId); + log.error("Revoke session Request - url:{}, token:{}, userId:{}", url, token, userId); RevokeSessionResponse revokeSessionResponse = AuthClientFactory.revokeSession(url, token, userId); - log.debug("revokeSessionResponse:{}", revokeSessionResponse); + log.error("revokeSessionResponse:{}", revokeSessionResponse); if (revokeSessionResponse != null) { - log.debug("revokeSessionResponse.getEntity():{}, revokeSessionResponse.getStatus():{} ", + log.error("revokeSessionResponse.getEntity():{}, revokeSessionResponse.getStatus():{} ", revokeSessionResponse.getEntity(), revokeSessionResponse.getStatus()); } return revokeSessionResponse; } + public List getAllScopeList(Map> scopeMap) { + List scopeList = new ArrayList<>(); + log.error("Get all scopeMap:{} ", scopeMap); + if (scopeMap == null || scopeMap.isEmpty()) { + return scopeList; + } + + scopeMap.entrySet().stream().forEach(e -> { + log.debug("scopeMap data key:{}, value:{} ", e.getKey(), e.getValue()); + scopeList.retainAll(e.getValue()); + }); + log.error("Get all scopeList:{} ", scopeList); + return scopeList; + + } + } From 2b446ffca101da8eed219ab20adc9edc0bdfe5f1 Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Thu, 24 Nov 2022 22:17:12 +0530 Subject: [PATCH 19/28] feat(config-api): scope enhancement --- .../docs/jans-config-api-swagger-auto.yaml | 25 ++++++------------- .../profiles/local/test.properties | 8 +++--- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index 1bb054ef451..726c69b26ae 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7178,20 +7178,20 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - whitePagesCanView: - type: boolean - userCanView: - type: boolean - userCanEdit: - type: boolean adminCanEdit: type: boolean - userCanAccess: + userCanEdit: type: boolean adminCanAccess: type: boolean adminCanView: type: boolean + userCanView: + type: boolean + userCanAccess: + type: boolean + whitePagesCanView: + type: boolean baseDn: type: string PatchRequest: @@ -7526,10 +7526,6 @@ components: ttl: type: integer format: int32 - displayName: - type: string - tokenBindingSupported: - type: boolean authenticationMethod: type: string enum: @@ -7646,13 +7642,6 @@ components: type: object additionalProperties: type: string - value: - type: string - languageTags: - uniqueItems: true - type: array - items: - type: string AppConfiguration: type: object properties: diff --git a/jans-config-api/profiles/local/test.properties b/jans-config-api/profiles/local/test.properties index e862359e7bc..af088ce1080 100644 --- a/jans-config-api/profiles/local/test.properties +++ b/jans-config-api/profiles/local/test.properties @@ -2,8 +2,8 @@ test.scopes=https://jans.io/oauth/config/acrs.readonly https://jans.io/oauth/config/acrs.write https://jans.io/oauth/config/attributes.readonly https://jans.io/oauth/config/attributes.write https://jans.io/oauth/config/attributes.delete https://jans.io/oauth/config/cache.readonly https://jans.io/oauth/config/cache.write https://jans.io/oauth/config/openid/clients.readonly https://jans.io/oauth/config/openid/clients.write https://jans.io/oauth/config/openid/clients.delete https://jans.io/oauth/jans-auth-server/config/properties.readonly https://jans.io/oauth/jans-auth-server/config/properties.write https://jans.io/oauth/config/smtp.readonly https://jans.io/oauth/config/smtp.write https://jans.io/oauth/config/smtp.delete https://jans.io/oauth/config/scripts.readonly https://jans.io/oauth/config/scripts.write https://jans.io/oauth/config/scripts.delete https://jans.io/oauth/config/fido2.readonly https://jans.io/oauth/config/fido2.write https://jans.io/oauth/config/jwks.readonly https://jans.io/oauth/config/jwks.write https://jans.io/oauth/config/jwks.delete https://jans.io/oauth/config/database/ldap.readonly https://jans.io/oauth/config/database/ldap.write https://jans.io/oauth/config/database/ldap.delete https://jans.io/oauth/config/logging.readonly https://jans.io/oauth/config/logging.write https://jans.io/oauth/config/scopes.readonly https://jans.io/oauth/config/scopes.write https://jans.io/oauth/config/scopes.delete https://jans.io/oauth/config/uma/resources.readonly https://jans.io/oauth/config/uma/resources.write https://jans.io/oauth/config/uma/resources.delete https://jans.io/oauth/config/database/sql.readonly https://jans.io/oauth/config/database/sql.write https://jans.io/oauth/config/database/sql.delete https://jans.io/oauth/config/stats.readonly jans_stat https://jans.io/scim/users.read https://jans.io/scim/users.write https://jans.io/oauth/config/scim/users.read https://jans.io/oauth/config/scim/users.write https://jans.io/scim/config.readonly https://jans.io/scim/config.write https://jans.io/oauth/config/organization.readonly https://jans.io/oauth/config/organization.write https://jans.io/oauth/config/user.readonly https://jans.io/oauth/config/user.write https://jans.io/oauth/config/user.delete https://jans.io/oauth/config/agama.readonly https://jans.io/oauth/config/agama.write https://jans.io/oauth/config/agama.delete https://jans.io/oauth/jans-auth-server/session.readonly https://jans.io/oauth/jans-auth-server/session.delete revoke_session # jans.server -token.endpoint=https://jans.server2/jans-auth/restv1/token +token.endpoint=https://jans.server1/jans-auth/restv1/token token.grant.type=client_credentials -test.client.id=1800.0a6a17a0-0d3b-4ce5-881c-f98b2f2b75a7 -test.client.secret=6n1RxN9uEC7q -test.issuer=https://jans.server2/ \ No newline at end of file +test.client.id=1800.5957dfad-b2cb-4764-85fe-841e6bc870ff +test.client.secret=ozu4fjIzoEbe +test.issuer=https://jans.server1/ \ No newline at end of file From b3e16d6441d13ae795cdca02a139c0ddfe738e8f Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Fri, 25 Nov 2022 21:13:53 +0530 Subject: [PATCH 20/28] feat(config-api): scope enhancement wip --- .../docs/jans-config-api-swagger-auto.yaml | 14 ++-- .../plugins/docs/user-mgt-plugin-swagger.yaml | 4 +- .../security/api/ApiProtectionService.java | 52 ++++++------ .../service/AuthorizationService.java | 4 +- .../java/io/jans/configapi/util/AuthUtil.java | 80 ------------------- 5 files changed, 36 insertions(+), 118 deletions(-) diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index 73d877bf0b0..35b9e1a6a48 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7180,14 +7180,14 @@ components: type: string whitePagesCanView: type: boolean - adminCanAccess: - type: boolean adminCanView: type: boolean - userCanAccess: + adminCanAccess: type: boolean adminCanEdit: type: boolean + userCanAccess: + type: boolean userCanView: type: boolean userCanEdit: @@ -8361,6 +8361,8 @@ components: - STAT - PAR - SSA + fapi: + type: boolean allResponseTypesSupported: uniqueItems: true type: array @@ -8370,8 +8372,6 @@ components: - code - token - id_token - fapi: - type: boolean AuthenticationFilter: required: - baseDn @@ -8628,13 +8628,13 @@ components: type: boolean internal: type: boolean - locationPath: - type: string locationType: type: string enum: - ldap - file + locationPath: + type: string baseDn: type: string ScriptError: diff --git a/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml b/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml index cfed2bc9a98..871aacaec5b 100644 --- a/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml +++ b/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml @@ -785,10 +785,10 @@ components: type: array items: type: object - displayValue: - type: string value: type: object + displayValue: + type: string CustomUser: type: object properties: diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java index 2929c4dd052..3e18920fda3 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java @@ -53,7 +53,7 @@ public Collection getResourceList() { } public void verifyResources(String apiProtectionType, String clientId) throws IOException { - log.error( + log.debug( "ApiProtectionService::verifyResources() - apiProtectionType:{}, clientId:{}, configurationFactory:{} ", apiProtectionType, clientId, configurationFactory); @@ -63,12 +63,12 @@ public void verifyResources(String apiProtectionType, String clientId) throws IO RsResourceList resourceList = Jackson.createJsonMapper().readValue(inputStream, RsResourceList.class); this.rsResourceList = resourceList.getResources(); - log.error("verifyResources() - rsResourceList{} ", rsResourceList); + log.debug("verifyResources() - rsResourceList{} ", rsResourceList); Preconditions.checkNotNull(rsResourceList, "Config Api Resource list cannot be null !!!"); createScopeIfNeeded(apiProtectionType); - log.error( + log.debug( "ApiProtectionService:::verifyResources() - getAllTypesOfScopes:{}, allResources:{}, getAllResourcesMap:{} ", ApiProtectionCache.getAllTypesOfScopes(), ApiProtectionCache.getAllResources(), ApiProtectionCache.getAllResourcesMap()); @@ -78,14 +78,14 @@ public void verifyResources(String apiProtectionType, String clientId) throws IO } private void createScopeIfNeeded(String apiProtectionType) { - log.error("ApiProtectionService:::createScopeIfNeeded() - apiProtectionType:{}", apiProtectionType); + log.debug("ApiProtectionService:::createScopeIfNeeded() - apiProtectionType:{}", apiProtectionType); List scopeList = new ArrayList<>(); for (RsResource rsResource : rsResourceList) { for (Condition condition : rsResource.getConditions()) { String resourceName = condition.getHttpMethods() + ":::" + rsResource.getPath(); - log.error( + log.debug( "ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, condition.getScopes():{}, condition.getGroupScopes():{}, condition.getSuperScopes():{}", resourceName, condition.getScopes(), condition.getGroupScopes(), condition.getSuperScopes()); @@ -108,7 +108,7 @@ private void createScopeIfNeeded(String apiProtectionType) { processScope(resourceName, ProtectionScopeType.SUPER, superScopes); } - log.error("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, scopeList:{}", resourceName, + log.debug("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, scopeList:{}", resourceName, scopeList); } // condition @@ -117,7 +117,7 @@ private void createScopeIfNeeded(String apiProtectionType) { private void processScope(String resourceName, ProtectionScopeType protectionScopeType, List scopeList) { - log.error("ApiProtectionService:::processScope() - resourceName:{}, protectionScopeType:{}, scopeList:{}", + log.debug("ApiProtectionService:::processScope() - resourceName:{}, protectionScopeType:{}, scopeList:{}", resourceName, protectionScopeType, scopeList); // return if no scopes @@ -128,7 +128,7 @@ private void processScope(String resourceName, ProtectionScopeType protectionSco for (io.jans.configapi.core.protect.Scope rsScope : scopeList) { String inum = rsScope.getInum(); String scopeName = rsScope.getName(); - log.error("ApiProtectionService:::processScope() - resourceName:{}, inum:{}, scopeName:{}", resourceName, + log.debug("ApiProtectionService:::processScope() - resourceName:{}, inum:{}, scopeName:{}", resourceName, inum, scopeName); // return if no scope details @@ -144,21 +144,21 @@ private void processScope(String resourceName, ProtectionScopeType protectionSco private List validateScope(String resourceName, ProtectionScopeType protectionScopeType, io.jans.configapi.core.protect.Scope rsScope) { - log.error("Verify Scope in DB - protectionScopeType:{}, rsScope:{} ", protectionScopeType, rsScope); + log.debug("Verify Scope in DB - protectionScopeType:{}, rsScope:{} ", protectionScopeType, rsScope); List scopeList = new ArrayList<>(); // Check in DB Scope scope = scopeService.getScope(rsScope.getInum()); - log.error("Scopes from DB - {}'", scope); + log.debug("Scopes from DB - {}'", scope); if (scope != null) { // Fetch existing scope to store in cache - log.error("Scope from DB scope.getInum():{}, scope.getId():{}", scope.getInum(), scope.getId()); + log.debug("Scope from DB scope.getInum():{}, scope.getId():{}", scope.getInum(), scope.getId()); scopeList.add(scope); } ScopeType scopeType = ScopeType.OAUTH; - log.error( + log.debug( "Scope details - scope:{}, rsScope.getName():{}, exclusiveAuthScopes:{}, isConfigApiScope(scopeName):{} '", scope, rsScope.getName(), configurationFactory.getApiAppConfiguration().getExclusiveAuthScopes(), isConfigApiScope(rsScope.getName())); @@ -168,10 +168,10 @@ private List validateScope(String resourceName, ProtectionScopeType prote // ensure scope does not exists scope = scopeService.getScope(rsScope.getInum()); - log.error("Re-verify ConfigApiScope rsScope.getName():{} with rsScope.getInum():{} in DB - scope:{} ", + log.debug("Re-verify ConfigApiScope rsScope.getName():{} with rsScope.getInum():{} in DB - scope:{} ", rsScope.getName(), rsScope.getInum(), scope); if (scope == null) { - log.error("Scope - '{}' does not exist, hence creating it.", scope); + log.debug("Scope - '{}' does not exist, hence creating it.", scope); // Scope does not exists hence create Scope scope = new Scope(); String inum = rsScope.getInum(); @@ -184,7 +184,7 @@ private List validateScope(String resourceName, ProtectionScopeType prote } // Update resource - log.error("Scope - '{}' already exists, hence updating it.", rsScope.getName()); + log.debug("Scope - '{}' already exists, hence updating it.", rsScope.getName()); scope.setId(rsScope.getName()); scope.setScopeType(scopeType); scopeService.updateScope(scope); @@ -205,7 +205,7 @@ private boolean isConfigApiScope(String scopeName) { } private void updateScopeForClientIfNeeded(String clientId) { - log.error(" Internal clientId:{} ", clientId); + log.debug(" Internal clientId:{} ", clientId); if (StringUtils.isBlank(clientId)) { return; @@ -213,17 +213,17 @@ private void updateScopeForClientIfNeeded(String clientId) { try { Client client = this.clientService.getClientByInum(clientId); - log.error("updateScopeForClientIfNeeded() - Verify client:{} ", client); + log.debug("updateScopeForClientIfNeeded() - Verify client:{} ", client); if (client != null) { // Assign scope // Prepare scope array List scopes = getScopeWithDn(getAllScopes()); - log.error("updateScopeForClientIfNeeded() - All scopes:{}", scopes); + log.debug("updateScopeForClientIfNeeded() - All scopes:{}", scopes); if (client.getScopes() != null) { List existingScopes = Arrays.asList(client.getScopes()); - log.error("updateScopeForClientIfNeeded() - Clients existing scopes:{} ", existingScopes); + log.debug("updateScopeForClientIfNeeded() - Clients existing scopes:{} ", existingScopes); if (scopes == null) { scopes = new ArrayList<>(); } @@ -233,19 +233,19 @@ private void updateScopeForClientIfNeeded(String clientId) { // Distinct scopes List distinctScopes = (scopes == null ? Collections.emptyList() : scopes.stream().distinct().collect(Collectors.toList())); - log.error("updateScopeForClientIfNeeded() - Distinct scopes to add:{} ", distinctScopes); + log.debug("updateScopeForClientIfNeeded() - Distinct scopes to add:{} ", distinctScopes); String[] scopeArray = this.getAllScopesArray(distinctScopes); - log.error("All Scope to assign to client:{}", Arrays.asList(scopeArray)); + log.debug("All Scope to assign to client:{}", Arrays.asList(scopeArray)); client.setScopes(scopeArray); this.clientService.updateClient(client); } client = this.clientService.getClientByInum(clientId); - log.error(" Verify scopes post assignment, clientId:{}, scopes:{}", clientId, + log.debug(" Verify scopes post assignment, clientId:{}, scopes:{}", clientId, Arrays.asList(client.getScopes())); } catch (Exception ex) { - log.error("Error while searching internal client", ex); + log.debug("Error while searching internal client", ex); } } @@ -256,14 +256,14 @@ private List getAllScopes() { // Verify in cache Map scopeMap = ApiProtectionCache.getAllTypesOfScopes(); Set keys = scopeMap.keySet(); - log.error(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); + log.debug(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); for (String id : keys) { Scope scope = scopeMap.get(id); - log.error(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); + log.debug(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); scopes.add(scope.getInum()); } - log.error(" All Scopes being returned scopes:{}", scopes); + log.debug(" All Scopes being returned scopes:{}", scopes); return scopes; } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java index a354fac37fd..d9681ee1d61 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java @@ -40,9 +40,7 @@ protected Response getErrorResponse(Response.Status status, String detail) { return Response.status(status).entity(detail).build(); } - public List getRequestedScopes(String path) { - return authUtil.getRequestedScopes(path); - } + public Map> getRequestedScopes(ResourceInfo resourceInfo) { return authUtil.getRequestedScopes(resourceInfo); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java index 0d1bbcac12c..b0029d25615 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java @@ -154,86 +154,6 @@ public String encryptPassword(String clientPassword) { return encryptedPassword; } - public List getResourceScopeList(String method, String path) { - log.trace(" ResourceScopeList requested for method:{}, path:{}", method, path); - - // Verify in cache - Map> resources = ApiProtectionCache.getAllResources(); - - // Filter paths based on resource name - Set keys = resources.keySet(); - List filteredPaths = keys.stream().filter(k -> k.contains(path)).collect(Collectors.toList()); - - if (filteredPaths == null || filteredPaths.isEmpty()) { - throw new WebApplicationException("No matching resource found .", - Response.status(Response.Status.UNAUTHORIZED).build()); - } - - List scopeList = null; - for (String key : filteredPaths) { - String[] result = key.split(":::"); - if (result != null && result.length > 1) { - String httpmethod = result[0]; - String pathUrl = result[1]; - log.trace(" Resource Scopes - httpmethod:{} , pathUrl:{} ", httpmethod, pathUrl); - - if (pathUrl != null && pathUrl.contains(path)) { - // Matching url - log.trace(" Matching url with path:{} , pathUrl:{} ", path, pathUrl); - - // Verify Method - if (httpmethod.contains(method)) { - scopeList = ApiProtectionCache.getResourceScopes(key); - log.trace(" scopeList:{} for the method:{} ", scopeList, method); - break; - } - } - } - } - return scopeList; - } - - public List getAllResourceScopes() { - Map scopeMap = ApiProtectionCache.getAllTypesOfScopes(); - log.trace("All Resource Scopes - scopeMap:{}", scopeMap); - - List scopeStrList = null; - if (scopeMap != null && !scopeMap.isEmpty()) { - Set scopeSet = scopeMap.keySet(); - scopeStrList = new ArrayList<>(scopeSet); - } - log.trace("All Resource Scopes - scopeStrList:{} ", scopeStrList); - return scopeStrList; - } - - public List getRequestedScopes(String path) { - List scopeList = ApiProtectionCache.getResourceScopes(path); - log.trace("Requested scopes:{} for path:{} ", scopeList, path); - - List scopeStrList = new ArrayList<>(); - if (scopeList != null && !scopeList.isEmpty()) { - for (Scope s : scopeList) { - scopeStrList.add(s.getId()); - } - } - log.trace("Requested scopeStrList:{} for path:{}", scopeStrList, path); - return scopeStrList; - } - - public List getRequestedScopes(String method, String path) { - log.trace("Requested scopes for path:{} and method:{} ", path, method); - List scopeList = this.getResourceScopeList(method, path); - log.trace("Requested scopeList:{} for path:{} and method:{} ", scopeList, path, method); - List scopeStrList = new ArrayList<>(); - if (scopeList != null && !scopeList.isEmpty()) { - for (Scope s : scopeList) { - scopeStrList.add(s.getId()); - } - } - log.trace("Final scopeStrList:{} for path:{} and method:{} ", scopeStrList, path, method); - return scopeStrList; - } - public Map> getRequestedScopes(ResourceInfo resourceInfo) { log.error("Requested scopes for resourceInfo:{} ", resourceInfo); Class resourceClass = resourceInfo.getResourceClass(); From 90bf084eec84250594bf5e1e15b55cc5a35f7e4b Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Mon, 28 Nov 2022 19:17:31 +0530 Subject: [PATCH 21/28] feat(config-api): scope enhancement- wip --- .../docs/jans-config-api-swagger-auto.yaml | 12 +-- .../security/api/ApiProtectionCache.java | 56 ++++++-------- .../security/api/ApiProtectionService.java | 75 ++++++++++--------- .../service/AuthorizationService.java | 4 +- .../service/OpenIdAuthorizationService.java | 13 ++-- 5 files changed, 72 insertions(+), 88 deletions(-) diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index 35b9e1a6a48..966cf4e015f 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7180,17 +7180,17 @@ components: type: string whitePagesCanView: type: boolean - adminCanView: - type: boolean adminCanAccess: type: boolean - adminCanEdit: + userCanEdit: type: boolean userCanAccess: type: boolean + adminCanEdit: + type: boolean userCanView: type: boolean - userCanEdit: + adminCanView: type: boolean baseDn: type: string @@ -8361,8 +8361,6 @@ components: - STAT - PAR - SSA - fapi: - type: boolean allResponseTypesSupported: uniqueItems: true type: array @@ -8372,6 +8370,8 @@ components: - code - token - id_token + fapi: + type: boolean AuthenticationFilter: required: - baseDn diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java index 9fd9a04a3d3..76b25a7898e 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java @@ -25,17 +25,14 @@ public class ApiProtectionCache { private static final Cache scopeCache = CacheBuilder.newBuilder() .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); - private static final Cache> resourceCache = CacheBuilder.newBuilder() - .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); - private static final Cache groupScopeCache = CacheBuilder.newBuilder() .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); private static final Cache superScopeCache = CacheBuilder.newBuilder() .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); - private static final Cache>> resourceScopeCache = CacheBuilder - .newBuilder().expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); + private static final Cache>> resourceCache = CacheBuilder.newBuilder() + .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); ApiProtectionCache() { } @@ -78,11 +75,11 @@ public static void putGroupScope(Scope scope) { } } - public static void removeAllGroupScopes() { + public static void removeGroupScopes() { groupScopeCache.invalidateAll(); } - public static Map getAllGroupScopes() { + public static Map getGroupScopes() { return Maps.newHashMap(groupScopeCache.asMap()); } @@ -101,11 +98,11 @@ public static void putSuperScope(Scope scope) { } } - public static void removeAllSuperScopes() { + public static void removeSuperScopes() { superScopeCache.invalidateAll(); } - public static Map getAllSuperScopes() { + public static Map getSuperScopes() { return Maps.newHashMap(superScopeCache.asMap()); } @@ -122,55 +119,44 @@ public static void raemoveAllResources() { resourceCache.invalidateAll(); } - public static List getResourceScopes(String resourceName) { - Preconditions.checkNotNull(resourceName); - Preconditions.checkState(!Strings.isNullOrEmpty(resourceName)); - return resourceCache.getIfPresent(resourceName); - - } - - public static void putResource(String resourceName, List scopeList) { - Preconditions.checkNotNull(resourceName); - resourceCache.put(resourceName, scopeList); - - } - - public static Map> getAllResources() { - return Maps.newHashMap(resourceCache.asMap()); - } - - // ResourceScopeCache public static void putResource(String resourceName, Map> scopeMap) { Preconditions.checkNotNull(resourceName); - resourceScopeCache.put(resourceName, scopeMap); + resourceCache.put(resourceName, scopeMap); } public static void putResourceScopeByType(String resourceName, ProtectionScopeType protectionScopeType, List scopes) { Preconditions.checkNotNull(resourceName); Preconditions.checkNotNull(protectionScopeType); - Map> scopeMap = resourceScopeCache.getIfPresent(resourceName); + Map> scopeMap = resourceCache.getIfPresent(resourceName); if (scopeMap == null) { scopeMap = new HashMap<>(); } scopeMap.put(protectionScopeType, scopes); - resourceScopeCache.put(resourceName, scopeMap); + resourceCache.put(resourceName, scopeMap); + } + + public static Map>> getAllResources() { + return Maps.newHashMap(resourceCache.asMap()); + } + + public static Map> getResourceScopes(String resourceName) { + Preconditions.checkNotNull(resourceName); + Preconditions.checkState(!Strings.isNullOrEmpty(resourceName)); + return resourceCache.getIfPresent(resourceName); + } public static List getResourceScopeByType(String resourceName, ProtectionScopeType protectionScopeType) { Preconditions.checkNotNull(resourceName); Preconditions.checkNotNull(protectionScopeType); - Map> scopeMap = resourceScopeCache.getIfPresent(resourceName); + Map> scopeMap = resourceCache.getIfPresent(resourceName); if (scopeMap == null) { return Collections.emptyList(); } return scopeMap.get(protectionScopeType); } - public static Map>> getAllResourcesMap() { - return Maps.newHashMap(resourceScopeCache.asMap()); - } - public static void addScope(String resourceName, ProtectionScopeType protectionScopeType, Scope scope) { Preconditions.checkNotNull(resourceName); Preconditions.checkNotNull(protectionScopeType); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java index 3e18920fda3..b9506a33122 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java @@ -19,6 +19,7 @@ import java.util.Collections; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -53,7 +54,7 @@ public Collection getResourceList() { } public void verifyResources(String apiProtectionType, String clientId) throws IOException { - log.debug( + log.error( "ApiProtectionService::verifyResources() - apiProtectionType:{}, clientId:{}, configurationFactory:{} ", apiProtectionType, clientId, configurationFactory); @@ -63,29 +64,30 @@ public void verifyResources(String apiProtectionType, String clientId) throws IO RsResourceList resourceList = Jackson.createJsonMapper().readValue(inputStream, RsResourceList.class); this.rsResourceList = resourceList.getResources(); - log.debug("verifyResources() - rsResourceList{} ", rsResourceList); + log.error("verifyResources() - rsResourceList{} ", rsResourceList); Preconditions.checkNotNull(rsResourceList, "Config Api Resource list cannot be null !!!"); createScopeIfNeeded(apiProtectionType); - log.debug( - "ApiProtectionService:::verifyResources() - getAllTypesOfScopes:{}, allResources:{}, getAllResourcesMap:{} ", - ApiProtectionCache.getAllTypesOfScopes(), ApiProtectionCache.getAllResources(), - ApiProtectionCache.getAllResourcesMap()); + log.error( + "\n\n\n ***** ApiProtectionService:::verifyResources() - getAllResources:{}, getScopes():{}, getGroupScopes():{}, getSuperScopes():{}, getAllTypesOfScopes():{}", + ApiProtectionCache.getAllResources(), ApiProtectionCache.getScopes(), + ApiProtectionCache.getGroupScopes(), ApiProtectionCache.getSuperScopes(), + ApiProtectionCache.getAllTypesOfScopes()); updateScopeForClientIfNeeded(clientId); } private void createScopeIfNeeded(String apiProtectionType) { - log.debug("ApiProtectionService:::createScopeIfNeeded() - apiProtectionType:{}", apiProtectionType); + log.error("ApiProtectionService:::createScopeIfNeeded() - apiProtectionType:{}", apiProtectionType); List scopeList = new ArrayList<>(); for (RsResource rsResource : rsResourceList) { for (Condition condition : rsResource.getConditions()) { String resourceName = condition.getHttpMethods() + ":::" + rsResource.getPath(); - log.debug( + log.error( "ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, condition.getScopes():{}, condition.getGroupScopes():{}, condition.getSuperScopes():{}", resourceName, condition.getScopes(), condition.getGroupScopes(), condition.getSuperScopes()); @@ -108,7 +110,7 @@ private void createScopeIfNeeded(String apiProtectionType) { processScope(resourceName, ProtectionScopeType.SUPER, superScopes); } - log.debug("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, scopeList:{}", resourceName, + log.error("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, scopeList:{}", resourceName, scopeList); } // condition @@ -117,7 +119,7 @@ private void createScopeIfNeeded(String apiProtectionType) { private void processScope(String resourceName, ProtectionScopeType protectionScopeType, List scopeList) { - log.debug("ApiProtectionService:::processScope() - resourceName:{}, protectionScopeType:{}, scopeList:{}", + log.error("ApiProtectionService:::processScope() - resourceName:{}, protectionScopeType:{}, scopeList:{}", resourceName, protectionScopeType, scopeList); // return if no scopes @@ -128,7 +130,7 @@ private void processScope(String resourceName, ProtectionScopeType protectionSco for (io.jans.configapi.core.protect.Scope rsScope : scopeList) { String inum = rsScope.getInum(); String scopeName = rsScope.getName(); - log.debug("ApiProtectionService:::processScope() - resourceName:{}, inum:{}, scopeName:{}", resourceName, + log.error("ApiProtectionService:::processScope() - resourceName:{}, inum:{}, scopeName:{}", resourceName, inum, scopeName); // return if no scope details @@ -137,28 +139,27 @@ private void processScope(String resourceName, ProtectionScopeType protectionSco } List scopes = validateScope(resourceName, protectionScopeType, rsScope); - ApiProtectionCache.putResource(resourceName, scopes); ApiProtectionCache.putResourceScopeByType(resourceName, protectionScopeType, scopes); } } private List validateScope(String resourceName, ProtectionScopeType protectionScopeType, io.jans.configapi.core.protect.Scope rsScope) { - log.debug("Verify Scope in DB - protectionScopeType:{}, rsScope:{} ", protectionScopeType, rsScope); - List scopeList = new ArrayList<>(); + log.error("Verify Scope in DB - protectionScopeType:{}, rsScope:{} ", protectionScopeType, rsScope); + Set scopeList = new HashSet<>(); // Check in DB Scope scope = scopeService.getScope(rsScope.getInum()); - log.debug("Scopes from DB - {}'", scope); + log.error("Scopes from DB - {}'", scope); if (scope != null) { // Fetch existing scope to store in cache - log.debug("Scope from DB scope.getInum():{}, scope.getId():{}", scope.getInum(), scope.getId()); + log.error("Scope from DB is not null scope.getInum():{}, scope.getId():{}", scope.getInum(), scope.getId()); scopeList.add(scope); } ScopeType scopeType = ScopeType.OAUTH; - log.debug( + log.error( "Scope details - scope:{}, rsScope.getName():{}, exclusiveAuthScopes:{}, isConfigApiScope(scopeName):{} '", scope, rsScope.getName(), configurationFactory.getApiAppConfiguration().getExclusiveAuthScopes(), isConfigApiScope(rsScope.getName())); @@ -168,10 +169,10 @@ private List validateScope(String resourceName, ProtectionScopeType prote // ensure scope does not exists scope = scopeService.getScope(rsScope.getInum()); - log.debug("Re-verify ConfigApiScope rsScope.getName():{} with rsScope.getInum():{} in DB - scope:{} ", + log.error("Re-verify ConfigApiScope rsScope.getName():{} with rsScope.getInum():{} in DB - scope:{} ", rsScope.getName(), rsScope.getInum(), scope); if (scope == null) { - log.debug("Scope - '{}' does not exist, hence creating it.", scope); + log.error("Scope - '{}' does not exist, hence creating it.", scope); // Scope does not exists hence create Scope scope = new Scope(); String inum = rsScope.getInum(); @@ -181,14 +182,14 @@ private List validateScope(String resourceName, ProtectionScopeType prote scope.setDn(scopeService.getDnForScope(inum)); scope.setScopeType(scopeType); scopeService.addScope(scope); + } else { + // Update resource + log.error("Scope - '{}' already exists, hence updating it.", rsScope.getName()); + scope.setId(rsScope.getName()); + scope.setScopeType(scopeType); + scopeService.updateScope(scope); } - // Update resource - log.debug("Scope - '{}' already exists, hence updating it.", rsScope.getName()); - scope.setId(rsScope.getName()); - scope.setScopeType(scopeType); - scopeService.updateScope(scope); - } // Add to scope if not null @@ -196,7 +197,7 @@ private List validateScope(String resourceName, ProtectionScopeType prote scopeList.add(scope); ApiProtectionCache.addScope(resourceName, protectionScopeType, scope); } - return scopeList; + return scopeList.stream().collect(Collectors.toList()); } private boolean isConfigApiScope(String scopeName) { @@ -205,7 +206,7 @@ private boolean isConfigApiScope(String scopeName) { } private void updateScopeForClientIfNeeded(String clientId) { - log.debug(" Internal clientId:{} ", clientId); + log.error(" Internal clientId:{} ", clientId); if (StringUtils.isBlank(clientId)) { return; @@ -213,17 +214,17 @@ private void updateScopeForClientIfNeeded(String clientId) { try { Client client = this.clientService.getClientByInum(clientId); - log.debug("updateScopeForClientIfNeeded() - Verify client:{} ", client); + log.error("updateScopeForClientIfNeeded() - Verify client:{} ", client); if (client != null) { // Assign scope // Prepare scope array List scopes = getScopeWithDn(getAllScopes()); - log.debug("updateScopeForClientIfNeeded() - All scopes:{}", scopes); + log.error("updateScopeForClientIfNeeded() - All scopes:{}", scopes); if (client.getScopes() != null) { List existingScopes = Arrays.asList(client.getScopes()); - log.debug("updateScopeForClientIfNeeded() - Clients existing scopes:{} ", existingScopes); + log.error("updateScopeForClientIfNeeded() - Clients existing scopes:{} ", existingScopes); if (scopes == null) { scopes = new ArrayList<>(); } @@ -233,19 +234,19 @@ private void updateScopeForClientIfNeeded(String clientId) { // Distinct scopes List distinctScopes = (scopes == null ? Collections.emptyList() : scopes.stream().distinct().collect(Collectors.toList())); - log.debug("updateScopeForClientIfNeeded() - Distinct scopes to add:{} ", distinctScopes); + log.error("updateScopeForClientIfNeeded() - Distinct scopes to add:{} ", distinctScopes); String[] scopeArray = this.getAllScopesArray(distinctScopes); - log.debug("All Scope to assign to client:{}", Arrays.asList(scopeArray)); + log.error("All Scope to assign to client:{}", Arrays.asList(scopeArray)); client.setScopes(scopeArray); this.clientService.updateClient(client); } client = this.clientService.getClientByInum(clientId); - log.debug(" Verify scopes post assignment, clientId:{}, scopes:{}", clientId, + log.error(" Verify scopes post assignment, clientId:{}, scopes:{}", clientId, Arrays.asList(client.getScopes())); } catch (Exception ex) { - log.debug("Error while searching internal client", ex); + log.error("Error while searching internal client", ex); } } @@ -256,14 +257,14 @@ private List getAllScopes() { // Verify in cache Map scopeMap = ApiProtectionCache.getAllTypesOfScopes(); Set keys = scopeMap.keySet(); - log.debug(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); + log.error(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); for (String id : keys) { Scope scope = scopeMap.get(id); - log.debug(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); + log.error(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); scopes.add(scope.getInum()); } - log.debug(" All Scopes being returned scopes:{}", scopes); + log.error(" All Scopes being returned scopes:{}", scopes); return scopes; } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java index d9681ee1d61..0b7e2440ae6 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java @@ -40,8 +40,6 @@ protected Response getErrorResponse(Response.Status status, String detail) { return Response.status(status).entity(detail).build(); } - - public Map> getRequestedScopes(ResourceInfo resourceInfo) { return authUtil.getRequestedScopes(resourceInfo); } @@ -49,7 +47,7 @@ public Map> getRequestedScopes(ResourceInfo re public boolean validateScope(List authScopes, List resourceScopes) { return authUtil.validateScope(authScopes, resourceScopes); } - + public List getAllScopeList(Map> scopeMap) { return authUtil.getAllScopeList(scopeMap); } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java index a622436b4b7..dceff93aa85 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java @@ -128,6 +128,9 @@ private String validateScope(String accessToken, List tokenScopes, Resou List resourceScopes = getAllScopeList(resourceScopesByType); logger.error("Validate scope, accessresourceScopesByType: {}, resourceScopes: {}", resourceScopesByType, resourceScopes); + // find missing scopes + List missingScopes = findMissingScopes(resourceScopesByType, tokenScopes); + logger.error("missingScopes:{}", missingScopes); // Check if resource requires auth server specific scope List authSpecificScope = getAuthSpecificScopeRequired(resourceInfo); @@ -136,7 +139,7 @@ private String validateScope(String accessToken, List tokenScopes, Resou // If No auth scope required OR if token contains the authSpecificScope if ((authSpecificScope == null || authSpecificScope.isEmpty())) { logger.error("Validating token scopes as no authSpecificScope required"); - if (!validateScope(tokenScopes, resourceScopes)) { + if ((missingScopes != null && !missingScopes.isEmpty())) { logger.error("Insufficient scopes! Required scope:{} - however token scopes:{}", resourceScopes, tokenScopes); throw new WebApplicationException("Insufficient scopes! , Required scope: " + resourceScopes @@ -146,10 +149,6 @@ private String validateScope(String accessToken, List tokenScopes, Resou return AUTHENTICATION_SCHEME + accessToken; } - // find missing scopes - List missingScopes = findMissingScopes(resourceScopesByType, tokenScopes); - logger.error("missingScopes:{}", missingScopes); - // If only authSpecificScope missing then proceed with token creation else throw // error if (missingScopes != null && !missingScopes.isEmpty() @@ -222,12 +221,12 @@ private List findMissingScopes(Map> sc List missingScopes = findMissingElements(scopeList, tokenScopes); logger.error("SUPER Missing Scopes:{}", missingScopes); - // If + // Super scope present so no need to check other types of scope if (missingScopes == null || missingScopes.isEmpty()) { return missingScopes; } - // Group scope + // Group scope present so no need to check normal scope presence scopeList = scopeMap.get(ProtectionScopeType.GROUP); // find missing scopes missingScopes = findMissingElements(scopeList, tokenScopes); From f7c14985198a0a34272683f6634e42531b0a57c7 Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Mon, 28 Nov 2022 22:15:04 +0530 Subject: [PATCH 22/28] feat(config-api): scope enhancement- wip --- .../docs/jans-config-api-swagger-auto.yaml | 16 ++--- .../security/api/ApiProtectionService.java | 52 ++++++++-------- .../service/OpenIdAuthorizationService.java | 61 +++++++++++-------- .../java/io/jans/configapi/util/AuthUtil.java | 51 ++++++++-------- 4 files changed, 94 insertions(+), 86 deletions(-) diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index 966cf4e015f..08220c7400e 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7178,19 +7178,19 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - whitePagesCanView: + adminCanEdit: type: boolean - adminCanAccess: + adminCanView: + type: boolean + userCanView: type: boolean userCanEdit: type: boolean userCanAccess: type: boolean - adminCanEdit: - type: boolean - userCanView: + adminCanAccess: type: boolean - adminCanView: + whitePagesCanView: type: boolean baseDn: type: string @@ -8361,6 +8361,8 @@ components: - STAT - PAR - SSA + fapi: + type: boolean allResponseTypesSupported: uniqueItems: true type: array @@ -8370,8 +8372,6 @@ components: - code - token - id_token - fapi: - type: boolean AuthenticationFilter: required: - baseDn diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java index b9506a33122..9df93750ce9 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java @@ -54,7 +54,7 @@ public Collection getResourceList() { } public void verifyResources(String apiProtectionType, String clientId) throws IOException { - log.error( + log.debug( "ApiProtectionService::verifyResources() - apiProtectionType:{}, clientId:{}, configurationFactory:{} ", apiProtectionType, clientId, configurationFactory); @@ -64,13 +64,13 @@ public void verifyResources(String apiProtectionType, String clientId) throws IO RsResourceList resourceList = Jackson.createJsonMapper().readValue(inputStream, RsResourceList.class); this.rsResourceList = resourceList.getResources(); - log.error("verifyResources() - rsResourceList{} ", rsResourceList); + log.debug("verifyResources() - rsResourceList{} ", rsResourceList); Preconditions.checkNotNull(rsResourceList, "Config Api Resource list cannot be null !!!"); createScopeIfNeeded(apiProtectionType); - log.error( - "\n\n\n ***** ApiProtectionService:::verifyResources() - getAllResources:{}, getScopes():{}, getGroupScopes():{}, getSuperScopes():{}, getAllTypesOfScopes():{}", + log.trace( + " *** ApiProtectionService:::verifyResources() - getAllResources:{}, getScopes():{}, getGroupScopes():{}, getSuperScopes():{}, getAllTypesOfScopes():{}", ApiProtectionCache.getAllResources(), ApiProtectionCache.getScopes(), ApiProtectionCache.getGroupScopes(), ApiProtectionCache.getSuperScopes(), ApiProtectionCache.getAllTypesOfScopes()); @@ -80,14 +80,14 @@ public void verifyResources(String apiProtectionType, String clientId) throws IO } private void createScopeIfNeeded(String apiProtectionType) { - log.error("ApiProtectionService:::createScopeIfNeeded() - apiProtectionType:{}", apiProtectionType); + log.debug("ApiProtectionService:::createScopeIfNeeded() - apiProtectionType:{}", apiProtectionType); List scopeList = new ArrayList<>(); for (RsResource rsResource : rsResourceList) { for (Condition condition : rsResource.getConditions()) { String resourceName = condition.getHttpMethods() + ":::" + rsResource.getPath(); - log.error( + log.debug( "ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, condition.getScopes():{}, condition.getGroupScopes():{}, condition.getSuperScopes():{}", resourceName, condition.getScopes(), condition.getGroupScopes(), condition.getSuperScopes()); @@ -110,7 +110,7 @@ private void createScopeIfNeeded(String apiProtectionType) { processScope(resourceName, ProtectionScopeType.SUPER, superScopes); } - log.error("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, scopeList:{}", resourceName, + log.debug("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, scopeList:{}", resourceName, scopeList); } // condition @@ -119,7 +119,7 @@ private void createScopeIfNeeded(String apiProtectionType) { private void processScope(String resourceName, ProtectionScopeType protectionScopeType, List scopeList) { - log.error("ApiProtectionService:::processScope() - resourceName:{}, protectionScopeType:{}, scopeList:{}", + log.debug("ApiProtectionService:::processScope() - resourceName:{}, protectionScopeType:{}, scopeList:{}", resourceName, protectionScopeType, scopeList); // return if no scopes @@ -130,7 +130,7 @@ private void processScope(String resourceName, ProtectionScopeType protectionSco for (io.jans.configapi.core.protect.Scope rsScope : scopeList) { String inum = rsScope.getInum(); String scopeName = rsScope.getName(); - log.error("ApiProtectionService:::processScope() - resourceName:{}, inum:{}, scopeName:{}", resourceName, + log.debug("ApiProtectionService:::processScope() - resourceName:{}, inum:{}, scopeName:{}", resourceName, inum, scopeName); // return if no scope details @@ -145,21 +145,21 @@ private void processScope(String resourceName, ProtectionScopeType protectionSco private List validateScope(String resourceName, ProtectionScopeType protectionScopeType, io.jans.configapi.core.protect.Scope rsScope) { - log.error("Verify Scope in DB - protectionScopeType:{}, rsScope:{} ", protectionScopeType, rsScope); + log.debug("Verify Scope in DB - protectionScopeType:{}, rsScope:{} ", protectionScopeType, rsScope); Set scopeList = new HashSet<>(); // Check in DB Scope scope = scopeService.getScope(rsScope.getInum()); - log.error("Scopes from DB - {}'", scope); + log.debug("Scopes from DB - {}'", scope); if (scope != null) { // Fetch existing scope to store in cache - log.error("Scope from DB is not null scope.getInum():{}, scope.getId():{}", scope.getInum(), scope.getId()); + log.debug("Scope from DB is not null scope.getInum():{}, scope.getId():{}", scope.getInum(), scope.getId()); scopeList.add(scope); } ScopeType scopeType = ScopeType.OAUTH; - log.error( + log.debug( "Scope details - scope:{}, rsScope.getName():{}, exclusiveAuthScopes:{}, isConfigApiScope(scopeName):{} '", scope, rsScope.getName(), configurationFactory.getApiAppConfiguration().getExclusiveAuthScopes(), isConfigApiScope(rsScope.getName())); @@ -169,10 +169,10 @@ private List validateScope(String resourceName, ProtectionScopeType prote // ensure scope does not exists scope = scopeService.getScope(rsScope.getInum()); - log.error("Re-verify ConfigApiScope rsScope.getName():{} with rsScope.getInum():{} in DB - scope:{} ", + log.debug("Re-verify ConfigApiScope rsScope.getName():{} with rsScope.getInum():{} in DB - scope:{} ", rsScope.getName(), rsScope.getInum(), scope); if (scope == null) { - log.error("Scope - '{}' does not exist, hence creating it.", scope); + log.debug("Scope - '{}' does not exist, hence creating it.", scope); // Scope does not exists hence create Scope scope = new Scope(); String inum = rsScope.getInum(); @@ -184,7 +184,7 @@ private List validateScope(String resourceName, ProtectionScopeType prote scopeService.addScope(scope); } else { // Update resource - log.error("Scope - '{}' already exists, hence updating it.", rsScope.getName()); + log.debug("Scope - '{}' already exists, hence updating it.", rsScope.getName()); scope.setId(rsScope.getName()); scope.setScopeType(scopeType); scopeService.updateScope(scope); @@ -206,7 +206,7 @@ private boolean isConfigApiScope(String scopeName) { } private void updateScopeForClientIfNeeded(String clientId) { - log.error(" Internal clientId:{} ", clientId); + log.debug(" Internal clientId:{} ", clientId); if (StringUtils.isBlank(clientId)) { return; @@ -214,17 +214,17 @@ private void updateScopeForClientIfNeeded(String clientId) { try { Client client = this.clientService.getClientByInum(clientId); - log.error("updateScopeForClientIfNeeded() - Verify client:{} ", client); + log.debug("updateScopeForClientIfNeeded() - Verify client:{} ", client); if (client != null) { // Assign scope // Prepare scope array List scopes = getScopeWithDn(getAllScopes()); - log.error("updateScopeForClientIfNeeded() - All scopes:{}", scopes); + log.debug("updateScopeForClientIfNeeded() - All scopes:{}", scopes); if (client.getScopes() != null) { List existingScopes = Arrays.asList(client.getScopes()); - log.error("updateScopeForClientIfNeeded() - Clients existing scopes:{} ", existingScopes); + log.debug("updateScopeForClientIfNeeded() - Clients existing scopes:{} ", existingScopes); if (scopes == null) { scopes = new ArrayList<>(); } @@ -234,16 +234,16 @@ private void updateScopeForClientIfNeeded(String clientId) { // Distinct scopes List distinctScopes = (scopes == null ? Collections.emptyList() : scopes.stream().distinct().collect(Collectors.toList())); - log.error("updateScopeForClientIfNeeded() - Distinct scopes to add:{} ", distinctScopes); + log.debug("updateScopeForClientIfNeeded() - Distinct scopes to add:{} ", distinctScopes); String[] scopeArray = this.getAllScopesArray(distinctScopes); - log.error("All Scope to assign to client:{}", Arrays.asList(scopeArray)); + log.debug("All Scope to assign to client:{}", Arrays.asList(scopeArray)); client.setScopes(scopeArray); this.clientService.updateClient(client); } client = this.clientService.getClientByInum(clientId); - log.error(" Verify scopes post assignment, clientId:{}, scopes:{}", clientId, + log.debug(" Verify scopes post assignment, clientId:{}, scopes:{}", clientId, Arrays.asList(client.getScopes())); } catch (Exception ex) { log.error("Error while searching internal client", ex); @@ -257,14 +257,14 @@ private List getAllScopes() { // Verify in cache Map scopeMap = ApiProtectionCache.getAllTypesOfScopes(); Set keys = scopeMap.keySet(); - log.error(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); + log.debug(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); for (String id : keys) { Scope scope = scopeMap.get(id); - log.error(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); + log.trace(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); scopes.add(scope.getInum()); } - log.error(" All Scopes being returned scopes:{}", scopes); + log.debug(" All Scopes being returned scopes:{}", scopes); return scopes; } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java index dceff93aa85..6b76c55886e 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java @@ -120,25 +120,26 @@ public String processAuthorization(String token, String issuer, ResourceInfo res private String validateScope(String accessToken, List tokenScopes, ResourceInfo resourceInfo, String issuer) throws WebApplicationException { - logger.error("Validate scope, accessToken:{}, tokenScopes:{}, resourceInfo: {}, issuer: {}", accessToken, + logger.debug("Validate scope, accessToken:{}, tokenScopes:{}, resourceInfo: {}, issuer: {}", accessToken, tokenScopes, resourceInfo, issuer); try { // Get resource scope Map> resourceScopesByType = getRequestedScopes(resourceInfo); List resourceScopes = getAllScopeList(resourceScopesByType); - logger.error("Validate scope, accessresourceScopesByType: {}, resourceScopes: {}", resourceScopesByType, + logger.debug("Validate scope, resourceScopesByType: {}, resourceScopes: {}", resourceScopesByType, resourceScopes); + // find missing scopes List missingScopes = findMissingScopes(resourceScopesByType, tokenScopes); - logger.error("missingScopes:{}", missingScopes); + logger.debug("missingScopes:{}", missingScopes); // Check if resource requires auth server specific scope List authSpecificScope = getAuthSpecificScopeRequired(resourceInfo); - logger.error(" resourceScopes:{}, authSpecificScope:{} ", resourceScopes, authSpecificScope); + logger.debug(" resourceScopes:{}, authSpecificScope:{} ", resourceScopes, authSpecificScope); // If No auth scope required OR if token contains the authSpecificScope if ((authSpecificScope == null || authSpecificScope.isEmpty())) { - logger.error("Validating token scopes as no authSpecificScope required"); + logger.debug("Validating token scopes as no authSpecificScope required"); if ((missingScopes != null && !missingScopes.isEmpty())) { logger.error("Insufficient scopes! Required scope:{} - however token scopes:{}", resourceScopes, tokenScopes); @@ -163,7 +164,7 @@ private String validateScope(String accessToken, List tokenScopes, Resou // Generate token with required resourceScopes resourceScopes.addAll(authSpecificScope); accessToken = openIdService.requestAccessToken(authUtil.getClientId(), resourceScopes); - logger.error("Introspecting new accessToken:{}", accessToken); + logger.debug("Introspecting new accessToken:{}", accessToken); // Introspect IntrospectionResponse introspectionResponse = openIdService @@ -182,8 +183,8 @@ private String validateScope(String accessToken, List tokenScopes, Resou logger.info("Token scopes Valid Returning accessToken:{}", accessToken); return AUTHENTICATION_SCHEME + accessToken; } catch (Exception ex) { - if (log.isErrorEnabled()) { - log.error("oAuth authorization error:{} ", ex.getMessage()); + if (logger.isErrorEnabled()) { + logger.error("oAuth authorization error:{} ", ex.getMessage()); } throw new WebApplicationException("oAuth authorization error " + ex.getMessage(), Response.status(Response.Status.INTERNAL_SERVER_ERROR).build()); @@ -205,44 +206,54 @@ private boolean externalAuthorization(String token, String issuer, String method } private List findMissingScopes(Map> scopeMap, List tokenScopes) { - logger.error("Check scopeMap:{}, tokenScopes:{}", scopeMap, tokenScopes); + logger.debug("Check scopeMap:{}, tokenScopes:{}", scopeMap, tokenScopes); List scopeList = new ArrayList<>(); if (tokenScopes == null || tokenScopes.isEmpty() || scopeMap == null || scopeMap.isEmpty()) { return scopeList; } for (Map.Entry> entry : scopeMap.entrySet()) { - log.error("Get all entry.getKey():{}, entry.getValue():{} ", entry.getKey(), entry.getValue()); + logger.error("Get all entry.getKey():{}, entry.getValue():{} ", entry.getKey(), entry.getValue()); } // Super scope scopeList = scopeMap.get(ProtectionScopeType.SUPER); - // find missing scopes - List missingScopes = findMissingElements(scopeList, tokenScopes); - logger.error("SUPER Missing Scopes:{}", missingScopes); + logger.debug("SUPER Scopes:{}", scopeList); + List missingScopes = null; + + if (scopeList != null && !scopeList.isEmpty()) { + // find missing scopes + missingScopes = findMissingElements(scopeList, tokenScopes); + logger.debug("SUPER Missing Scopes:{}", missingScopes); - // Super scope present so no need to check other types of scope - if (missingScopes == null || missingScopes.isEmpty()) { - return missingScopes; + // Super scope present so no need to check other types of scope + if (missingScopes == null || missingScopes.isEmpty()) { + return missingScopes; + } } // Group scope present so no need to check normal scope presence scopeList = scopeMap.get(ProtectionScopeType.GROUP); - // find missing scopes - missingScopes = findMissingElements(scopeList, tokenScopes); - logger.error("GROUP Missing Scopes:{}", missingScopes); + logger.debug("GROUP Scopes:{}", scopeList); + if (scopeList != null && !scopeList.isEmpty()) { + // find missing scopes + missingScopes = findMissingElements(scopeList, tokenScopes); + logger.debug("GROUP Missing Scopes:{}", missingScopes); - if (missingScopes == null || missingScopes.isEmpty()) { - return missingScopes; + if (missingScopes == null || missingScopes.isEmpty()) { + return missingScopes; + } } // Normal scope scopeList = scopeMap.get(ProtectionScopeType.SCOPE); - // find missing scopes - missingScopes = findMissingElements(scopeList, tokenScopes); - logger.error("SCOPE Missing Scopes:{}", missingScopes); + logger.debug("SCOPE Scopes:{}", scopeList); + if (scopeList != null && !scopeList.isEmpty()) { + // find missing scopes + missingScopes = findMissingElements(scopeList, tokenScopes); + logger.debug("SCOPE Missing Scopes:{}", missingScopes); + } return missingScopes; - } } \ No newline at end of file diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java index b0029d25615..510be58bd0a 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java @@ -155,42 +155,44 @@ public String encryptPassword(String clientPassword) { } public Map> getRequestedScopes(ResourceInfo resourceInfo) { - log.error("Requested scopes for resourceInfo:{} ", resourceInfo); + log.debug("Requested scopes for resourceInfo:{} ", resourceInfo); Class resourceClass = resourceInfo.getResourceClass(); ProtectedApi typeAnnotation = resourceClass.getAnnotation(ProtectedApi.class); Map> scopes = new HashMap<>(); - log.error("Requested scopes for resourceClass:{}, typeAnnotation:{} ", resourceClass, typeAnnotation); + log.debug("Requested scopes for resourceClass:{}, typeAnnotation:{} ", resourceClass, typeAnnotation); + if (typeAnnotation == null) { - log.error("Requested scopes for resourceClass:{}, typeAnnotation == null ", resourceClass); + log.debug("Requested scopes for resourceClass:{}, typeAnnotation == null ", resourceClass); addMethodScopes(resourceInfo, scopes); } else { - log.error("Requested scopes for resourceClass:{}, typeAnnotation is not null ", resourceClass); + log.debug("Requested scopes for resourceClass:{}, typeAnnotation is not null ", resourceClass); scopes.put(ProtectionScopeType.SCOPE, Stream.of(typeAnnotation.scopes()).collect(Collectors.toList())); scopes.put(ProtectionScopeType.GROUP, Stream.of(typeAnnotation.groupScopes()).collect(Collectors.toList())); scopes.put(ProtectionScopeType.SUPER, Stream.of(typeAnnotation.superScopes()).collect(Collectors.toList())); - log.error("ProtectionScopeType.SCOPE:{} ", Stream.of(typeAnnotation.scopes()).collect(Collectors.toList())); - log.error("ProtectionScopeType.GROUP:{} ", - Stream.of(typeAnnotation.groupScopes()).collect(Collectors.toList())); - log.error("ProtectionScopeType.SUPER:{} ", + log.trace("ProtectionScopeType.SCOPE:{}, ProtectionScopeType.GROUP:{} , ProtectionScopeType.SUPER:{} ", + Stream.of(typeAnnotation.scopes()).collect(Collectors.toList()), + Stream.of(typeAnnotation.groupScopes()).collect(Collectors.toList()), Stream.of(typeAnnotation.superScopes()).collect(Collectors.toList())); - log.error("All scopes:{} ", scopes); + + log.debug("All scopes:{} ", scopes); addMethodScopes(resourceInfo, scopes); } - log.trace("Requested scopes:{} for resourceInfo:{} ", scopes, resourceInfo); + log.debug("*** Final Requested scopes:{} for resourceInfo:{} ", scopes, resourceInfo); return scopes; } public boolean validateScope(List authScopes, List resourceScopes) { - log.error("Validate Scopes for authScopes:{}, resourceScopes:{} ", authScopes, resourceScopes); + log.debug("Validate Scopes for authScopes:{}, resourceScopes:{} ", authScopes, resourceScopes); Set authScopeSet = new HashSet<>(authScopes); Set resourceScopeSet = new HashSet<>(resourceScopes); return authScopeSet.containsAll(resourceScopeSet); } private void addMethodScopes(ResourceInfo resourceInfo, Map> scopes) { - log.error("Method Scopes for resourceInfo:{}, scopes:{} ", resourceInfo, scopes); + log.debug("Method Scopes for resourceInfo:{}, scopes:{} ", resourceInfo, scopes); Method resourceMethod = resourceInfo.getResourceMethod(); ProtectedApi methodAnnotation = resourceMethod.getAnnotation(ProtectedApi.class); + if (methodAnnotation != null) { scopes.put(ProtectionScopeType.SCOPE, Stream.of(methodAnnotation.scopes()).collect(Collectors.toList())); scopes.put(ProtectionScopeType.GROUP, @@ -198,7 +200,7 @@ private void addMethodScopes(ResourceInfo resourceInfo, Map scope) { @@ -308,11 +310,11 @@ public boolean isValidIssuer(String issuer) { } public List getAuthSpecificScopeRequired(ResourceInfo resourceInfo) { - log.error("Fetch Auth server specific scope for resourceInfo:{} ", resourceInfo); + log.debug("Fetch Auth server specific scope for resourceInfo:{} ", resourceInfo); // Get required oauth scopes for the endpoint List resourceScopes = getAllScopeList(getRequestedScopes(resourceInfo)); - log.error(" resource:{} has these scopes:{} and configured exclusiveAuthScopes are {}", resourceInfo, + log.debug(" resource:{} has these scopes:{} and configured exclusiveAuthScopes are {}", resourceInfo, resourceScopes, this.configurationFactory.getApiAppConfiguration().getExclusiveAuthScopes()); // Check if the path has any exclusiveAuthScopes requirement @@ -325,7 +327,7 @@ public List getAuthSpecificScopeRequired(ResourceInfo resourceInfo) { .collect(Collectors.toList()); } - log.error("Applicable exclusiveAuthScopes for resourceInfo:{} are {} ", resourceInfo, exclusiveAuthScopesToReq); + log.debug("Applicable exclusiveAuthScopes for resourceInfo:{} are {} ", resourceInfo, exclusiveAuthScopesToReq); return exclusiveAuthScopesToReq; } @@ -372,31 +374,26 @@ public boolean isValidDn(String dn, boolean strictNameChecking) { } public RevokeSessionResponse revokeSession(final String url, final String token, final String userId) { - log.error("Revoke session Request - url:{}, token:{}, userId:{}", url, token, userId); + log.debug("Revoke session Request - url:{}, token:{}, userId:{}", url, token, userId); RevokeSessionResponse revokeSessionResponse = AuthClientFactory.revokeSession(url, token, userId); - log.error("revokeSessionResponse:{}", revokeSessionResponse); + log.debug("revokeSessionResponse:{}", revokeSessionResponse); if (revokeSessionResponse != null) { - - log.error("revokeSessionResponse.getEntity():{}, revokeSessionResponse.getStatus():{} ", + log.debug("revokeSessionResponse.getEntity():{}, revokeSessionResponse.getStatus():{} ", revokeSessionResponse.getEntity(), revokeSessionResponse.getStatus()); - } return revokeSessionResponse; } public List getAllScopeList(Map> scopeMap) { List scopeList = new ArrayList<>(); - log.error("Get all scopeMap:{} ", scopeMap); + log.debug("Get all scopeMap:{} ", scopeMap); if (scopeMap == null || scopeMap.isEmpty()) { return scopeList; } - scopeMap.entrySet().stream().forEach(e -> { - log.debug("scopeMap data key:{}, value:{} ", e.getKey(), e.getValue()); - scopeList.retainAll(e.getValue()); - }); - log.error("Get all scopeList:{} ", scopeList); + scopeList = scopeMap.get(ProtectionScopeType.SCOPE); + log.debug("Get all scopeList:{} ", scopeList); return scopeList; } From 35b3dc918a891c33092f267ec1e8bb2ecffac071 Mon Sep 17 00:00:00 2001 From: Mustafa Baser Date: Tue, 29 Nov 2022 11:33:58 +0300 Subject: [PATCH 23/28] feat: jans-linux-setup config-api scope creation with static inum (ref: #3097) --- .../setup_app/installers/config_api.py | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/jans-linux-setup/jans_setup/setup_app/installers/config_api.py b/jans-linux-setup/jans_setup/setup_app/installers/config_api.py index 40c470cb2dd..2e5284c049c 100644 --- a/jans-linux-setup/jans_setup/setup_app/installers/config_api.py +++ b/jans-linux-setup/jans_setup/setup_app/installers/config_api.py @@ -77,7 +77,7 @@ def install(self): def extract_files(self): base.extract_file(base.current_app.jans_zip, 'jans-config-api/server/src/main/resources/log4j2.xml', self.custom_config_dir) base.extract_file(base.current_app.jans_zip, 'jans-config-api/docs/jans-config-api-swagger.yaml', Config.data_dir) - + base.extract_file(base.current_app.jans_zip, 'jans-config-api/server/src/main/resources/config-api-rs-protect.json', Config.data_dir) def create_folders(self): for d in (self.output_folder, self.custom_config_dir): @@ -96,11 +96,9 @@ def read_config_api_swagger(self): def generate_configuration(self): - try: - cfg_yml = self.read_config_api_swagger() - scopes_def = cfg_yml['components']['securitySchemes']['oauth2']['flows']['clientCredentials']['scopes'] - except: - scopes_def = {} + + config_api_rs_protect_fn = os.path.join(Config.data_dir, 'config-api-rs-protect.json') + scopes_def = base.readJsonFile(config_api_rs_protect_fn) scope_type = 'oauth' self.check_clients([('jca_client_id', '1800.')]) @@ -109,7 +107,6 @@ def generate_configuration(self): Config.jca_client_pw = self.getPW() Config.jca_client_encoded_pw = self.obscure(Config.jca_client_pw) - scopes = '' scope_ldif_fd = open(self.scope_ldif_fn, 'wb') ldif_scopes_writer = LDIFWriter(scope_ldif_fd, cols=1000) scopes = {} @@ -119,32 +116,37 @@ def generate_configuration(self): scim_scopes = base.current_app.ScimInstaller.create_user_scopes() jansUmaScopes_all += scim_scopes - for scope in scopes_def: - - jansUmaScopes = [] - - if Config.installed_instance and self.dbUtils.search('ou=scopes,o=jans', search_filter='(&(jansId={})(objectClass=jansScope))'.format(scope)): - continue - - if not scope in scopes: - inum = '1800.' + os.urandom(3).hex().upper() - scope_dn = 'inum={},ou=scopes,o=jans'.format(inum) - scopes[scope] = {'dn': scope_dn} - display_name = 'Config API scope {}'.format(scope) - ldif_scopes_writer.unparse( - scope_dn, { - 'objectclass': ['top', 'jansScope'], - 'description': [scopes_def[scope]], - 'displayName': [display_name], - 'inum': [inum], - 'jansDefScope': ['false'], - 'jansId': [scope], - 'jansScopeTyp': [scope_type], - 'jansAttrs': [json.dumps({"spontaneousClientId":None, "spontaneousClientScopes":[], "showInConfigurationEndpoint": False})], - }) - - jansUmaScopes.append(scopes[scope]['dn']) - jansUmaScopes_all.append(scopes[scope]['dn']) + scope_levels = {'scopes':'1', 'groupScopes':'2', 'superScopes':'3'} + + for resource in scopes_def['resources']: + + for condition in resource.get('conditions', []): + for scope_level in scope_levels: + for scope in (condition.get(scope_level, [])): + + if Config.installed_instance and self.dbUtils.search('ou=scopes,o=jans', search_filter='(&(jansId={})(objectClass=jansScope))'.format(scope['name'])): + continue + + if not scope['name'] in scopes: + inum = scope['inum'] + if not inum: + inum = '1800.' + scope_levels[scope_level] + '.' + os.urandom(4).hex().upper() + scope_dn = 'inum={},ou=scopes,o=jans'.format(inum) + scopes[scope['name']] = {'dn': scope_dn} + display_name = 'Config API scope {}'.format(scope['name']) + description = 'Config API {} scope {}'.format(scope_level, scope['name']) + ldif_dict = { + 'objectclass': ['top', 'jansScope'], + 'description': [description], + 'displayName': [display_name], + 'inum': [inum], + 'jansDefScope': ['false'], + 'jansId': [scope['name']], + 'jansScopeTyp': [scope_type], + 'jansAttrs': [json.dumps({"spontaneousClientId":None, "spontaneousClientScopes":[], "showInConfigurationEndpoint": False})], + } + ldif_scopes_writer.unparse(scope_dn, ldif_dict) + jansUmaScopes_all.append(scope_dn) scope_ldif_fd.close() From 0aff4ba1d9fc3c3d8e390b5e0b5412b96838dbd8 Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Tue, 29 Nov 2022 14:41:47 +0530 Subject: [PATCH 24/28] feat(config-api): scope enhancement - wip --- .../docs/jans-config-api-swagger-auto.yaml | 37 +-- .../service/AuthorizationService.java | 9 +- .../service/OpenIdAuthorizationService.java | 27 +-- .../java/io/jans/configapi/util/AuthUtil.java | 38 ++- .../main/resources/config-api-rs-protect.json | 225 +++++++++++++++--- 5 files changed, 262 insertions(+), 74 deletions(-) diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index 08220c7400e..22525f94684 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7178,18 +7178,18 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - adminCanEdit: + userCanEdit: type: boolean - adminCanView: + adminCanAccess: + type: boolean + adminCanEdit: type: boolean userCanView: type: boolean - userCanEdit: + adminCanView: type: boolean userCanAccess: type: boolean - adminCanAccess: - type: boolean whitePagesCanView: type: boolean baseDn: @@ -7620,6 +7620,15 @@ components: format: int32 allowOfflineAccessWithoutConsent: type: boolean + minimumAcrLevel: + type: integer + format: int32 + minimumAcrLevelAutoresolve: + type: boolean + minimumAcrPriorityList: + type: array + items: + type: string CustomObjectAttribute: type: object properties: @@ -8334,6 +8343,15 @@ components: $ref: '#/components/schemas/EngineConfig' ssaConfiguration: $ref: '#/components/schemas/SsaConfiguration' + allResponseTypesSupported: + uniqueItems: true + type: array + items: + type: string + enum: + - code + - token + - id_token enabledFeatureFlags: uniqueItems: true type: array @@ -8363,15 +8381,6 @@ components: - SSA fapi: type: boolean - allResponseTypesSupported: - uniqueItems: true - type: array - items: - type: string - enum: - - code - - token - - id_token AuthenticationFilter: required: - baseDn diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java index 0b7e2440ae6..f2f7bfc3281 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java @@ -7,13 +7,13 @@ package io.jans.configapi.security.service; import io.jans.configapi.util.AuthUtil; -import io.jans.as.persistence.model.Scope; import io.jans.configapi.configuration.ConfigurationFactory; import io.jans.configapi.core.util.ProtectionScopeType; import org.slf4j.Logger; import jakarta.inject.Inject; +import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.container.ResourceInfo; import java.io.Serializable; @@ -34,7 +34,7 @@ public abstract class AuthorizationService implements Serializable { transient AuthUtil authUtil; public abstract String processAuthorization(String token, String issuer, ResourceInfo resourceInfo, String method, - String path) throws Exception; + String path) throws WebApplicationException, Exception; protected Response getErrorResponse(Response.Status status, String detail) { return Response.status(status).entity(detail).build(); @@ -71,4 +71,9 @@ public List findMissingElements(List list1, List list2) public boolean isEqualCollection(List list1, List list2) { return authUtil.isEqualCollection(list1, list2); } + + public boolean containsAnyElement(List list1, List list2) { + return authUtil.containsAnyElement(list1, list2); + } + } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java index 6b76c55886e..425a81b39d6 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java @@ -61,7 +61,7 @@ public class OpenIdAuthorizationService extends AuthorizationService implements ExternalInterceptionService externalInterceptionService; public String processAuthorization(String token, String issuer, ResourceInfo resourceInfo, String method, - String path) throws Exception { + String path) throws WebApplicationException, Exception { logger.debug("oAuth Authorization parameters , token:{}, issuer:{}, resourceInfo:{}, method: {}, path: {} ", token, issuer, resourceInfo, method, path); @@ -212,22 +212,18 @@ private List findMissingScopes(Map> sc return scopeList; } - for (Map.Entry> entry : scopeMap.entrySet()) { - logger.error("Get all entry.getKey():{}, entry.getValue():{} ", entry.getKey(), entry.getValue()); - } - // Super scope scopeList = scopeMap.get(ProtectionScopeType.SUPER); logger.debug("SUPER Scopes:{}", scopeList); List missingScopes = null; - + boolean containsScope = false; if (scopeList != null && !scopeList.isEmpty()) { - // find missing scopes - missingScopes = findMissingElements(scopeList, tokenScopes); - logger.debug("SUPER Missing Scopes:{}", missingScopes); + // check if token contains any of the super scopes + containsScope = containsAnyElement(scopeList, tokenScopes); + logger.debug("Token contains SUPER scopes?:{}", containsScope); // Super scope present so no need to check other types of scope - if (missingScopes == null || missingScopes.isEmpty()) { + if (containsScope) { return missingScopes; } } @@ -236,11 +232,12 @@ private List findMissingScopes(Map> sc scopeList = scopeMap.get(ProtectionScopeType.GROUP); logger.debug("GROUP Scopes:{}", scopeList); if (scopeList != null && !scopeList.isEmpty()) { - // find missing scopes - missingScopes = findMissingElements(scopeList, tokenScopes); - logger.debug("GROUP Missing Scopes:{}", missingScopes); + // check if token contains any of the group scopes + containsScope = containsAnyElement(scopeList, tokenScopes); + logger.debug("Token contains GROUP scopes?:{}", containsScope); - if (missingScopes == null || missingScopes.isEmpty()) { + // Group scope present so no need to check normal scope + if (containsScope) { return missingScopes; } } @@ -249,7 +246,7 @@ private List findMissingScopes(Map> sc scopeList = scopeMap.get(ProtectionScopeType.SCOPE); logger.debug("SCOPE Scopes:{}", scopeList); if (scopeList != null && !scopeList.isEmpty()) { - // find missing scopes + // check if token contains all the required scopes missingScopes = findMissingElements(scopeList, tokenScopes); logger.debug("SCOPE Missing Scopes:{}", missingScopes); } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java index 510be58bd0a..ce28d113ca3 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java @@ -24,6 +24,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -33,9 +34,7 @@ import java.util.stream.Stream; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.container.ResourceInfo; -import jakarta.ws.rs.core.Response; import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; @@ -155,7 +154,8 @@ public String encryptPassword(String clientPassword) { } public Map> getRequestedScopes(ResourceInfo resourceInfo) { - log.debug("Requested scopes for resourceInfo:{} ", resourceInfo); + log.info("Requested scopes for resourceInfo:{} ", resourceInfo); + Class resourceClass = resourceInfo.getResourceClass(); ProtectedApi typeAnnotation = resourceClass.getAnnotation(ProtectedApi.class); Map> scopes = new HashMap<>(); @@ -169,6 +169,7 @@ public Map> getRequestedScopes(ResourceInfo re scopes.put(ProtectionScopeType.SCOPE, Stream.of(typeAnnotation.scopes()).collect(Collectors.toList())); scopes.put(ProtectionScopeType.GROUP, Stream.of(typeAnnotation.groupScopes()).collect(Collectors.toList())); scopes.put(ProtectionScopeType.SUPER, Stream.of(typeAnnotation.superScopes()).collect(Collectors.toList())); + log.trace("ProtectionScopeType.SCOPE:{}, ProtectionScopeType.GROUP:{} , ProtectionScopeType.SUPER:{} ", Stream.of(typeAnnotation.scopes()).collect(Collectors.toList()), Stream.of(typeAnnotation.groupScopes()).collect(Collectors.toList()), @@ -177,19 +178,19 @@ public Map> getRequestedScopes(ResourceInfo re log.debug("All scopes:{} ", scopes); addMethodScopes(resourceInfo, scopes); } - log.debug("*** Final Requested scopes:{} for resourceInfo:{} ", scopes, resourceInfo); + log.info("*** Final Requested scopes:{} for resourceInfo:{} ", scopes, resourceInfo); return scopes; } public boolean validateScope(List authScopes, List resourceScopes) { - log.debug("Validate Scopes for authScopes:{}, resourceScopes:{} ", authScopes, resourceScopes); + log.info("Validate Scopes for authScopes:{}, resourceScopes:{} ", authScopes, resourceScopes); Set authScopeSet = new HashSet<>(authScopes); Set resourceScopeSet = new HashSet<>(resourceScopes); return authScopeSet.containsAll(resourceScopeSet); } private void addMethodScopes(ResourceInfo resourceInfo, Map> scopes) { - log.debug("Method Scopes for resourceInfo:{}, scopes:{} ", resourceInfo, scopes); + log.info("Method Scopes for resourceInfo:{}, scopes:{} ", resourceInfo, scopes); Method resourceMethod = resourceInfo.getResourceMethod(); ProtectedApi methodAnnotation = resourceMethod.getAnnotation(ProtectedApi.class); @@ -200,14 +201,14 @@ private void addMethodScopes(ResourceInfo resourceInfo, Map scope) { log.info("Request for AccessToken - clientId:{}, scope:{} ", clientId, scope); String tokenUrl = getTokenEndpoint(); Token token = getAccessToken(tokenUrl, clientId, scope); - log.info("oAuth AccessToken response - token:{}", token); + log.debug("oAuth AccessToken response - token:{}", token); if (token != null) { return token.getAccessToken(); } @@ -215,7 +216,7 @@ public String requestAccessToken(final String clientId, final List scope } public Token getAccessToken(final String tokenUrl, final String clientId, final List scopes) { - log.debug("Access Token Request - tokenUrl:{}, clientId:{}, scopes:{}", tokenUrl, clientId, scopes); + log.info("Access Token Request - tokenUrl:{}, clientId:{}, scopes:{}", tokenUrl, clientId, scopes); // Get clientSecret String clientSecret = this.getClientDecryptPassword(clientId); @@ -246,7 +247,7 @@ public Token getAccessToken(final String tokenUrl, final String clientId, final } public void assignAllScope(final String clientId) { - log.trace("Client to be assigned all scope - {} ", clientId); + log.info("Client to be assigned all scope - {} ", clientId); // Get Client Client client = this.clientService.getClientByInum(clientId); @@ -310,7 +311,7 @@ public boolean isValidIssuer(String issuer) { } public List getAuthSpecificScopeRequired(ResourceInfo resourceInfo) { - log.debug("Fetch Auth server specific scope for resourceInfo:{} ", resourceInfo); + log.info("Fetch Auth server specific scope for resourceInfo:{} ", resourceInfo); // Get required oauth scopes for the endpoint List resourceScopes = getAllScopeList(getRequestedScopes(resourceInfo)); @@ -327,15 +328,28 @@ public List getAuthSpecificScopeRequired(ResourceInfo resourceInfo) { .collect(Collectors.toList()); } - log.debug("Applicable exclusiveAuthScopes for resourceInfo:{} are {} ", resourceInfo, exclusiveAuthScopesToReq); + log.info("Applicable exclusiveAuthScopes for resourceInfo:{} are {} ", resourceInfo, exclusiveAuthScopesToReq); return exclusiveAuthScopesToReq; } public List findMissingElements(List list1, List list2) { + if (list1 == null || list1.isEmpty() || list2 == null || list2.isEmpty()) { + return Collections.emptyList(); + } return list1.stream().filter(e -> !list2.contains(e)).collect(Collectors.toList()); } + public boolean containsAnyElement(List list1, List list2) { + if (list1 == null || list1.isEmpty() || list2 == null || list2.isEmpty()) { + return false; + } + return list1.stream().anyMatch(list2::contains); + } + public boolean isEqualCollection(List list1, List list2) { + if (list1 == null || list1.isEmpty() || list2 == null || list2.isEmpty()) { + return false; + } return CollectionUtils.isEqualCollection(list1, list2); } diff --git a/jans-config-api/server/src/main/resources/config-api-rs-protect.json b/jans-config-api/server/src/main/resources/config-api-rs-protect.json index fd87f99751f..03315700ed3 100644 --- a/jans-config-api/server/src/main/resources/config-api-rs-protect.json +++ b/jans-config-api/server/src/main/resources/config-api-rs-protect.json @@ -13,7 +13,12 @@ "name": "https://jans.io/oauth/config/acrs.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.2", + "name": "https://jans.io/oauth/config/acrs.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -54,7 +59,12 @@ "name": "https://jans.io/oauth/config/attributes.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.4", + "name": "https://jans.io/oauth/config/attributes.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -115,7 +125,12 @@ "name": "https://jans.io/oauth/config/cache.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -156,7 +171,12 @@ "name": "https://jans.io/oauth/config/cache.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -215,7 +235,12 @@ "name": "https://jans.io/oauth/config/cache.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -274,7 +299,12 @@ "name": "https://jans.io/oauth/config/cache.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -333,7 +363,12 @@ "name": "https://jans.io/oauth/config/cache.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -468,7 +503,12 @@ "name": "https://jans.io/oauth/jans-auth-server/config/properties.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.12", + "name": "https://jans.io/oauth/jans-auth-server/config/properties.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -509,7 +549,12 @@ "name": "https://jans.io/oauth/jans-auth-server/config/properties.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.12", + "name": "https://jans.io/oauth/jans-auth-server/config/properties.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -532,7 +577,12 @@ "name": "https://jans.io/oauth/config/smtp.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.14", + "name": "https://jans.io/oauth/config/smtp.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -592,7 +642,12 @@ "name": "https://jans.io/oauth/config/smtp.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.14", + "name": "https://jans.io/oauth/config/smtp.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -615,7 +670,12 @@ "name": "https://jans.io/oauth/config/scripts.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.17", + "name": "https://jans.io/oauth/config/scripts.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -657,7 +717,12 @@ "name": "https://jans.io/oauth/config/scripts.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.17", + "name": "https://jans.io/oauth/config/scripts.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -680,7 +745,12 @@ "name": "https://jans.io/oauth/config/scripts.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.17", + "name": "https://jans.io/oauth/config/scripts.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -744,7 +814,12 @@ "name": "https://jans.io/oauth/config/fido2.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.20", + "name": "https://jans.io/oauth/config/fido2.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -785,7 +860,12 @@ "name": "https://jans.io/oauth/config/jwks.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.22", + "name": "https://jans.io/oauth/config/jwks.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -845,7 +925,12 @@ "name": "https://jans.io/oauth/config/database/ldap.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.25", + "name": "https://jans.io/oauth/config/database/ldap.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -887,7 +972,12 @@ "name": "https://jans.io/oauth/config/database/ldap.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.25", + "name": "https://jans.io/oauth/config/database/ldap.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -946,7 +1036,12 @@ "name": "https://jans.io/oauth/config/database/ldap.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.25", + "name": "https://jans.io/oauth/config/database/ldap.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -969,7 +1064,12 @@ "name": "https://jans.io/oauth/config/logging.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.28", + "name": "https://jans.io/oauth/config/logging.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -1010,7 +1110,12 @@ "name": "https://jans.io/oauth/config/scopes.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.30", + "name": "https://jans.io/oauth/config/scopes.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -1052,7 +1157,12 @@ "name": "https://jans.io/oauth/config/scopes.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.30", + "name": "https://jans.io/oauth/config/scopes.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -1111,7 +1221,16 @@ "name": "https://jans.io/oauth/config/uma/resources.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.33", + "name": "https://jans.io/oauth/config/uma/resources.write" + }, + { + "inum": "1800.02.4", + "name": "https://jans.io/oauth/config/uma-read" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -1130,7 +1249,12 @@ "name": "https://jans.io/oauth/config/uma/resources.write" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.02.5", + "name": "https://jans.io/oauth/config/uma-write" + } + ], "superScopes": [ { "inum": "1800.03.2", @@ -1153,7 +1277,16 @@ "name": "https://jans.io/oauth/config/uma/resources.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.33", + "name": "https://jans.io/oauth/config/uma/resources.write" + }, + { + "inum": "1800.02.4", + "name": "https://jans.io/oauth/config/uma-read" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -1171,7 +1304,12 @@ "name": "https://jans.io/oauth/config/uma/resources.write" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.02.5", + "name": "https://jans.io/oauth/config/uma-write" + } + ], "superScopes": [ { "inum": "1800.03.2", @@ -1189,7 +1327,12 @@ "name": "https://jans.io/oauth/config/uma/resources.delete" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.02.6", + "name": "https://jans.io/oauth/config/uma-delete" + } + ], "superScopes": [ { "inum": "1800.03.3", @@ -1276,7 +1419,12 @@ "name": "https://jans.io/scim/config.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.37", + "name": "https://jans.io/scim/config.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -1317,7 +1465,12 @@ "name": "https://jans.io/oauth/config/organization.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.39", + "name": "https://jans.io/oauth/config/organization.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -1358,7 +1511,12 @@ "name": "https://jans.io/oauth/config/user.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.41", + "name": "https://jans.io/oauth/config/user.write" + } + ], "superScopes": [ { "inum": "1800.03.1", @@ -1419,7 +1577,12 @@ "name": "https://jans.io/oauth/config/agama.readonly" } ], - "groupScopes": [], + "groupScopes": [ + { + "inum": "1800.01.44", + "name": "https://jans.io/oauth/config/agama.write" + } + ], "superScopes": [ { "inum": "1800.03.1", From 46549b93681ffee6edc1824f9ca5eaace4da9878 Mon Sep 17 00:00:00 2001 From: Mustafa Baser Date: Tue, 29 Nov 2022 12:23:54 +0300 Subject: [PATCH 25/28] fix: jans-linux-setup create scope if inum exists (ref: #3097) --- .../jans_setup/setup_app/installers/config_api.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jans-linux-setup/jans_setup/setup_app/installers/config_api.py b/jans-linux-setup/jans_setup/setup_app/installers/config_api.py index 2e5284c049c..ba1948a798e 100644 --- a/jans-linux-setup/jans_setup/setup_app/installers/config_api.py +++ b/jans-linux-setup/jans_setup/setup_app/installers/config_api.py @@ -124,13 +124,13 @@ def generate_configuration(self): for scope_level in scope_levels: for scope in (condition.get(scope_level, [])): + if not scope.get('inum'): + continue + if Config.installed_instance and self.dbUtils.search('ou=scopes,o=jans', search_filter='(&(jansId={})(objectClass=jansScope))'.format(scope['name'])): continue if not scope['name'] in scopes: - inum = scope['inum'] - if not inum: - inum = '1800.' + scope_levels[scope_level] + '.' + os.urandom(4).hex().upper() scope_dn = 'inum={},ou=scopes,o=jans'.format(inum) scopes[scope['name']] = {'dn': scope_dn} display_name = 'Config API scope {}'.format(scope['name']) From 749d21455dac3c45ff7702f26d54f02461e52298 Mon Sep 17 00:00:00 2001 From: Mustafa Baser Date: Tue, 29 Nov 2022 12:40:26 +0300 Subject: [PATCH 26/28] feat: jans-linux-setup config-api scope creation (ref: #3097) --- .../jans_setup/setup_app/installers/config_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jans-linux-setup/jans_setup/setup_app/installers/config_api.py b/jans-linux-setup/jans_setup/setup_app/installers/config_api.py index ba1948a798e..0904179da7a 100644 --- a/jans-linux-setup/jans_setup/setup_app/installers/config_api.py +++ b/jans-linux-setup/jans_setup/setup_app/installers/config_api.py @@ -131,7 +131,7 @@ def generate_configuration(self): continue if not scope['name'] in scopes: - scope_dn = 'inum={},ou=scopes,o=jans'.format(inum) + scope_dn = 'inum={},ou=scopes,o=jans'.format(scope['inum']) scopes[scope['name']] = {'dn': scope_dn} display_name = 'Config API scope {}'.format(scope['name']) description = 'Config API {} scope {}'.format(scope_level, scope['name']) @@ -139,7 +139,7 @@ def generate_configuration(self): 'objectclass': ['top', 'jansScope'], 'description': [description], 'displayName': [display_name], - 'inum': [inum], + 'inum': [scope['inum']], 'jansDefScope': ['false'], 'jansId': [scope['name']], 'jansScopeTyp': [scope_type], From 6c24268acbcadb1586bb9124891a2c4773ec5cc2 Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Tue, 29 Nov 2022 23:06:09 +0530 Subject: [PATCH 27/28] feat(config-api): scope enhancement - wip --- .../docs/jans-config-api-swagger-auto.yaml | 25 ++++--- .../rest/resource/auth/AcrsResource.java | 13 ++-- .../rest/resource/auth/AgamaResource.java | 27 ++++--- .../resource/auth/AttributesResource.java | 34 +++++---- .../auth/CacheConfigurationResource.java | 72 +++++++++++-------- .../rest/resource/auth/ClientsResource.java | 22 +++--- .../rest/resource/auth/ConfigResource.java | 18 +++-- .../resource/auth/ConfigSmtpResource.java | 17 +++-- .../resource/auth/CustomScriptResource.java | 32 +++++---- .../rest/resource/auth/JwksResource.java | 16 +++-- 10 files changed, 170 insertions(+), 106 deletions(-) diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index 22525f94684..fbfedf44df0 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -132,6 +132,8 @@ paths: security: - oauth2: - https://jans.io/oauth/config/acrs.readonly + - https://jans.io/oauth/config/acrs.write + - https://jans.io/oauth/config/read-all put: tags: - Default Authentication Method @@ -167,6 +169,7 @@ paths: security: - oauth2: - https://jans.io/oauth/config/acrs.write + - https://jans.io/oauth/config/write-all /api/v1/agama: get: tags: @@ -243,6 +246,8 @@ paths: security: - oauth2: - https://jans.io/oauth/config/agama.readonly + - https://jans.io/oauth/config/agama.write + - https://jans.io/oauth/config/read-all post: tags: - Configuration – Agama Flow @@ -333,6 +338,8 @@ paths: security: - oauth2: - https://jans.io/oauth/config/agama.readonly + - https://jans.io/oauth/config/agama.write + - https://jans.io/oauth/config/read-all post: tags: - Configuration – Agama Flow @@ -7178,18 +7185,18 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - userCanEdit: + adminCanView: + type: boolean + userCanAccess: type: boolean adminCanAccess: type: boolean + userCanEdit: + type: boolean adminCanEdit: type: boolean userCanView: type: boolean - adminCanView: - type: boolean - userCanAccess: - type: boolean whitePagesCanView: type: boolean baseDn: @@ -8343,6 +8350,8 @@ components: $ref: '#/components/schemas/EngineConfig' ssaConfiguration: $ref: '#/components/schemas/SsaConfiguration' + fapi: + type: boolean allResponseTypesSupported: uniqueItems: true type: array @@ -8379,8 +8388,6 @@ components: - STAT - PAR - SSA - fapi: - type: boolean AuthenticationFilter: required: - baseDn @@ -8637,13 +8644,13 @@ components: type: boolean internal: type: boolean + locationPath: + type: string locationType: type: string enum: - ldap - file - locationPath: - type: string baseDn: type: string ScriptError: diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AcrsResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AcrsResource.java index 669c24a0268..cfcfc6b52b3 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AcrsResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AcrsResource.java @@ -48,13 +48,15 @@ public class AcrsResource extends ConfigBaseResource { @Operation(summary = "Gets default authentication method.", description = "Gets default authentication method.", operationId = "get-acrs", tags = { "Default Authentication Method" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.ACRS_READ_ACCESS })) + ApiAccessConstants.ACRS_READ_ACCESS, ApiAccessConstants.ACRS_WRITE_ACCESS, + ApiAccessConstants.SUPER_ADMIN_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuthenticationMethod.class) , examples = @ExampleObject(name = "Response example" , value = "example/acr/acr.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuthenticationMethod.class), examples = @ExampleObject(name = "Response example", value = "example/acr/acr.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.ACRS_READ_ACCESS } , superScopes = {ApiAccessConstants.SUPER_ADMIN_READ_ACCESS} ) + @ProtectedApi(scopes = { ApiAccessConstants.ACRS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.ACRS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getDefaultAuthenticationMethod() { final GluuConfiguration gluuConfiguration = configurationService.findGluuConfiguration(); @@ -65,7 +67,7 @@ public Response getDefaultAuthenticationMethod() { @Operation(summary = "Updates default authentication method.", description = "Updates default authentication method.", operationId = "put-acrs", tags = { "Default Authentication Method" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.ACRS_WRITE_ACCESS })) + ApiAccessConstants.ACRS_WRITE_ACCESS, ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS })) @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuthenticationMethod.class), examples = @ExampleObject(name = "Request json example", value = "example/acr/acr.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuthenticationMethod.class))), @@ -73,7 +75,8 @@ public Response getDefaultAuthenticationMethod() { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.ACRS_WRITE_ACCESS } , superScopes = {ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS}) + @ProtectedApi(scopes = { ApiAccessConstants.ACRS_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateDefaultAuthenticationMethod(@NotNull AuthenticationMethod authenticationMethod) { log.debug("ACRS details to update - authenticationMethod:{}", authenticationMethod); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaResource.java index bb7a43d03c0..7e339b63f8d 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaResource.java @@ -61,13 +61,15 @@ public class AgamaResource extends ConfigBaseResource { @Operation(summary = "Fetches all agama flow.", description = "Fetches all agama flow.", operationId = "get-agama-flows", tags = { "Configuration – Agama Flow" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.AGAMA_READ_ACCESS })) + ApiAccessConstants.AGAMA_READ_ACCESS, ApiAccessConstants.AGAMA_WRITE_ACCESS, + ApiAccessConstants.SUPER_ADMIN_READ_ACCESS })) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Agama Flows", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class), examples = @ExampleObject(name = "Response json example", value = "example/agama/agama-get-all.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }, groupScopes = { + ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getFlows(@DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue(ApiConstants.DEFAULT_LIST_START_INDEX) @QueryParam(value = ApiConstants.START_INDEX) int startIndex, @@ -90,13 +92,15 @@ public Response getFlows(@DefaultValue("") @QueryParam(value = ApiConstants.PATT @Operation(summary = "Gets an agama flow based on Qname.", description = "Gets an agama flow based on Qname.", operationId = "get-agama-flow", tags = { "Configuration – Agama Flow" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.AGAMA_READ_ACCESS })) + ApiAccessConstants.AGAMA_READ_ACCESS, ApiAccessConstants.AGAMA_WRITE_ACCESS, + ApiAccessConstants.SUPER_ADMIN_READ_ACCESS })) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Agama Flow", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = Flow.class), examples = @ExampleObject(name = "Response json example", value = "example/agama/agama-get.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }, groupScopes = { + ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.QNAME_PATH) public Response getFlowByName(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @DefaultValue("false") @QueryParam(value = ApiConstants.INCLUDE_SOURCE) boolean includeSource) { @@ -121,7 +125,8 @@ public Response getFlowByName(@PathParam(ApiConstants.QNAME) @NotNull String flo @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createFlow(@Valid Flow flow) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { logger.debug(" Flow to be added flow:{}, flow.getQName():{}, flow.getSource():{} ", flow, flow.getQname(), @@ -155,7 +160,8 @@ public Response createFlow(@Valid Flow flow) @POST @Consumes(MediaType.TEXT_PLAIN) @Path(ApiConstants.QNAME_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createFlowFromSource(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @Valid String source) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { logger.debug(" Flow to be created flowName:{}, source:{}", flowName, source); @@ -196,7 +202,8 @@ public Response createFlowFromSource(@PathParam(ApiConstants.QNAME) @NotNull Str @PUT @Consumes(MediaType.TEXT_PLAIN) @Path(ApiConstants.SOURCE + ApiConstants.QNAME_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateFlowSource(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @Valid String source) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { logger.debug(" Flow to be updated flowName:{}, source:{}", flowName, source); @@ -232,7 +239,8 @@ public Response updateFlowSource(@PathParam(ApiConstants.QNAME) @NotNull String @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) @Path(ApiConstants.QNAME_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchFlow(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @NotNull JsonPatch jsonPatch) throws JsonPatchException, IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { @@ -267,7 +275,8 @@ public Response patchFlow(@PathParam(ApiConstants.QNAME) @NotNull String flowNam @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.QNAME_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_DELETE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response delete(@PathParam(ApiConstants.QNAME) @NotNull String flowName) { logger.debug(" Flow to delete - flowName:{}", flowName); String decodedFlowName = getURLDecodedValue(flowName); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java index b3d48969ef7..5fbeab63569 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java @@ -64,11 +64,12 @@ public class AttributesResource extends ConfigBaseResource { "Attribute" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class), examples = @ExampleObject(name = "Response example" , value = "example/attribute/attribute-get-all.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute-get-all.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS }, groupScopes = { + ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getAttributes( @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -94,11 +95,12 @@ public Response getAttributes( "Attribute" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Response example" , value = "example/attribute/attribute-get.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute-get.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS }, groupScopes = { + ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response getAttributeByInum(@PathParam(ApiConstants.INUM) @NotNull String inum) { GluuAttribute attribute = attributeService.getAttributeByInum(inum); @@ -109,13 +111,14 @@ public Response getAttributeByInum(@PathParam(ApiConstants.INUM) @NotNull String @Operation(summary = "Adds a new attribute", description = "Adds a new attribute", operationId = "post-attributes", tags = { "Attribute" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS })) - @RequestBody(description = "GluuAttribute object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class) , examples = @ExampleObject(name = "Request example" , value = "example/attribute/attribute.json"))) + @RequestBody(description = "GluuAttribute object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Request example", value = "example/attribute/attribute.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class) , examples = @ExampleObject(name = "Response example" , value = "example/attribute/attribute.json"))), + @ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createAttribute(@Valid GluuAttribute attribute) { log.debug(" GluuAttribute details to add - attribute:{}", attribute); checkNotNull(attribute.getName(), AttributeNames.NAME); @@ -132,13 +135,14 @@ public Response createAttribute(@Valid GluuAttribute attribute) { @Operation(summary = "Updates an existing attribute", description = "Updates an existing attribute", operationId = "put-attributes", tags = { "Attribute" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS })) - @RequestBody(description = "GluuAttribute object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class) , examples = @ExampleObject(name = "Request example" , value = "example/attribute/attribute.json"))) + @RequestBody(description = "GluuAttribute object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Request example", value = "example/attribute/attribute.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class) , examples = @ExampleObject(name = "Response example" , value = "example/attribute/attribute.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateAttribute(@Valid GluuAttribute attribute) { log.debug(" GluuAttribute details to update - attribute:{}", attribute); String inum = attribute.getInum(); @@ -158,15 +162,16 @@ public Response updateAttribute(@Valid GluuAttribute attribute) { @Operation(summary = "Partially modify a GluuAttribute", description = "Partially modify a GluuAttribute", operationId = "patch-attributes-by-inum", tags = { "Attribute" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS })) - @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = PatchRequest.class)) , examples = @ExampleObject(name = "Patch request example" , value = "example/attribute/attribute-patch.json"))) + @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = PatchRequest.class)), examples = @ExampleObject(name = "Patch request example", value = "example/attribute/attribute-patch.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Updated GluuAttribute", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class) , examples = @ExampleObject(name = "Response example" , value = "example/attribute/attribute.json"))), + @ApiResponse(responseCode = "200", description = "Updated GluuAttribute", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response patchAtribute(@PathParam(ApiConstants.INUM) @NotNull String inum, @NotNull String pathString) throws JsonPatchException, IOException { @@ -188,7 +193,8 @@ public Response patchAtribute(@PathParam(ApiConstants.INUM) @NotNull String inum @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.INUM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_DELETE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteAttribute(@PathParam(ApiConstants.INUM) @NotNull String inum) { log.debug(" GluuAttribute details to delete - inum:{}", inum); GluuAttribute attribute = attributeService.getAttributeByInum(inum); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CacheConfigurationResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CacheConfigurationResource.java index e538eeb23a0..4cf973f3c06 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CacheConfigurationResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CacheConfigurationResource.java @@ -70,11 +70,12 @@ private CacheConfiguration mergeModifiedCache(Function { @@ -111,7 +113,8 @@ public Response patchCacheConfiguration(@NotNull String requestString) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.REDIS) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }, groupScopes = { + ApiAccessConstants.CACHE_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getRedisConfiguration() { return Response.ok(loadCacheConfiguration().getRedisConfiguration()).build(); } @@ -119,14 +122,15 @@ public Response getRedisConfiguration() { @Operation(summary = "Updates Redis cache configuration.", description = "Updates Redis cache configuration", operationId = "put-config-cache-redis", tags = { "Cache Configuration – Redis" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS })) - @RequestBody(description = "RedisConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class) , examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-redis.json"))) + @RequestBody(description = "RedisConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class), examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-redis.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Redis cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-redis.json"))), + @ApiResponse(responseCode = "200", description = "Redis cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-redis.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT @Path(ApiConstants.REDIS) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateRedisConfiguration(@NotNull RedisConfiguration redisConfiguration) { logger.debug("REDIS CACHE details to update - redisConfiguration:{}", redisConfiguration); final CacheConfiguration modifiedCache = mergeModifiedCache(cache -> { @@ -139,15 +143,16 @@ public Response updateRedisConfiguration(@NotNull RedisConfiguration redisConfig @Operation(summary = "Patch Redis cache configuration.", description = "Patch Redis cache configuration", operationId = "patch-config-cache-redis", tags = { "Cache Configuration – Redis" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS })) - @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)) , examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-redis-patch.json"))) + @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)), examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-redis-patch.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Redis cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-redis.json"))), + @ApiResponse(responseCode = "200", description = "Redis cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-redis.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Path(ApiConstants.REDIS) - @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchRedisConfiguration(@NotNull String requestString) { logger.debug("REDIS CACHE details to patch - requestString:{} ", requestString); mergeModifiedCache(cache -> { @@ -166,12 +171,13 @@ public Response patchRedisConfiguration(@NotNull String requestString) { "Cache Configuration – in-Memory" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "In-Memory configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), + @ApiResponse(responseCode = "200", description = "In-Memory configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.IN_MEMORY) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }, groupScopes = { + ApiAccessConstants.CACHE_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getInMemoryConfiguration() { return Response.ok(loadCacheConfiguration().getInMemoryConfiguration()).build(); } @@ -179,14 +185,15 @@ public Response getInMemoryConfiguration() { @Operation(summary = "Updates in-Memory cache configuration.", description = "Updates in-Memory cache configuration", operationId = "put-config-cache-in-memory", tags = { "Cache Configuration – in-Memory" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS })) - @RequestBody(description = "inMemoryConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class) , examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-in-memory.json"))) + @RequestBody(description = "inMemoryConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class), examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-in-memory.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "In-Memory cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), + @ApiResponse(responseCode = "200", description = "In-Memory cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT @Path(ApiConstants.IN_MEMORY) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateInMemoryConfiguration(@NotNull InMemoryConfiguration inMemoryConfiguration) { logger.debug("IN_MEMORY CACHE details to update - inMemoryConfiguration:{}", inMemoryConfiguration); final CacheConfiguration modifiedCache = mergeModifiedCache(cache -> { @@ -200,15 +207,16 @@ public Response updateInMemoryConfiguration(@NotNull InMemoryConfiguration inMem @Operation(summary = "Patch In-Memory cache configuration.", description = "Patch In-Memory cache configuration", operationId = "patch-config-cache-in-memory", tags = { "Cache Configuration – in-Memory" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS })) - @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)) , examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-in-memory-patch.json"))) + @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)), examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-in-memory-patch.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "In-Memory cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), + @ApiResponse(responseCode = "200", description = "In-Memory cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Path(ApiConstants.IN_MEMORY) @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchInMemoryConfiguration(@NotNull String requestString) { logger.debug("IN_MEMORY CACHE details to patch - requestString:{}", requestString); mergeModifiedCache(cache -> { @@ -231,7 +239,8 @@ public Response patchInMemoryConfiguration(@NotNull String requestString) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.NATIVE_PERSISTENCE) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }, groupScopes = { + ApiAccessConstants.CACHE_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getNativePersistenceConfiguration() { return Response.ok(loadCacheConfiguration().getNativePersistenceConfiguration()).build(); } @@ -241,12 +250,13 @@ public Response getNativePersistenceConfiguration() { ApiAccessConstants.CACHE_WRITE_ACCESS })) @RequestBody(description = "NativePersistenceConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = NativePersistenceConfiguration.class), examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-native-persistence.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Native persistence cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = NativePersistenceConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-native-persistence.json"))), + @ApiResponse(responseCode = "200", description = "Native persistence cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = NativePersistenceConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-native-persistence.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT @Path(ApiConstants.NATIVE_PERSISTENCE) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateNativePersistenceConfiguration( @NotNull NativePersistenceConfiguration nativePersistenceConfiguration) { logger.debug("NATIVE_PERSISTENCE CACHE details to update - nativePersistenceConfiguration:{}", @@ -269,7 +279,8 @@ public Response updateNativePersistenceConfiguration( @PATCH @Path(ApiConstants.NATIVE_PERSISTENCE) @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchNativePersistenceConfiguration(@NotNull String requestString) { logger.debug("NATIVE_PERSISTENCE CACHE details to patch - requestString:{} ", requestString); mergeModifiedCache(cache -> { @@ -288,12 +299,13 @@ public Response patchNativePersistenceConfiguration(@NotNull String requestStrin "Cache Configuration – Memcached" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Memcached configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = MemcachedConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-memcached.json"))), + @ApiResponse(responseCode = "200", description = "Memcached configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = MemcachedConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-memcached.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.MEMCACHED) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }, groupScopes = { + ApiAccessConstants.CACHE_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getMemcachedConfiguration() { return Response.ok(loadCacheConfiguration().getMemcachedConfiguration()).build(); } @@ -309,7 +321,8 @@ public Response getMemcachedConfiguration() { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT @Path(ApiConstants.MEMCACHED) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateMemcachedConfiguration(@NotNull MemcachedConfiguration memcachedConfiguration) { logger.debug("MEMCACHED CACHE details to update - memcachedConfiguration:{} ", memcachedConfiguration); final CacheConfiguration modifiedCache = mergeModifiedCache(cache -> { @@ -330,7 +343,8 @@ public Response updateMemcachedConfiguration(@NotNull MemcachedConfiguration mem @PATCH @Path(ApiConstants.MEMCACHED) @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchMemcachedConfiguration(@NotNull String requestString) { logger.debug("MEMCACHED CACHE details to patch - requestString:{} ", requestString); mergeModifiedCache(cache -> { diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ClientsResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ClientsResource.java index 12f36086b03..ebea7e4f979 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ClientsResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ClientsResource.java @@ -86,11 +86,12 @@ public class ClientsResource extends ConfigBaseResource { "OAuth - OpenID Connect - Clients" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.OPENID_CLIENTS_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class) , examples = @ExampleObject(name = "Response json example", value = "example/openid-clients/openid-clients-get-all.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class), examples = @ExampleObject(name = "Response json example", value = "example/openid-clients/openid-clients-get-all.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_READ_ACCESS }, groupScopes = {ApiAccessConstants.OPENID_READ_ACCESS}, superScopes = {ApiAccessConstants.SUPER_ADMIN_READ_ACCESS}) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_READ_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getOpenIdConnectClients( @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -116,7 +117,8 @@ public Response getOpenIdConnectClients( @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_READ_ACCESS }, groupScopes = {ApiAccessConstants.OPENID_READ_ACCESS}, superScopes = {ApiAccessConstants.SUPER_ADMIN_READ_ACCESS}) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_READ_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response getOpenIdClientByInum(@PathParam(ApiConstants.INUM) @NotNull String inum) { if (logger.isDebugEnabled()) { @@ -136,7 +138,8 @@ public Response getOpenIdClientByInum(@PathParam(ApiConstants.INUM) @NotNull Str @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }, groupScopes = {ApiAccessConstants.OPENID_WRITE_ACCESS}, superScopes = {ApiAccessConstants.SUPER_ADMIN_READ_ACCESS}) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createOpenIdConnect(@Valid Client client) throws EncryptionException { if (logger.isDebugEnabled()) { logger.debug("Client to be added - client:{}, client.getAttributes():{}, client.getCustomAttributes():{}", @@ -184,7 +187,8 @@ public Response createOpenIdConnect(@Valid Client client) throws EncryptionExcep @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }, groupScopes = {ApiAccessConstants.OPENID_WRITE_ACCESS}, superScopes = {ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS}) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateClient(@Valid Client client) throws EncryptionException { if (logger.isDebugEnabled()) { logger.debug("Client details to be updated - client:{}", escapeLog(client)); @@ -217,7 +221,7 @@ public Response updateClient(@Valid Client client) throws EncryptionException { @Operation(summary = "Patch OpenId Connect client", description = "Patch OpenId Connect client", operationId = "patch-oauth-openid-client-by-inum", tags = { "OAuth - OpenID Connect - Clients" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS })) - @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)), examples = @ExampleObject(name = "Request json example", value = "example/openid-clients/openid-clients-patch.json") )) + @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)), examples = @ExampleObject(name = "Request json example", value = "example/openid-clients/openid-clients-patch.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = Client.class), examples = @ExampleObject(name = "Response json example", value = "example/openid-clients/openid-clients-get.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @@ -225,7 +229,8 @@ public Response updateClient(@Valid Client client) throws EncryptionException { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }, groupScopes = {ApiAccessConstants.OPENID_WRITE_ACCESS}, superScopes = {ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS}) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response patchClient(@PathParam(ApiConstants.INUM) @NotNull String inum, @NotNull String jsonPatchString) throws JsonPatchException, IOException { @@ -250,7 +255,8 @@ public Response patchClient(@PathParam(ApiConstants.INUM) @NotNull String inum, @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.INUM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_DELETE_ACCESS }, groupScopes = {ApiAccessConstants.OPENID_DELETE_ACCESS}, superScopes = {ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS}) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_DELETE_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_DELETE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteClient(@PathParam(ApiConstants.INUM) @NotNull String inum) { if (logger.isDebugEnabled()) { logger.debug("Client to be deleted - inum:{} ", escapeLog(inum)); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigResource.java index 5a4e9de9ab4..a24286a23d4 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigResource.java @@ -34,7 +34,6 @@ import jakarta.ws.rs.core.Response; import java.io.IOException; -import org.json.JSONObject; import org.slf4j.Logger; @Path(ApiConstants.JANS_AUTH + ApiConstants.CONFIG) @@ -58,7 +57,9 @@ public class ConfigResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_READ_ACCESS }, groupScopes = { + ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getAppConfiguration() { AppConfiguration appConfiguration = configurationService.find(); log.debug("ConfigResource::getAppConfiguration() appConfiguration:{}", appConfiguration); @@ -67,15 +68,16 @@ public Response getAppConfiguration() { @Operation(summary = "Partially modifies Jans authorization server Application configuration properties.", description = "Partially modifies Jans authorization server AppConfiguration properties.", operationId = "patch-properties", tags = { "Configuration – Properties" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS})) - @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)) , examples = @ExampleObject(name = "Request json example", value = "example/auth/config/auth-config-patch.json"))) + ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS })) + @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)), examples = @ExampleObject(name = "Request json example", value = "example/auth/config/auth-config-patch.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AppConfiguration.class))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchAppConfigurationProperty(@NotNull String jsonPatchString) throws JsonPatchException, IOException { log.debug("AUTH CONF details to patch - jsonPatchString:{} ", jsonPatchString); @@ -101,11 +103,13 @@ public Response patchAppConfigurationProperty(@NotNull String jsonPatchString) "Configuration – Properties" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Jans Authorization Server persistence type", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PersistenceConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/auth/config/auth-config-persistence.json"))), + @ApiResponse(responseCode = "200", description = "Jans Authorization Server persistence type", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PersistenceConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/config/auth-config-persistence.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_READ_ACCESS }, groupScopes = { + ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.PERSISTENCE) public Response getPersistenceDetails() { String persistenceType = configurationService.getPersistenceType(); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigSmtpResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigSmtpResource.java index aca1a9dd13f..18109bd996a 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigSmtpResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigSmtpResource.java @@ -65,7 +65,8 @@ public class ConfigSmtpResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SMTP_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SMTP_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SMTP_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getSmtpServerConfiguration() { SmtpConfiguration smtpConfiguration = configurationService.getConfiguration().getSmtpConfiguration(); log.debug(SMTP_CONFIGURATION + ":{}", smtpConfiguration); @@ -74,14 +75,15 @@ public Response getSmtpServerConfiguration() { @Operation(summary = "Adds SMTP server configuration", description = "Adds SMTP server configuration", operationId = "post-config-smtp", tags = { "Configuration – SMTP" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.SMTP_WRITE_ACCESS })) + ApiAccessConstants.SMTP_WRITE_ACCESS })) @RequestBody(description = "SmtpConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = SmtpConfiguration.class), examples = @ExampleObject(name = "Request json example", value = "example/auth/smtp/smtp.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = SmtpConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/smtp/smtp-get.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.SMTP_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SMTP_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response setupSmtpConfiguration(@Valid SmtpConfiguration smtpConfiguration) throws EncryptionException { log.debug(SMTP_CONFIGURATION + ":{}", smtpConfiguration); String password = smtpConfiguration.getPassword(); @@ -107,7 +109,8 @@ public Response setupSmtpConfiguration(@Valid SmtpConfiguration smtpConfiguratio @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.SMTP_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SMTP_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateSmtpConfiguration(@Valid SmtpConfiguration smtpConfiguration) throws EncryptionException { log.debug(SMTP_CONFIGURATION + ":{}", smtpConfiguration); String password = smtpConfiguration.getPassword(); @@ -131,7 +134,8 @@ public Response updateSmtpConfiguration(@Valid SmtpConfiguration smtpConfigurati @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST @Path(ApiConstants.TEST) - @ProtectedApi(scopes = { ApiAccessConstants.SMTP_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SMTP_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SMTP_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response testSmtpConfiguration() throws EncryptionException { SmtpConfiguration smtpConfiguration = configurationService.getConfiguration().getSmtpConfiguration(); @@ -152,7 +156,8 @@ public Response testSmtpConfiguration() throws EncryptionException { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE - @ProtectedApi(scopes = { ApiAccessConstants.SMTP_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SMTP_DELETE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response removeSmtpConfiguration() { GluuConfiguration configurationUpdate = configurationService.getConfiguration(); configurationUpdate.setSmtpConfiguration(new SmtpConfiguration()); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CustomScriptResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CustomScriptResource.java index 3fd789c4ec8..8a7dffc0d66 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CustomScriptResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CustomScriptResource.java @@ -57,11 +57,12 @@ public class CustomScriptResource extends ConfigBaseResource { "Custom Scripts" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class) , examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-all.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-all.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getAllCustomScripts( @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -83,13 +84,14 @@ public Response getAllCustomScripts( "Custom Scripts" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "CustomScript", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class) , examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-by-name.json"))), + @ApiResponse(responseCode = "200", description = "CustomScript", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-by-name.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(PATH_SEPARATOR + ApiConstants.NAME + ApiConstants.NAME_PARAM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getCustomScriptByName(@PathParam(ApiConstants.NAME) @NotNull String name) { if (logger.isDebugEnabled()) { @@ -113,7 +115,8 @@ public Response getCustomScriptByName(@PathParam(ApiConstants.NAME) @NotNull Str @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(PATH_SEPARATOR + ApiConstants.TYPE + ApiConstants.TYPE_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getCustomScriptsByTypePattern(@PathParam(ApiConstants.TYPE) @NotNull String type, @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -142,7 +145,8 @@ public Response getCustomScriptsByTypePattern(@PathParam(ApiConstants.TYPE) @Not @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(PATH_SEPARATOR + ApiConstants.INUM + PATH_SEPARATOR + ApiConstants.INUM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getCustomScriptByInum(@PathParam(ApiConstants.INUM) @NotNull String inum) { if (logger.isDebugEnabled()) { logger.debug("Custom Script to be fetched - inum:{} ", escapeLog(inum)); @@ -163,13 +167,14 @@ public Response getCustomScriptByInum(@PathParam(ApiConstants.INUM) @NotNull Str @Operation(summary = "Adds a new custom script", description = "Adds a new custom script", operationId = "post-config-scripts", tags = { "Custom Scripts" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS })) - @RequestBody(description = "CustomScript object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class) , examples = @ExampleObject(name = "Request json example", value = "example/auth/scripts/scripts.json"))) + @RequestBody(description = "CustomScript object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class), examples = @ExampleObject(name = "Request json example", value = "example/auth/scripts/scripts.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-response.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createScript(@Valid CustomScript customScript) { logger.debug("Custom Script to create - customScript:{}", customScript); Objects.requireNonNull(customScript, "Attempt to create null custom script"); @@ -187,14 +192,15 @@ public Response createScript(@Valid CustomScript customScript) { @Operation(summary = "Updates a custom script", description = "Updates a custom script", operationId = "put-config-scripts", tags = { "Custom Scripts" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS })) - @RequestBody(description = "CustomScript object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class) , examples = @ExampleObject(name = "Request json example", value = "example/auth/scripts/scripts.json"))) + @RequestBody(description = "CustomScript object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class), examples = @ExampleObject(name = "Request json example", value = "example/auth/scripts/scripts.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-response.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateScript(@Valid @NotNull CustomScript customScript) { logger.debug("Custom Script to update - customScript:{}", customScript); CustomScript existingScript = customScriptService.getScriptByInum(customScript.getInum()); @@ -214,7 +220,8 @@ public Response updateScript(@Valid @NotNull CustomScript customScript) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.INUM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_DELETE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteScript(@PathParam(ApiConstants.INUM) @NotNull String inum) { try { if (logger.isDebugEnabled()) { @@ -240,7 +247,8 @@ public Response deleteScript(@PathParam(ApiConstants.INUM) @NotNull String inum) @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response patchAtribute(@PathParam(ApiConstants.INUM) @NotNull String inum, @NotNull String pathString) throws JsonPatchException, IOException { diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/JwksResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/JwksResource.java index ff1fd210881..2277f784771 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/JwksResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/JwksResource.java @@ -58,7 +58,8 @@ public class JwksResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.JWKS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response get() { final String json = configurationService.findConf().getWebKeys().toString(); log.debug("JWKS json :{}", json); @@ -74,7 +75,7 @@ public Response get() { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response put(WebKeysConfiguration webkeys) { log.debug("JWKS details to be updated - webkeys:{}", webkeys); final Conf conf = configurationService.findConf(); @@ -94,7 +95,7 @@ public Response put(WebKeysConfiguration webkeys) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patch(String requestString) throws JsonPatchException, IOException { log.debug("JWKS details to be patched - requestString:{}", requestString); final Conf conf = configurationService.findConf(); @@ -116,7 +117,7 @@ public Response patch(String requestString) throws JsonPatchException, IOExcepti @ApiResponse(responseCode = "406", description = "Not Acceptable"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.KEY_PATH) public Response getKeyById(@NotNull JSONWebKey jwk) { log.debug("Add a new Key to the JWKS:{}", jwk); @@ -145,7 +146,8 @@ public Response getKeyById(@NotNull JSONWebKey jwk) { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_READ_ACCESS } , groupScopes = { + ApiAccessConstants.JWKS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.KID_PATH) public Response getKeyById(@PathParam(ApiConstants.KID) @NotNull String kid) { log.debug("Fetch JWK details by kid:{}", kid); @@ -166,7 +168,7 @@ public Response getKeyById(@PathParam(ApiConstants.KID) @NotNull String kid) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.KID_PATH) public Response patch(@PathParam(ApiConstants.KID) @NotNull String kid, @NotNull String requestString) throws JsonPatchException, IOException { @@ -201,7 +203,7 @@ public Response patch(@PathParam(ApiConstants.KID) @NotNull String kid, @NotNull @ApiResponse(responseCode = "406", description = "Not Acceptable"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_DELETE_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) @Path(ApiConstants.KID_PATH) public Response deleteKey(@PathParam(ApiConstants.KID) @NotNull String kid) { log.debug("Key to be to be deleted - kid:{}", kid); From 58ccd9229528f48c20d86f09b139967684b5f0d0 Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Wed, 30 Nov 2022 16:37:49 +0530 Subject: [PATCH 28/28] feat(config-api): scope enhancement --- ; | 6 ------ .../configapi/util/ApiAccessConstants.java | 4 ++++ .../docs/jans-config-api-swagger-auto.yaml | 16 +++++++-------- .../auth/LdapConfigurationResource.java | 16 ++++++++------- .../rest/resource/auth/LoggingResource.java | 5 +++-- .../resource/auth/OrganizationResource.java | 5 +++-- .../rest/resource/auth/ScopesResource.java | 20 +++++++++++-------- .../rest/resource/auth/SessionResource.java | 4 ++-- .../rest/resource/auth/StatResource.java | 2 +- .../resource/auth/UmaResourcesResource.java | 17 +++++++++------- .../main/resources/config-api-rs-protect.json | 4 ++++ 11 files changed, 56 insertions(+), 43 deletions(-) delete mode 100644 ; diff --git a/; b/; deleted file mode 100644 index 8982a76312a..00000000000 --- a/; +++ /dev/null @@ -1,6 +0,0 @@ -Merge branch 'main' of https://github.com/JanssenProject/jans into jans-config-fixes -# Please enter a commit message to explain why this merge is necessary, -# especially if it merges an updated upstream into a topic branch. -# -# Lines starting with '#' will be ignored, and an empty message aborts -# the commit. diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiAccessConstants.java b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiAccessConstants.java index 9c7d593199c..fd8bacbb807 100644 --- a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiAccessConstants.java +++ b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiAccessConstants.java @@ -79,4 +79,8 @@ private ApiAccessConstants() { public static final String OPENID_READ_ACCESS = "https://jans.io/oauth/config/openid-read"; public static final String OPENID_WRITE_ACCESS = "https://jans.io/oauth/config/openid/openid-write"; public static final String OPENID_DELETE_ACCESS = "https://jans.io/oauth/config/openid/openid-delete"; + + public static final String UMA_READ_ACCESS = "https://jans.io/oauth/config/uma-read"; + public static final String UMA_WRITE_ACCESS = "https://jans.io/oauth/config/uma-write"; + public static final String UMA_DELETE_ACCESS = "https://jans.io/oauth/config/uma-delete"; } diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index fbfedf44df0..2b3b83113f0 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -7185,18 +7185,18 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - adminCanView: - type: boolean - userCanAccess: - type: boolean - adminCanAccess: + adminCanEdit: type: boolean userCanEdit: type: boolean - adminCanEdit: + adminCanView: type: boolean userCanView: type: boolean + adminCanAccess: + type: boolean + userCanAccess: + type: boolean whitePagesCanView: type: boolean baseDn: @@ -8350,8 +8350,6 @@ components: $ref: '#/components/schemas/EngineConfig' ssaConfiguration: $ref: '#/components/schemas/SsaConfiguration' - fapi: - type: boolean allResponseTypesSupported: uniqueItems: true type: array @@ -8388,6 +8386,8 @@ components: - STAT - PAR - SSA + fapi: + type: boolean AuthenticationFilter: required: - baseDn diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LdapConfigurationResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LdapConfigurationResource.java index 70a34784847..c09729faf71 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LdapConfigurationResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LdapConfigurationResource.java @@ -55,7 +55,8 @@ public class LdapConfigurationResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS } , groupScopes = { + ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getLdapConfiguration() { List ldapConfigurationList = this.ldapConfigurationService.findLdapConfigurations(); return Response.ok(ldapConfigurationList).build(); @@ -70,7 +71,8 @@ public Response getLdapConfiguration() { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.NAME_PARAM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS } , groupScopes = { + ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getLdapConfigurationByName(@PathParam(ApiConstants.NAME) String name) { GluuLdapConfiguration ldapConfiguration = findLdapConfigurationByName(name); return Response.ok(ldapConfiguration).build(); @@ -86,7 +88,7 @@ public Response getLdapConfigurationByName(@PathParam(ApiConstants.NAME) String @ApiResponse(responseCode = "406", description = "Not Acceptable"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response addLdapConfiguration(@Valid @NotNull GluuLdapConfiguration ldapConfiguration) { logger.debug("LDAP configuration to be added - ldapConfiguration:{} ", ldapConfiguration); // Ensure that an LDAP server with same name does not exists. @@ -113,7 +115,7 @@ public Response addLdapConfiguration(@Valid @NotNull GluuLdapConfiguration ldapC @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateLdapConfiguration(@Valid @NotNull GluuLdapConfiguration ldapConfiguration) { logger.debug("LDAP configuration to be updated - ldapConfiguration:{}", ldapConfiguration); findLdapConfigurationByName(ldapConfiguration.getConfigId()); @@ -131,7 +133,7 @@ public Response updateLdapConfiguration(@Valid @NotNull GluuLdapConfiguration ld @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.NAME_PARAM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_DELETE_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteLdapConfigurationByName(@PathParam(ApiConstants.NAME) String name) { logger.debug("LDAP configuration to be deleted - name:{}", name); findLdapConfigurationByName(name); @@ -153,7 +155,7 @@ public Response deleteLdapConfigurationByName(@PathParam(ApiConstants.NAME) Stri @PATCH @Path(ApiConstants.NAME_PARAM_PATH) @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchLdapConfigurationByName(@PathParam(ApiConstants.NAME) String name, @NotNull String requestString) throws JsonPatchException, IOException { logger.debug("LDAP configuration to be patched - name:{}, requestString:{} ", name, requestString); @@ -175,7 +177,7 @@ public Response patchLdapConfigurationByName(@PathParam(ApiConstants.NAME) Strin @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST @Path(ApiConstants.TEST) - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS }, groupScopes = {ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response testLdapConfigurationByName(@Valid @NotNull GluuLdapConfiguration ldapConfiguration) { logger.debug("LDAP configuration to be tested - ldapConfiguration:{}", ldapConfiguration); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LoggingResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LoggingResource.java index 5f85a9e31e0..68717ee9a3e 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LoggingResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LoggingResource.java @@ -51,7 +51,8 @@ public class LoggingResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.LOGGING_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.LOGGING_READ_ACCESS } , groupScopes = { + ApiAccessConstants.LOGGING_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getLogging() { return Response.ok(this.getLoggingConfiguration()).build(); } @@ -65,7 +66,7 @@ public Response getLogging() { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.LOGGING_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.LOGGING_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateLogConf(@Valid Logging logging) { log.debug("LOGGING configuration to be updated -logging:{}", logging); Conf conf = configurationService.findConf(); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/OrganizationResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/OrganizationResource.java index ca8f4718a7a..c878d482d11 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/OrganizationResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/OrganizationResource.java @@ -49,7 +49,8 @@ public class OrganizationResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.ORG_CONFIG_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ORG_CONFIG_READ_ACCESS } , groupScopes = { + ApiAccessConstants.ORG_CONFIG_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getOrganization() { return Response.ok(organizationService.getOrganization()).build(); } @@ -64,7 +65,7 @@ public Response getOrganization() { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.ORG_CONFIG_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ORG_CONFIG_WRITE_ACCESS }, groupScopes = { }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchOrganization(@NotNull String pathString) throws JsonPatchException, IOException { logger.trace("Organization patch request - pathString:{} ", pathString); GluuOrganization organization = organizationService.getOrganization(); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ScopesResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ScopesResource.java index 16a74953142..f4845572e30 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ScopesResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ScopesResource.java @@ -80,7 +80,8 @@ public class ScopesResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS } , groupScopes = { + ApiAccessConstants.SCOPES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getScopes(@DefaultValue("") @QueryParam(ApiConstants.TYPE) String type, @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -106,7 +107,8 @@ public Response getScopes(@DefaultValue("") @QueryParam(ApiConstants.TYPE) Strin @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS } , groupScopes = { + ApiAccessConstants.SCOPES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response getScopeById(@NotNull @PathParam(ApiConstants.INUM) String inum, @DefaultValue("false") @QueryParam(value = ApiConstants.WITH_ASSOCIATED_CLIENTS) boolean withAssociatedClients) { @@ -124,7 +126,8 @@ public Response getScopeById(@NotNull @PathParam(ApiConstants.INUM) String inum, @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SCOPES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.CREATOR + ApiConstants.CREATORID_PATH) public Response getScopeByClientId(@NotNull @PathParam(ApiConstants.CREATORID) String creatorId) { log.debug("SCOPES to be fetched by creatorId:{}", creatorId); @@ -144,7 +147,8 @@ public Response getScopeByClientId(@NotNull @PathParam(ApiConstants.CREATORID) S @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS } , groupScopes = { + ApiAccessConstants.SCOPES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.TYPE + ApiConstants.TYPE_PATH) public Response getScopeByType(@NotNull @PathParam(ApiConstants.TYPE) String type) { log.debug("SCOPES to be fetched by type:{}", type); @@ -164,7 +168,7 @@ public Response getScopeByType(@NotNull @PathParam(ApiConstants.TYPE) String typ @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createOpenidScope(@Valid Scope scope) { log.debug("SCOPE to be added - scope:{}", scope); @@ -195,7 +199,7 @@ public Response createOpenidScope(@Valid Scope scope) { @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateScope(@Valid Scope scope) { log.debug("SCOPE to be updated - scop:{}", scope.getId()); String inum = scope.getInum(); @@ -226,7 +230,7 @@ public Response updateScope(@Valid Scope scope) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response patchScope(@PathParam(ApiConstants.INUM) @NotNull String inum, @NotNull String pathString) throws JsonPatchException, IOException { @@ -251,7 +255,7 @@ public Response patchScope(@PathParam(ApiConstants.INUM) @NotNull String inum, @ @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.INUM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_DELETE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteScope(@PathParam(ApiConstants.INUM) @NotNull String inum) { log.debug("SCOPES to be deleted - inum:{}", inum); Scope scope = scopeService.getScopeByInum(inum); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/SessionResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/SessionResource.java index c6c86e9b702..1da2c0840aa 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/SessionResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/SessionResource.java @@ -49,7 +49,7 @@ public class SessionResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_SESSION_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_SESSION_READ_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getAllSessions() { final List sessions = sessionService.getSessions(); logger.debug("sessions:{}", sessions); @@ -66,7 +66,7 @@ public Response getAllSessions() { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_SESSION_DELETE_ACCESS, - ApiAccessConstants.JANS_AUTH_REVOKE_SESSION }) + ApiAccessConstants.JANS_AUTH_REVOKE_SESSION } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) @Path(ApiConstants.USERDN_PATH) public Response getAppConfiguration(@PathParam(ApiConstants.USERDN) @NotNull String userDn) { logger.debug("userDn:{}", userDn); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/StatResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/StatResource.java index 555870cf972..496c31f60ab 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/StatResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/StatResource.java @@ -46,7 +46,7 @@ public class StatResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.STATS_USER_READ_ACCESS, ApiAccessConstants.JANS_STAT }) + @ProtectedApi(scopes = { ApiAccessConstants.STATS_USER_READ_ACCESS, ApiAccessConstants.JANS_STAT } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Produces(MediaType.APPLICATION_JSON) public Response getStatistics(@HeaderParam("Authorization") String authorization, @QueryParam(value = "month") String month, @QueryParam(value = "start_month") String startMonth, diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UmaResourcesResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UmaResourcesResource.java index 00b29370e18..d01993838e2 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UmaResourcesResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UmaResourcesResource.java @@ -67,7 +67,8 @@ public class UmaResourcesResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS } , groupScopes = { + ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS, ApiAccessConstants.UMA_READ_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response fetchUmaResources( @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -92,7 +93,8 @@ public Response fetchUmaResources( @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.ID_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS }, groupScopes = { + ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS, ApiAccessConstants.UMA_READ_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getUmaResourceByInum(@PathParam(value = ApiConstants.ID) @NotNull String id) { logger.debug("UMA_RESOURCE to fetch by id:{}", id); return Response.ok(findOrThrow(id)).build(); @@ -107,7 +109,8 @@ public Response getUmaResourceByInum(@PathParam(value = ApiConstants.ID) @NotNul @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path("/" + ApiConstants.CLIENTID + ApiConstants.CLIENTID_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS }, groupScopes = { + ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS, ApiAccessConstants.UMA_READ_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getUmaResourceByAssociatedClient( @PathParam(value = ApiConstants.CLIENTID) @NotNull String associatedClientId) { logger.debug("UMA_RESOURCE to fetch by associatedClientId:{} ", associatedClientId); @@ -124,7 +127,7 @@ public Response getUmaResourceByAssociatedClient( @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }, groupScopes = { ApiAccessConstants.UMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createUmaResource(@Valid UmaResource umaResource) { logger.debug("UMA_RESOURCE to be added umaResource:{}", umaResource); checkNotNull(umaResource.getName(), AttributeNames.NAME); @@ -158,7 +161,7 @@ private UmaResource findOrThrow(String id) { @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }, groupScopes = { ApiAccessConstants.UMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateUmaResource(@Valid UmaResource resource) { logger.debug("UMA_RESOURCE to be upated - umaResource:{}", resource); String id = resource.getId(); @@ -182,7 +185,7 @@ public Response updateUmaResource(@Valid UmaResource resource) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }, groupScopes = { ApiAccessConstants.UMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.ID_PATH) public Response patchResource(@PathParam(ApiConstants.ID) @NotNull String id, @NotNull String pathString) throws JsonPatchException, IOException { @@ -203,7 +206,7 @@ public Response patchResource(@PathParam(ApiConstants.ID) @NotNull String id, @N @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.ID_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_DELETE_ACCESS }, groupScopes = { ApiAccessConstants.UMA_DELETE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteUmaResource(@PathParam(value = ApiConstants.ID) @NotNull String id) { logger.debug("UMA_RESOURCE to delete - id:{}", id); UmaResource umaResource = findOrThrow(id); diff --git a/jans-config-api/server/src/main/resources/config-api-rs-protect.json b/jans-config-api/server/src/main/resources/config-api-rs-protect.json index 03315700ed3..9b8561234c2 100644 --- a/jans-config-api/server/src/main/resources/config-api-rs-protect.json +++ b/jans-config-api/server/src/main/resources/config-api-rs-protect.json @@ -1658,6 +1658,10 @@ { "inum": "1800.01.47", "name": "https://jans.io/oauth/jans-auth-server/session.delete" + }, + { + "inum": "", + "name": "revoke_session" } ], "groupScopes": [],