code_junkie

How do you authenticate against an Active Directory server using Spring Security?

Nov 10th, 2011
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.54 KB | None | 0 0
  1. <beans:bean id="ldapAuthProvider" class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
  2. <beans:constructor-arg>
  3. <beans:bean class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
  4. <beans:constructor-arg ref="initialDirContextFactory" />
  5. <beans:property name="userDnPatterns">
  6. <beans:list>
  7. <beans:value>CN={0},OU=SBSUsers,OU=Users,OU=MyBusiness,DC=Acme,DC=com</beans:value>
  8. </beans:list>
  9. </beans:property>
  10. </beans:bean>
  11. </beans:constructor-arg>
  12. </beans:bean>
  13.  
  14. <beans:bean id="userDetailsService" class="org.springframework.security.userdetails.ldap.LdapUserDetailsManager">
  15. <beans:constructor-arg ref="initialDirContextFactory" />
  16. </beans:bean>
  17.  
  18. <beans:bean id="initialDirContextFactory" class="org.springframework.security.ldap.DefaultInitialDirContextFactory">
  19. <beans:constructor-arg value="ldap://192.168.123.456:389/DC=Acme,DC=com" />
  20. </beans:bean>
  21.  
  22. <beans:bean id="contextSource"
  23. class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
  24. <beans:constructor-arg value="ldap://hostname.queso.com:389/" />
  25. </beans:bean>
  26.  
  27. <beans:bean id="ldapAuthenticationProvider"
  28. class="org.queso.ad.service.authentication.LdapAuthenticationProvider">
  29. <beans:property name="authenticator" ref="ldapAuthenticator" />
  30. <custom-authentication-provider />
  31. </beans:bean>
  32.  
  33. <beans:bean id="ldapAuthenticator"
  34. class="org.queso.ad.service.authentication.LdapAuthenticatorImpl">
  35. <beans:property name="contextFactory" ref="contextSource" />
  36. <beans:property name="principalPrefix" value="QUESO" />
  37. </beans:bean>
  38.  
  39. /**
  40. * Custom Spring Security authentication provider which tries to bind to an LDAP server with
  41. * the passed-in credentials; of note, when used with the custom {@link LdapAuthenticatorImpl},
  42. * does <strong>not</strong> require an LDAP username and password for initial binding.
  43. *
  44. * @author Jason
  45. */
  46. public class LdapAuthenticationProvider implements AuthenticationProvider {
  47.  
  48. private LdapAuthenticator authenticator;
  49.  
  50. public Authentication authenticate(Authentication auth) throws AuthenticationException {
  51.  
  52. // Authenticate, using the passed-in credentials.
  53. DirContextOperations authAdapter = authenticator.authenticate(auth);
  54.  
  55. // Creating an LdapAuthenticationToken (rather than using the existing Authentication
  56. // object) allows us to add the already-created LDAP context for our app to use later.
  57. LdapAuthenticationToken ldapAuth = new LdapAuthenticationToken(auth, "ROLE_USER");
  58. InitialLdapContext ldapContext = (InitialLdapContext) authAdapter
  59. .getObjectAttribute("ldapContext");
  60. if (ldapContext != null) {
  61. ldapAuth.setContext(ldapContext);
  62. }
  63.  
  64. return ldapAuth;
  65. }
  66.  
  67. public boolean supports(Class clazz) {
  68. return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(clazz));
  69. }
  70.  
  71. public LdapAuthenticator getAuthenticator() {
  72. return authenticator;
  73. }
  74.  
  75. public void setAuthenticator(LdapAuthenticator authenticator) {
  76. this.authenticator = authenticator;
  77. }
  78.  
  79. }
  80.  
  81. /**
  82. * Custom Spring Security LDAP authenticator which tries to bind to an LDAP server using the
  83. * passed-in credentials; does <strong>not</strong> require "master" credentials for an
  84. * initial bind prior to searching for the passed-in username.
  85. *
  86. * @author Jason
  87. */
  88. public class LdapAuthenticatorImpl implements LdapAuthenticator {
  89.  
  90. private DefaultSpringSecurityContextSource contextFactory;
  91. private String principalPrefix = "";
  92.  
  93. public DirContextOperations authenticate(Authentication authentication) {
  94.  
  95. // Grab the username and password out of the authentication object.
  96. String principal = principalPrefix + authentication.getName();
  97. String password = "";
  98. if (authentication.getCredentials() != null) {
  99. password = authentication.getCredentials().toString();
  100. }
  101.  
  102. // If we have a valid username and password, try to authenticate.
  103. if (!("".equals(principal.trim())) && !("".equals(password.trim()))) {
  104. InitialLdapContext ldapContext = (InitialLdapContext) contextFactory
  105. .getReadWriteContext(principal, password);
  106.  
  107. // We need to pass the context back out, so that the auth provider can add it to the
  108. // Authentication object.
  109. DirContextOperations authAdapter = new DirContextAdapter();
  110. authAdapter.addAttributeValue("ldapContext", ldapContext);
  111.  
  112. return authAdapter;
  113. } else {
  114. throw new BadCredentialsException("Blank username and/or password!");
  115. }
  116. }
  117.  
  118. /**
  119. * Since the InitialLdapContext that's stored as a property of an LdapAuthenticationToken is
  120. * transient (because it isn't Serializable), we need some way to recreate the
  121. * InitialLdapContext if it's null (e.g., if the LdapAuthenticationToken has been serialized
  122. * and deserialized). This is that mechanism.
  123. *
  124. * @param authenticator
  125. * the LdapAuthenticator instance from your application's context
  126. * @param auth
  127. * the LdapAuthenticationToken in which to recreate the InitialLdapContext
  128. * @return
  129. */
  130. static public InitialLdapContext recreateLdapContext(LdapAuthenticator authenticator,
  131. LdapAuthenticationToken auth) {
  132. DirContextOperations authAdapter = authenticator.authenticate(auth);
  133. InitialLdapContext context = (InitialLdapContext) authAdapter
  134. .getObjectAttribute("ldapContext");
  135. auth.setContext(context);
  136. return context;
  137. }
  138.  
  139. public DefaultSpringSecurityContextSource getContextFactory() {
  140. return contextFactory;
  141. }
  142.  
  143. /**
  144. * Set the context factory to use for generating a new LDAP context.
  145. *
  146. * @param contextFactory
  147. */
  148. public void setContextFactory(DefaultSpringSecurityContextSource contextFactory) {
  149. this.contextFactory = contextFactory;
  150. }
  151.  
  152. public String getPrincipalPrefix() {
  153. return principalPrefix;
  154. }
  155.  
  156. /**
  157. * Set the string to be prepended to all principal names prior to attempting authentication
  158. * against the LDAP server. (For example, if the Active Directory wants the domain-name-plus
  159. * backslash prepended, use this.)
  160. *
  161. * @param principalPrefix
  162. */
  163. public void setPrincipalPrefix(String principalPrefix) {
  164. if (principalPrefix != null) {
  165. this.principalPrefix = principalPrefix;
  166. } else {
  167. this.principalPrefix = "";
  168. }
  169. }
  170.  
  171. }
  172.  
  173. /**
  174. * <p>
  175. * Authentication token to use when an app needs further access to the LDAP context used to
  176. * authenticate the user.
  177. * </p>
  178. *
  179. * <p>
  180. * When this is the Authentication object stored in the Spring Security context, an application
  181. * can retrieve the current LDAP context thusly:
  182. * </p>
  183. *
  184. * <pre>
  185. * LdapAuthenticationToken ldapAuth = (LdapAuthenticationToken) SecurityContextHolder
  186. * .getContext().getAuthentication();
  187. * InitialLdapContext ldapContext = ldapAuth.getContext();
  188. * </pre>
  189. *
  190. * @author Jason
  191. *
  192. */
  193. public class LdapAuthenticationToken extends AbstractAuthenticationToken {
  194.  
  195. private static final long serialVersionUID = -5040340622950665401L;
  196.  
  197. private Authentication auth;
  198. transient private InitialLdapContext context;
  199. private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
  200.  
  201. /**
  202. * Construct a new LdapAuthenticationToken, using an existing Authentication object and
  203. * granting all users a default authority.
  204. *
  205. * @param auth
  206. * @param defaultAuthority
  207. */
  208. public LdapAuthenticationToken(Authentication auth, GrantedAuthority defaultAuthority) {
  209. this.auth = auth;
  210. if (auth.getAuthorities() != null) {
  211. this.authorities.addAll(Arrays.asList(auth.getAuthorities()));
  212. }
  213. if (defaultAuthority != null) {
  214. this.authorities.add(defaultAuthority);
  215. }
  216. super.setAuthenticated(true);
  217. }
  218.  
  219. /**
  220. * Construct a new LdapAuthenticationToken, using an existing Authentication object and
  221. * granting all users a default authority.
  222. *
  223. * @param auth
  224. * @param defaultAuthority
  225. */
  226. public LdapAuthenticationToken(Authentication auth, String defaultAuthority) {
  227. this(auth, new GrantedAuthorityImpl(defaultAuthority));
  228. }
  229.  
  230. public GrantedAuthority[] getAuthorities() {
  231. GrantedAuthority[] authoritiesArray = this.authorities.toArray(new GrantedAuthority[0]);
  232. return authoritiesArray;
  233. }
  234.  
  235. public void addAuthority(GrantedAuthority authority) {
  236. this.authorities.add(authority);
  237. }
  238.  
  239. public Object getCredentials() {
  240. return auth.getCredentials();
  241. }
  242.  
  243. public Object getPrincipal() {
  244. return auth.getPrincipal();
  245. }
  246.  
  247. /**
  248. * Retrieve the LDAP context attached to this user's authentication object.
  249. *
  250. * @return the LDAP context
  251. */
  252. public InitialLdapContext getContext() {
  253. return context;
  254. }
  255.  
  256. /**
  257. * Attach an LDAP context to this user's authentication object.
  258. *
  259. * @param context
  260. * the LDAP context
  261. */
  262. public void setContext(InitialLdapContext context) {
  263. this.context = context;
  264. }
  265.  
  266. }
Add Comment
Please, Sign In to add comment