View Javadoc

1   /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package org.springframework.ws.soap.security.x509.populator;
17  
18  import org.springframework.security.core.SpringSecurityMessageSource;
19  import org.springframework.security.core.AuthenticationException;
20  import org.springframework.security.authentication.BadCredentialsException;
21  import org.springframework.security.authentication.AuthenticationServiceException;
22  
23  import org.springframework.ws.soap.security.x509.X509AuthoritiesPopulator;
24  
25  import org.springframework.security.core.userdetails.UserDetails;
26  import org.springframework.security.core.userdetails.UserDetailsService;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  import org.springframework.beans.factory.InitializingBean;
32  
33  import org.springframework.context.MessageSource;
34  import org.springframework.context.MessageSourceAware;
35  import org.springframework.context.support.MessageSourceAccessor;
36  
37  import org.springframework.util.Assert;
38  
39  import java.security.cert.X509Certificate;
40  import java.util.regex.Pattern;
41  import java.util.regex.Matcher;
42  
43  /**
44   * Populates the X509 authorities via an {@link org.springframework.security.core.userdetails.UserDetailsService}.
45   * <p>Migrated from Spring Security 2 since it has been removed in Spring Security 3.</p>
46   *
47   * @author Luke Taylor
48   * @version $Id: DaoX509AuthoritiesPopulator.java 2544 2008-01-29 11:50:33Z luke_t $
49   */
50  public class DaoX509AuthoritiesPopulator implements X509AuthoritiesPopulator, InitializingBean, MessageSourceAware {
51      //~ Static fields/initializers =====================================================================================
52  
53      private static final Log logger = LogFactory.getLog(DaoX509AuthoritiesPopulator.class);
54  
55      //~ Instance fields ================================================================================================
56  
57      protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
58      private Pattern subjectDNPattern;
59      private String subjectDNRegex = "CN=(.*?),";
60      private UserDetailsService userDetailsService;
61  
62      //~ Methods ========================================================================================================
63  
64      public void afterPropertiesSet() throws Exception {
65          Assert.notNull(userDetailsService, "An authenticationDao must be set");
66          Assert.notNull(this.messages, "A message source must be set");
67  
68          subjectDNPattern = Pattern.compile(subjectDNRegex, Pattern.CASE_INSENSITIVE);
69      }
70  
71      public UserDetails getUserDetails(X509Certificate clientCert) throws AuthenticationException {
72          String subjectDN = clientCert.getSubjectDN().getName();
73  
74          Matcher matcher = subjectDNPattern.matcher(subjectDN);
75  
76          if (!matcher.find()) {
77              throw new BadCredentialsException(messages.getMessage("DaoX509AuthoritiesPopulator.noMatching",
78                      new Object[] {subjectDN}, "No matching pattern was found in subjectDN: {0}"));
79          }
80  
81          if (matcher.groupCount() != 1) {
82              throw new IllegalArgumentException("Regular expression must contain a single group ");
83          }
84  
85          String userName = matcher.group(1);
86  
87          UserDetails user = this.userDetailsService.loadUserByUsername(userName);
88  
89          if (user == null) {
90              throw new AuthenticationServiceException(
91                  "UserDetailsService returned null, which is an interface contract violation");
92          }
93  
94          return user;
95      }
96  
97      public void setMessageSource(MessageSource messageSource) {
98          this.messages = new MessageSourceAccessor(messageSource);
99      }
100 
101     /**
102      * Sets the regular expression which will by used to extract the user name from the certificate's Subject
103      * DN.
104      * <p>It should contain a single group; for example the default expression "CN=(.?)," matches the common
105      * name field. So "CN=Jimi Hendrix, OU=..." will give a user name of "Jimi Hendrix".</p>
106      * <p>The matches are case insensitive. So "emailAddress=(.?)," will match "EMAILADDRESS=[email protected],
107      * CN=..." giving a user name "[email protected]"</p>
108      *
109      * @param subjectDNRegex the regular expression to find in the subject
110      */
111     public void setSubjectDNRegex(String subjectDNRegex) {
112         this.subjectDNRegex = subjectDNRegex;
113     }
114 
115     public void setUserDetailsService(UserDetailsService userDetailsService) {
116         this.userDetailsService = userDetailsService;
117     }
118 }