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
26
27
28
29
30
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 }