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.core.spring.security;
20  
21  import com.nimbusds.jose.JOSEException;
22  import com.nimbusds.jose.JWSAlgorithm;
23  import com.nimbusds.jose.KeyLengthException;
24  import java.security.NoSuchAlgorithmException;
25  import java.security.spec.InvalidKeySpecException;
26  import org.apache.syncope.common.lib.types.CipherAlgorithm;
27  import org.apache.syncope.core.persistence.api.dao.AccessTokenDAO;
28  import org.apache.syncope.core.persistence.api.dao.RealmDAO;
29  import org.apache.syncope.core.persistence.api.dao.UserDAO;
30  import org.apache.syncope.core.provisioning.api.rules.RuleEnforcer;
31  import org.apache.syncope.core.spring.ApplicationContextProvider;
32  import org.apache.syncope.core.spring.policy.DefaultRuleEnforcer;
33  import org.apache.syncope.core.spring.security.jws.AccessTokenJWSSigner;
34  import org.apache.syncope.core.spring.security.jws.AccessTokenJWSVerifier;
35  import org.slf4j.Logger;
36  import org.slf4j.LoggerFactory;
37  import org.springframework.beans.factory.config.BeanDefinition;
38  import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
39  import org.springframework.boot.context.properties.EnableConfigurationProperties;
40  import org.springframework.context.annotation.Bean;
41  import org.springframework.context.annotation.Configuration;
42  import org.springframework.context.annotation.Role;
43  import org.springframework.security.config.core.GrantedAuthorityDefaults;
44  
45  @EnableConfigurationProperties(SecurityProperties.class)
46  @Configuration(proxyBeanMethods = false)
47  public class SecurityContext {
48  
49      private static final Logger LOG = LoggerFactory.getLogger(SecurityContext.class);
50  
51      @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
52      @Bean
53      public static GrantedAuthorityDefaults grantedAuthorityDefaults() {
54          return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
55      }
56  
57      protected static String jwsKey(final JWSAlgorithm jwsAlgorithm, final SecurityProperties props) {
58          String jwsKey = props.getJwsKey();
59          if (jwsKey == null) {
60              throw new IllegalArgumentException("No JWS key provided");
61          }
62  
63          if (JWSAlgorithm.Family.HMAC_SHA.contains(jwsAlgorithm)) {
64              int minLength = jwsAlgorithm.equals(JWSAlgorithm.HS256)
65                      ? 256 / 8
66                      : jwsAlgorithm.equals(JWSAlgorithm.HS384)
67                      ? 384 / 8
68                      : 512 / 8;
69              if (jwsKey.length() < minLength) {
70                  jwsKey = SecureRandomUtils.generateRandomPassword(minLength);
71                  props.setJwsKey(jwsKey);
72                  LOG.warn("The configured key for {} must be at least {} bits, generating random: {}",
73                          jwsAlgorithm, minLength * 8, jwsKey);
74              }
75          }
76  
77          return jwsKey;
78      }
79  
80      @Bean
81      public CipherAlgorithm adminPasswordAlgorithm(final SecurityProperties props) {
82          return props.getAdminPasswordAlgorithm();
83      }
84  
85      @Bean
86      public JWSAlgorithm jwsAlgorithm(final SecurityProperties props) {
87          return JWSAlgorithm.parse(props.getJwsAlgorithm().toUpperCase());
88      }
89  
90      @ConditionalOnMissingBean
91      @Bean
92      public DefaultCredentialChecker credentialChecker(
93              final SecurityProperties props,
94              final JWSAlgorithm jwsAlgorithm) {
95  
96          return new DefaultCredentialChecker(
97                  jwsKey(jwsAlgorithm, props),
98                  props.getAdminPassword(),
99                  props.getAnonymousKey());
100     }
101 
102     @ConditionalOnMissingBean
103     @Bean
104     public AccessTokenJWSVerifier accessTokenJWSVerifier(
105             final JWSAlgorithm jwsAlgorithm,
106             final SecurityProperties props)
107             throws JOSEException, NoSuchAlgorithmException, InvalidKeySpecException {
108 
109         return new AccessTokenJWSVerifier(jwsAlgorithm, jwsKey(jwsAlgorithm, props));
110     }
111 
112     @ConditionalOnMissingBean
113     @Bean
114     public AccessTokenJWSSigner accessTokenJWSSigner(
115             final JWSAlgorithm jwsAlgorithm,
116             final SecurityProperties props)
117             throws KeyLengthException, NoSuchAlgorithmException, InvalidKeySpecException {
118 
119         return new AccessTokenJWSSigner(jwsAlgorithm, jwsKey(jwsAlgorithm, props));
120     }
121 
122     @ConditionalOnMissingBean
123     @Bean
124     public SyncopeJWTSSOProvider syncopeJWTSSOProvider(
125             final SecurityProperties props,
126             final AccessTokenJWSVerifier accessTokenJWSVerifier,
127             final UserDAO userDAO,
128             final AccessTokenDAO accessTokenDAO) {
129 
130         return new SyncopeJWTSSOProvider(props, accessTokenJWSVerifier, userDAO, accessTokenDAO);
131     }
132 
133     @ConditionalOnMissingBean
134     @Bean
135     public PasswordGenerator passwordGenerator() {
136         return new DefaultPasswordGenerator();
137     }
138 
139     @ConditionalOnMissingBean
140     @Bean
141     public RuleEnforcer ruleEnforcer(final RealmDAO realmDAO) {
142         return new DefaultRuleEnforcer(realmDAO);
143     }
144 
145     @Bean
146     public ApplicationContextProvider applicationContextProvider() {
147         return new ApplicationContextProvider();
148     }
149 }