View Javadoc
1   package org.argeo.naming;
2   
3   import java.io.IOException;
4   import java.util.Arrays;
5   import java.util.StringTokenizer;
6   
7   import javax.naming.NamingEnumeration;
8   import javax.naming.NamingException;
9   import javax.naming.directory.Attribute;
10  import javax.naming.directory.Attributes;
11  import javax.security.auth.callback.Callback;
12  import javax.security.auth.callback.CallbackHandler;
13  import javax.security.auth.callback.NameCallback;
14  import javax.security.auth.callback.PasswordCallback;
15  import javax.security.auth.callback.UnsupportedCallbackException;
16  
17  import org.argeo.osgi.useradmin.UserDirectoryException;
18  
19  /** LDAP authPassword field according to RFC 3112 */
20  public class AuthPassword implements CallbackHandler {
21  	private final String authScheme;
22  	private final String authInfo;
23  	private final String authValue;
24  
25  	public AuthPassword(String value) {
26  		StringTokenizer st = new StringTokenizer(value, "$");
27  		// TODO make it more robust, deal with bad formatting
28  		this.authScheme = st.nextToken().trim();
29  		this.authInfo = st.nextToken().trim();
30  		this.authValue = st.nextToken().trim();
31  
32  		String expectedAuthScheme = getExpectedAuthScheme();
33  		if (expectedAuthScheme != null && !authScheme.equals(expectedAuthScheme))
34  			throw new IllegalArgumentException(
35  					"Auth scheme " + authScheme + " is not compatible with " + expectedAuthScheme);
36  	}
37  
38  	protected AuthPassword(String authInfo, String authValue) {
39  		this.authScheme = getExpectedAuthScheme();
40  		if (authScheme == null)
41  			throw new IllegalArgumentException("Expected auth scheme cannot be null");
42  		this.authInfo = authInfo;
43  		this.authValue = authValue;
44  	}
45  
46  	protected AuthPassword(AuthPassword authPassword) {
47  		this.authScheme = authPassword.getAuthScheme();
48  		this.authInfo = authPassword.getAuthInfo();
49  		this.authValue = authPassword.getAuthValue();
50  	}
51  
52  	protected String getExpectedAuthScheme() {
53  		return null;
54  	}
55  
56  	protected boolean matchAuthValue(Object object) {
57  		return authValue.equals(object.toString());
58  	}
59  
60  	@Override
61  	public boolean equals(Object obj) {
62  		if (!(obj instanceof AuthPassword))
63  			return false;
64  		AuthPassword authPassword = (AuthPassword) obj;
65  		return authScheme.equals(authPassword.authScheme) && authInfo.equals(authPassword.authInfo)
66  				&& authValue.equals(authValue);
67  	}
68  
69  	public boolean keyEquals(AuthPassword authPassword) {
70  		return authScheme.equals(authPassword.authScheme) && authInfo.equals(authPassword.authInfo);
71  	}
72  
73  	@Override
74  	public int hashCode() {
75  		return authValue.hashCode();
76  	}
77  
78  	@Override
79  	public String toString() {
80  		return toAuthPassword();
81  	}
82  
83  	public final String toAuthPassword() {
84  		return getAuthScheme() + '$' + authInfo + '$' + authValue;
85  	}
86  
87  	public String getAuthScheme() {
88  		return authScheme;
89  	}
90  
91  	public String getAuthInfo() {
92  		return authInfo;
93  	}
94  
95  	public String getAuthValue() {
96  		return authValue;
97  	}
98  
99  	public static AuthPassword matchAuthValue(Attributes attributes, char[] value) {
100 		try {
101 			Attribute authPassword = attributes.get(LdapAttrs.authPassword.name());
102 			if (authPassword != null) {
103 				NamingEnumeration<?> values = authPassword.getAll();
104 				while (values.hasMore()) {
105 					Object val = values.next();
106 					AuthPassword token = new AuthPassword(val.toString());
107 					String auth;
108 					if (Arrays.binarySearch(value, '$') >= 0) {
109 						auth = token.authInfo + '$' + token.authValue;
110 					} else {
111 						auth = token.authValue;
112 					}
113 					if (Arrays.equals(auth.toCharArray(), value))
114 						return token;
115 					// if (token.matchAuthValue(value))
116 					// return token;
117 				}
118 			}
119 			return null;
120 		} catch (NamingException e) {
121 			throw new UserDirectoryException("Cannot check attribute", e);
122 		}
123 	}
124 
125 	public static boolean remove(Attributes attributes, AuthPassword value) {
126 		Attribute authPassword = attributes.get(LdapAttrs.authPassword.name());
127 		return authPassword.remove(value.toAuthPassword());
128 	}
129 
130 	@Override
131 	public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
132 		for (Callback callback : callbacks) {
133 			if (callback instanceof NameCallback)
134 				((NameCallback) callback).setName(toAuthPassword());
135 			else if (callback instanceof PasswordCallback)
136 				((PasswordCallback) callback).setPassword(getAuthValue().toCharArray());
137 		}
138 	}
139 
140 }