View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.wa.starter.mapping;
20  
21  import java.util.HashSet;
22  import java.util.Objects;
23  import java.util.Optional;
24  import java.util.Set;
25  import java.util.stream.Collectors;
26  import org.apache.commons.lang3.StringUtils;
27  import org.apache.syncope.common.lib.OIDCScopeConstants;
28  import org.apache.syncope.common.lib.to.ClientAppTO;
29  import org.apache.syncope.common.lib.to.OIDCRPClientAppTO;
30  import org.apache.syncope.common.lib.types.OIDCGrantType;
31  import org.apache.syncope.common.lib.types.OIDCResponseType;
32  import org.apache.syncope.common.lib.wa.WAClientApp;
33  import org.apereo.cas.oidc.claims.OidcAddressScopeAttributeReleasePolicy;
34  import org.apereo.cas.oidc.claims.OidcCustomScopeAttributeReleasePolicy;
35  import org.apereo.cas.oidc.claims.OidcEmailScopeAttributeReleasePolicy;
36  import org.apereo.cas.oidc.claims.OidcOpenIdScopeAttributeReleasePolicy;
37  import org.apereo.cas.oidc.claims.OidcPhoneScopeAttributeReleasePolicy;
38  import org.apereo.cas.oidc.claims.OidcProfileScopeAttributeReleasePolicy;
39  import org.apereo.cas.services.BaseMappedAttributeReleasePolicy;
40  import org.apereo.cas.services.ChainingAttributeReleasePolicy;
41  import org.apereo.cas.services.OidcRegisteredService;
42  import org.apereo.cas.services.RegisteredService;
43  import org.apereo.cas.services.RegisteredServiceAccessStrategy;
44  import org.apereo.cas.services.RegisteredServiceAttributeReleasePolicy;
45  import org.apereo.cas.services.RegisteredServiceAuthenticationPolicy;
46  import org.apereo.cas.services.RegisteredServiceMultifactorPolicy;
47  import org.apereo.cas.services.RegisteredServiceProxyGrantingTicketExpirationPolicy;
48  import org.apereo.cas.services.RegisteredServiceProxyTicketExpirationPolicy;
49  import org.apereo.cas.services.RegisteredServiceServiceTicketExpirationPolicy;
50  import org.apereo.cas.services.RegisteredServiceTicketGrantingTicketExpirationPolicy;
51  import org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy;
52  
53  public class OIDCRPClientAppTOMapper extends AbstractClientAppMapper {
54  
55      @Override
56      public boolean supports(final ClientAppTO clientApp) {
57          return OIDCRPClientAppTO.class.equals(clientApp.getClass());
58      }
59  
60      @Override
61      public RegisteredService map(
62              final WAClientApp clientApp,
63              final RegisteredServiceAuthenticationPolicy authPolicy,
64              final RegisteredServiceMultifactorPolicy mfaPolicy,
65              final RegisteredServiceAccessStrategy accessStrategy,
66              final RegisteredServiceAttributeReleasePolicy attributeReleasePolicy,
67              final RegisteredServiceTicketGrantingTicketExpirationPolicy tgtExpirationPolicy,
68              final RegisteredServiceServiceTicketExpirationPolicy stExpirationPolicy,
69              final RegisteredServiceProxyGrantingTicketExpirationPolicy tgtProxyExpirationPolicy,
70              final RegisteredServiceProxyTicketExpirationPolicy stProxyExpirationPolicy) {
71  
72          OIDCRPClientAppTO rp = OIDCRPClientAppTO.class.cast(clientApp.getClientAppTO());
73          OidcRegisteredService service = new OidcRegisteredService();
74          setCommon(service, rp);
75  
76          service.setServiceId(rp.getRedirectUris().stream().
77                  filter(Objects::nonNull).
78                  collect(Collectors.joining("|")));
79          service.setClientId(rp.getClientId());
80          service.setClientSecret(rp.getClientSecret());
81          service.setSignIdToken(rp.isSignIdToken());
82          if (!service.isSignIdToken()) {
83              service.setIdTokenSigningAlg("none");
84          }
85          service.setJwtAccessToken(rp.isJwtAccessToken());
86          service.setBypassApprovalPrompt(rp.isBypassApprovalPrompt());
87          service.setGenerateRefreshToken(rp.isGenerateRefreshToken());
88          if (StringUtils.isNotBlank(rp.getJwksUri())) {
89              service.setJwks(rp.getJwksUri());
90          } else {
91              service.setJwks(rp.getJwks());
92          }
93          service.setSupportedGrantTypes(rp.getSupportedGrantTypes().stream().
94                  map(OIDCGrantType::name).collect(Collectors.toSet()));
95          service.setSupportedResponseTypes(rp.getSupportedResponseTypes().stream().
96                  map(OIDCResponseType::getExternalForm).collect(Collectors.toSet()));
97          Optional.ofNullable(rp.getSubjectType()).ifPresent(st -> service.setSubjectType(st.name()));
98          service.setLogoutUrl(rp.getLogoutUri());
99          service.setTokenEndpointAuthenticationMethod(rp.getTokenEndpointAuthenticationMethod().name());
100 
101         service.setScopes(new HashSet<>(rp.getScopes()));
102 
103         ChainingAttributeReleasePolicy chain;
104         if (attributeReleasePolicy instanceof ChainingAttributeReleasePolicy) {
105             chain = (ChainingAttributeReleasePolicy) attributeReleasePolicy;
106         } else {
107             chain = new ChainingAttributeReleasePolicy();
108             Optional.ofNullable(attributeReleasePolicy).ifPresent(chain::addPolicies);
109         }
110 
111         if (rp.getScopes().contains(OIDCScopeConstants.OPEN_ID)) {
112             chain.addPolicies(new OidcOpenIdScopeAttributeReleasePolicy());
113         }
114         if (rp.getScopes().contains(OIDCScopeConstants.PROFILE)) {
115             chain.addPolicies(new OidcProfileScopeAttributeReleasePolicy());
116         }
117         if (rp.getScopes().contains(OIDCScopeConstants.ADDRESS)) {
118             chain.addPolicies(new OidcAddressScopeAttributeReleasePolicy());
119         }
120         if (rp.getScopes().contains(OIDCScopeConstants.EMAIL)) {
121             chain.addPolicies(new OidcEmailScopeAttributeReleasePolicy());
122         }
123         if (rp.getScopes().contains(OIDCScopeConstants.PHONE)) {
124             chain.addPolicies(new OidcPhoneScopeAttributeReleasePolicy());
125         }
126 
127         Set<String> customClaims = new HashSet<>();
128         if (attributeReleasePolicy instanceof BaseMappedAttributeReleasePolicy) {
129             customClaims.addAll(((BaseMappedAttributeReleasePolicy) attributeReleasePolicy).
130                     getAllowedAttributes().values().stream().
131                     map(Objects::toString).collect(Collectors.toSet()));
132         } else if (attributeReleasePolicy instanceof ReturnAllowedAttributeReleasePolicy) {
133             customClaims.addAll(((ReturnAllowedAttributeReleasePolicy) attributeReleasePolicy).
134                     getAllowedAttributes().stream().collect(Collectors.toSet()));
135         } else if (attributeReleasePolicy instanceof ChainingAttributeReleasePolicy) {
136             ((ChainingAttributeReleasePolicy) attributeReleasePolicy).getPolicies().stream().
137                     filter(ReturnAllowedAttributeReleasePolicy.class::isInstance).
138                     findFirst().map(ReturnAllowedAttributeReleasePolicy.class::cast).
139                     map(p -> p.getAllowedAttributes().stream().collect(Collectors.toSet())).
140                     ifPresent(customClaims::addAll);
141         }
142         if (rp.getScopes().contains(OIDCScopeConstants.PROFILE)) {
143             customClaims.removeAll(OidcProfileScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
144         }
145         if (rp.getScopes().contains(OIDCScopeConstants.ADDRESS)) {
146             customClaims.removeAll(OidcAddressScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
147         }
148         if (rp.getScopes().contains(OIDCScopeConstants.EMAIL)) {
149             customClaims.removeAll(OidcEmailScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
150         }
151         if (rp.getScopes().contains(OIDCScopeConstants.PHONE)) {
152             customClaims.removeAll(OidcPhoneScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
153         }
154 
155         if (!customClaims.isEmpty()) {
156             service.getScopes().add(OIDCScopeConstants.SYNCOPE);
157 
158             chain.addPolicies(new OidcCustomScopeAttributeReleasePolicy(
159                     OIDCScopeConstants.SYNCOPE, customClaims.stream().collect(Collectors.toList())));
160         }
161 
162         setPolicies(service, authPolicy, mfaPolicy, accessStrategy, chain,
163                 tgtExpirationPolicy, stExpirationPolicy, tgtProxyExpirationPolicy, stProxyExpirationPolicy);
164 
165         return service;
166     }
167 }