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