View Javadoc

1   package org.springframework.security.config;
2   
3   import org.springframework.security.providers.encoding.Md4PasswordEncoder;
4   import org.springframework.security.providers.encoding.Md5PasswordEncoder;
5   import org.springframework.security.providers.encoding.PlaintextPasswordEncoder;
6   import org.springframework.security.providers.encoding.ShaPasswordEncoder;
7   import org.springframework.security.providers.encoding.BaseDigestPasswordEncoder;
8   import org.springframework.security.providers.ldap.authenticator.LdapShaPasswordEncoder;
9   import org.springframework.beans.factory.xml.ParserContext;
10  import org.springframework.beans.factory.config.BeanDefinition;
11  import org.springframework.beans.factory.config.RuntimeBeanReference;
12  import org.springframework.beans.factory.support.RootBeanDefinition;
13  import org.springframework.beans.BeanMetadataElement;
14  import org.springframework.util.StringUtils;
15  import org.springframework.util.xml.DomUtils;
16  
17  import org.w3c.dom.Element;
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  
21  import java.util.Map;
22  import java.util.HashMap;
23  
24  /**
25   * Stateful parser for the <password-encoder> element.
26   *
27   * Will produce a PasswordEncoder and (optionally) a SaltSource.
28   *
29   * @author Luke Taylor
30   * @version $Id: PasswordEncoderParser.java 3079 2008-05-20 22:45:02Z luke_t $
31   */
32  public class PasswordEncoderParser {
33      static final String ATT_REF = "ref";
34      static final String ATT_HASH = "hash";
35      static final String ATT_BASE_64 = "base64";
36      static final String OPT_HASH_PLAINTEXT = "plaintext";    
37      static final String OPT_HASH_SHA = "sha";
38      static final String OPT_HASH_SHA256 = "sha-256";    
39      static final String OPT_HASH_MD4 = "md4";
40      static final String OPT_HASH_MD5 = "md5";
41      static final String OPT_HASH_LDAP_SHA = "{sha}";
42  
43      static final Map ENCODER_CLASSES;
44  
45      static {
46          ENCODER_CLASSES = new HashMap();
47          ENCODER_CLASSES.put(OPT_HASH_PLAINTEXT, PlaintextPasswordEncoder.class);
48          ENCODER_CLASSES.put(OPT_HASH_SHA, ShaPasswordEncoder.class);
49          ENCODER_CLASSES.put(OPT_HASH_SHA256, ShaPasswordEncoder.class);
50          ENCODER_CLASSES.put(OPT_HASH_MD4, Md4PasswordEncoder.class);
51          ENCODER_CLASSES.put(OPT_HASH_MD5, Md5PasswordEncoder.class);
52          ENCODER_CLASSES.put(OPT_HASH_LDAP_SHA, LdapShaPasswordEncoder.class);
53      }
54  
55      private Log logger = LogFactory.getLog(getClass());
56  
57      private BeanMetadataElement passwordEncoder;
58      private BeanDefinition saltSource;
59  
60      public PasswordEncoderParser(Element element, ParserContext parserContext) {
61          parse(element, parserContext);
62      }
63  
64      private void parse(Element element, ParserContext parserContext) {
65          String hash = element.getAttribute(ATT_HASH);
66          boolean useBase64 = false;
67          
68          if (StringUtils.hasText(element.getAttribute(ATT_BASE_64))) {
69              useBase64 = new Boolean(element.getAttribute(ATT_BASE_64)).booleanValue();
70          }
71  
72          String ref = element.getAttribute(ATT_REF);
73  
74          if (StringUtils.hasText(ref)) {
75              passwordEncoder = new RuntimeBeanReference(ref);
76          } else {
77              Class beanClass = (Class) ENCODER_CLASSES.get(hash);
78              RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
79              
80              if (OPT_HASH_SHA256.equals(hash)) {
81                  beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new Integer(256));
82              }
83              
84              beanDefinition.setSource(parserContext.extractSource(element));
85              if (useBase64) {
86                  if (BaseDigestPasswordEncoder.class.isAssignableFrom(beanClass)) {
87                      beanDefinition.getPropertyValues().addPropertyValue("encodeHashAsBase64", "true");
88                  } else {
89                      logger.warn(ATT_BASE_64 + " isn't compatible with " + hash + " and will be ignored");
90                  }
91              }
92              passwordEncoder = beanDefinition;
93          }
94  
95          Element saltSourceElt = DomUtils.getChildElementByTagName(element, Elements.SALT_SOURCE);
96  
97          if (saltSourceElt != null) {
98              saltSource = new SaltSourceBeanDefinitionParser().parse(saltSourceElt, parserContext);
99          }
100     }
101 
102     public BeanMetadataElement getPasswordEncoder() {
103         return passwordEncoder;
104     }
105 
106     public BeanDefinition getSaltSource() {
107         return saltSource;
108     }
109 }