View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.shiro.realm.ldap;
20  
21  import org.apache.shiro.authc.AuthenticationException;
22  import org.apache.shiro.authc.AuthenticationToken;
23  import org.apache.shiro.authc.UsernamePasswordToken;
24  import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
25  import org.junit.Before;
26  import org.junit.Test;
27  
28  import javax.naming.NamingException;
29  import javax.naming.ldap.LdapContext;
30  
31  import java.util.UUID;
32  
33  import static org.easymock.EasyMock.*;
34  import static org.junit.Assert.*;
35  
36  /**
37   * Tests for the {@link DefaultLdapRealm} class.
38   *
39   * @since 1.3
40   */
41  @SuppressWarnings({"ThrowableInstanceNeverThrown"})
42  public class DefaultLdapRealmTest {
43  
44      private DefaultLdapRealm realm;
45  
46      // this method can be collapsed back into setUp once the JndiLdapRealm has been removed in 2.0
47      protected DefaultLdapRealm getNewRealmUnderTest() {
48          return new DefaultLdapRealm();
49      }
50  
51      @Before
52      public void setUp() {
53          realm = getNewRealmUnderTest();
54      }
55  
56      @Test
57      public void testDefaultInstance() {
58          assertTrue(realm.getCredentialsMatcher() instanceof AllowAllCredentialsMatcher);
59          assertEquals(AuthenticationToken.class, realm.getAuthenticationTokenClass());
60          assertTrue(realm.getContextFactory() instanceof JndiLdapContextFactory);
61      }
62  
63      @Test(expected=IllegalArgumentException.class)
64      public void testSetUserDnTemplateNull() {
65          realm.setUserDnTemplate(null);
66      }
67      
68      @Test(expected=IllegalArgumentException.class)
69      public void testSetUserDnTemplateEmpty() {
70          realm.setUserDnTemplate("  ");
71      }
72  
73      @Test(expected=IllegalArgumentException.class)
74      public void testSetUserDnTemplateWithoutToken() {
75          realm.setUserDnTemplate("uid=,ou=users,dc=mycompany,dc=com");
76      }
77  
78      @Test
79      public void testUserDnTemplate() {
80          String template = "uid={0},ou=users,dc=mycompany,dc=com";
81          realm.setUserDnTemplate(template);
82          assertEquals(template, realm.getUserDnTemplate());
83      }
84  
85      @Test
86      public void testUserDnTemplateSubstitution() throws NamingException {
87          realm.setUserDnTemplate("uid={0},ou=users,dc=mycompany,dc=com");
88          LdapContextFactory factory = createMock(LdapContextFactory.class);
89          realm.setContextFactory(factory);
90  
91          Object expectedPrincipal = "uid=jsmith,ou=users,dc=mycompany,dc=com";
92  
93          expect(factory.getLdapContext(eq(expectedPrincipal), isA(Object.class))).andReturn(createNiceMock(LdapContext.class));
94          replay(factory);
95  
96          realm.getAuthenticationInfo(new UsernamePasswordToken("jsmith", "secret") );
97          verify(factory);
98      }
99  
100     @Test(expected= AuthenticationException.class)
101     public void testGetAuthenticationInfoNamingAuthenticationException() throws NamingException {
102         realm.setUserDnTemplate("uid={0},ou=users,dc=mycompany,dc=com");
103         LdapContextFactory factory = createMock(LdapContextFactory.class);
104         realm.setContextFactory(factory);
105 
106         expect(factory.getLdapContext(isA(Object.class), isA(Object.class)))
107                 .andThrow(new javax.naming.AuthenticationException("LDAP Authentication failed."));
108         replay(factory);
109 
110         realm.getAuthenticationInfo(new UsernamePasswordToken("jsmith", "secret") );
111     }
112 
113     @Test(expected= AuthenticationException.class)
114     public void testGetAuthenticationInfoNamingException() throws NamingException {
115         realm.setUserDnTemplate("uid={0},ou=users,dc=mycompany,dc=com");
116         LdapContextFactory factory = createMock(LdapContextFactory.class);
117         realm.setContextFactory(factory);
118 
119         expect(factory.getLdapContext(isA(Object.class), isA(Object.class)))
120                 .andThrow(new NamingException("Communication error."));
121         replay(factory);
122 
123         realm.getAuthenticationInfo(new UsernamePasswordToken("jsmith", "secret") );
124     }
125 
126     /**
127      * This test simulates that if a non-String principal (i.e. not a username) is passed as the LDAP principal, that
128      * it is not altered into a User DN and is passed as-is.  This will allow principals to be things like X.509
129      * certificates as well instead of only strings.
130      *
131      * @throws NamingException not thrown
132      */
133     @Test
134     public void testGetAuthenticationInfoNonSimpleToken() throws NamingException {
135         realm.setUserDnTemplate("uid={0},ou=users,dc=mycompany,dc=com");
136         LdapContextFactory factory = createMock(LdapContextFactory.class);
137         realm.setContextFactory(factory);
138 
139         final UUID userId = UUID.randomUUID();
140 
141         //ensure the userId is passed as-is:
142         expect(factory.getLdapContext(eq(userId), isA(Object.class))).andReturn(createNiceMock(LdapContext.class));
143         replay(factory);
144 
145         realm.getAuthenticationInfo(new AuthenticationToken() {
146             public Object getPrincipal() {
147                 return userId;
148             }
149 
150             public Object getCredentials() {
151                 return "secret";
152             }
153         });
154         verify(factory);
155     }
156 
157     @Test(expected=IllegalArgumentException.class)
158     public void testGetUserDnNullArgument() {
159         realm.getUserDn(null);
160     }
161 
162     @Test
163     public void testGetUserDnWithOutPrefixAndSuffix() {
164         realm = new DefaultLdapRealm() {
165             @Override
166             protected String getUserDnPrefix() {
167                 return null;
168             }
169 
170             @Override
171             protected String getUserDnSuffix() {
172                 return null;
173             }
174         };
175         String principal = "foo";
176         String userDn = realm.getUserDn(principal);
177         assertEquals(principal, userDn);
178     }
179 }