1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package org.apache.harmony.auth.tests.module; 19 20import java.io.IOException; 21import java.security.Principal; 22import java.util.HashMap; 23import java.util.Set; 24 25import javax.security.auth.Subject; 26import javax.security.auth.callback.Callback; 27import javax.security.auth.callback.CallbackHandler; 28import javax.security.auth.callback.NameCallback; 29import javax.security.auth.callback.PasswordCallback; 30import javax.security.auth.callback.UnsupportedCallbackException; 31import javax.security.auth.login.LoginException; 32 33import junit.framework.TestCase; 34 35import org.apache.harmony.auth.module.LdapLoginModule; 36import org.apache.harmony.auth.UserPrincipal; 37 38 39public class LdapLoginModuleTest extends TestCase { 40 41 // module options 42 private HashMap<String, String> options = new HashMap<String, String>(); 43 44 private final String USER_PROVIDER_URL = "ldap://9.181.106.121:389/ou=People,o=JNDITutorial,dc=my-domain,dc=com"; 45 46 protected void setUp() throws Exception { 47 options.put("userProvider", USER_PROVIDER_URL); 48 options.put("useSSL", "false"); 49 } 50 51 @Override 52 protected void tearDown() throws Exception { 53 options.clear(); 54 } 55 56 /** 57 * Test method for {@link org.apache.harmony.auth.module.LdapLoginModule#abort()}. 58 */ 59 public void test_abort() throws LoginException{ 60 LdapLoginModule jlm = new LdapLoginModule(); 61 try { 62 assertFalse("Should return false if login failed or no login", jlm 63 .abort()); 64 } catch (LoginException e) { 65 fail("Abort failed"); 66 } 67 Subject subject = new Subject(); 68 subject.setReadOnly(); 69 jlm.initialize(subject, null, null, options); 70 try { 71 assertFalse("Should return false if login failed or no login", jlm 72 .abort()); 73 } catch (Exception e) { 74 fail("Not any exception here"); 75 } 76 subject = new Subject(); 77 jlm.initialize(subject, new FaultCallbackHandler(), null, options); 78 try { 79 jlm.login(); 80 fail("login should fail"); 81 } catch (LoginException e) { 82 assertFalse("Should return false because of login failure", jlm 83 .abort()); 84 } 85 subject = new Subject(); 86 options.put("authIdentity","cn=Manager,dc=my-domain,dc=com"); 87 jlm.initialize(subject, new MockCallbackHandler(), null, options); 88 jlm.login(); 89 assertTrue("Should return true if login was successful", jlm 90 .abort()); 91 } 92 93 /** 94 * Test method for {@link org.apache.harmony.auth.module.LdapLoginModule#commit()}. 95 */ 96 public void test_commit() { 97 LdapLoginModule module = new LdapLoginModule(); 98 Subject subject = new Subject(); 99 options.put("authIdentity","cn=Manager,dc=my-domain,dc=com"); 100 module.initialize(subject, new MockCallbackHandler(), null, options); 101 try { 102 assertTrue("Login should be successful", module.login()); 103 module.commit(); 104 } catch (LoginException e) { 105 fail("Login shouldn't fail"); 106 } 107 Set<Principal> principals = subject.getPrincipals(); 108 assertFalse("Should get at least one principal", principals.isEmpty()); 109 subject = new Subject(); 110 subject.setReadOnly(); 111 module.initialize(subject, new MockCallbackHandler(), null, options); 112 try { 113 assertFalse("Commit shouldn't be successful", module.commit()); 114 fail("Should throw LoginException here because of trying to clear read-only subject"); 115 } catch (LoginException e) { 116 // expected LoginException here 117 } 118 } 119 120 /** 121 * Test method for {@link org.apache.harmony.auth.module.LdapLoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)}. 122 */ 123 public void test_initialize() { 124 LdapLoginModule module = new LdapLoginModule(); 125 try { 126 module.initialize(null, null, null, null); 127 fail("Should throw NullPointerException here."); 128 } catch (NullPointerException e) { 129 // expected NullPointerException 130 } 131 } 132 133 /** 134 * Test method for {@link org.apache.harmony.auth.module.LdapLoginModule#login()}. 135 */ 136 public void test_login() { 137 LdapLoginModule module = new LdapLoginModule(); 138 HashMap<String, String> emptyOptions = new HashMap<String, String>(); 139 module.initialize(null, new MockCallbackHandler(), null, emptyOptions); 140 try { 141 module.login(); 142 fail("Should throw LoginException here."); 143 } catch (LoginException e) { 144 // expected LoginException 145 } 146 147 options.put("authIdentity","cn=Manager,dc=my-domain,dc=com"); 148 Subject subject = new Subject(); 149 module.initialize(subject, new MockCallbackHandler(), null, options); 150 try { 151 assertTrue("Login should be successful", module.login()); 152 } catch (LoginException e) { 153 fail("Login shouldn't fail"); 154 } 155 module.initialize(subject, new FaultCallbackHandler(), null, options); 156 try { 157 assertFalse("Login shouldn't be successful", module.login()); 158 fail("Login should fail"); 159 } catch (LoginException e) { 160 // expected Loginexception here 161 } 162 } 163 164 /** 165 * Test method for {@link org.apache.harmony.auth.module.LdapLoginModule#logout()}. 166 */ 167 public void test_logout() { 168 LdapLoginModule module = new LdapLoginModule(); 169 Subject subject = new Subject(); 170 options.put("authIdentity","cn=Manager,dc=my-domain,dc=com"); 171 module.initialize(subject, new MockCallbackHandler(), null, options); 172 try { 173 assertTrue("Login should be successful", module.login()); 174 module.commit(); 175 } catch (LoginException e) { 176 fail("Login shouldn't fail"); 177 } 178 Set<Principal> principals = subject.getPrincipals(); 179 assertFalse("Should get at least one principal", principals.isEmpty()); 180 try { 181 assertTrue("Should be true", module.logout()); 182 } catch (LoginException e) { 183 fail("Logout failed"); 184 } 185 principals = subject.getPrincipals(); 186 assertTrue("Principals should be cleared", principals.isEmpty()); 187 } 188 189 public void test_optionsAndSharedStatus() throws LoginException{ 190 options.put("authIdentity","cn=Manager,dc=my-domain,dc=com"); 191 options.put("authzIdentity","testAuthzIdentityOption"); 192 LdapLoginModule module = new LdapLoginModule(); 193 Subject subject = new Subject(); 194 module.initialize(subject, new MockCallbackHandler(), null, options); 195 try { 196 module.login(); 197 module.commit(); 198 assertTrue("Should get a principal from authzIdentity option",subject.getPrincipals().contains(new UserPrincipal("testAuthzIdentityOption"))); 199 } 200 catch(LoginException e){ 201 fail("Login failed"); 202 } 203 finally{ 204 module.logout(); 205 } 206 207 options.put("debug", "true"); 208 options.put("useFirstPass", "true"); 209 HashMap<String, Object> status = new HashMap<String,Object>(); 210 status.put("javax.security.auth.login.name", "leo"); 211 status.put("javax.security.auth.login.password", "faultPass".toCharArray()); 212 subject = new Subject(); 213 module.initialize(subject, new MockCallbackHandler(), status, options); 214 try { 215 module.login(); 216 fail("Should be failed for using password from shared state"); 217 } 218 catch(LoginException e){ 219 //expected LoginException here 220 } 221 222 options.remove("useFirstPass"); 223 options.put("tryFirstPass", "true"); 224 module.initialize(subject, new MockCallbackHandler(), status, options); 225 try { 226 module.login(); 227 module.commit(); 228 } 229 catch(LoginException e){ 230 fail("Login should be failed"); 231 } 232 finally{ 233 module.logout(); 234 } 235 236 options.remove("tryFirstPass"); 237 options.put("clearPass", "true"); 238 status.put("javax.security.auth.login.name", "leo"); 239 status.put("javax.security.auth.login.password", "passw0rd".toCharArray()); 240 module.initialize(subject, new MockCallbackHandler(), status, options); 241 try { 242 module.login(); 243 module.commit(); 244 assertNull("javax.security.auth.login.name in shared state should be null when clearPass switch on",status.get("javax.security.auth.login.name")); 245 assertNull("javax.security.auth.login.password in shared state should be null when clearPass switch on",status.get("javax.security.auth.login.password")); 246 } catch (LoginException e) { 247 fail("Login shouldn't fail"); 248 } 249 finally{ 250 module.logout(); 251 } 252 253 status = new HashMap<String,Object>(); 254 options.remove("clearPass"); 255 options.put("storePass", "true"); 256 module.initialize(subject, new FaultCallbackHandler(), status, options); 257 try { 258 module.login(); 259 module.commit(); 260 } catch (LoginException e) { 261 assertNull("javax.security.auth.login.name in shared state should be null when login failed",status.get("javax.security.auth.login.name")); 262 assertNull("javax.security.auth.login.password in shared state should be null when login failed",status.get("javax.security.auth.login.password")); 263 } 264 finally{ 265 module.logout(); 266 } 267 268 module.initialize(subject, new MockCallbackHandler(), status, options); 269 try { 270 module.login(); 271 module.commit(); 272 } catch (LoginException e) { 273 fail("Login failed"); 274 } 275 finally{ 276 module.logout(); 277 } 278 assertNotNull("javax.security.auth.login.name should be stored in shared state when storePass switch on",status.get("javax.security.auth.login.name")); 279 assertNotNull("javax.security.auth.login.password should be stored in shared state when storePass switch on",status.get("javax.security.auth.login.password")); 280 281 status.put("javax.security.auth.login.name", "tester"); 282 status.put("javax.security.auth.login.password", "testerPass"); 283 module.initialize(subject, new MockCallbackHandler(), status, options); 284 try { 285 module.login(); 286 module.commit(); 287 } catch (LoginException e) { 288 fail("Login failed"); 289 } 290 finally{ 291 module.logout(); 292 } 293 assertEquals("Should't override the username value in sharedState",status.get("javax.security.auth.login.name"),"tester"); 294 assertEquals("Should't override the password value in sharedState",status.get("javax.security.auth.login.password"),"testerPass"); 295 } 296 297 static private class MockCallbackHandler implements CallbackHandler{ 298 299 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { 300 for(int i=0;i<callbacks.length;i++){ 301 if(callbacks[i] instanceof NameCallback){ 302 NameCallback nc = (NameCallback)callbacks[i]; 303 nc.setName("leo"); 304 } 305 else if(callbacks[i] instanceof PasswordCallback){ 306 PasswordCallback pc = (PasswordCallback)callbacks[i]; 307 pc.setPassword("secret".toCharArray()); 308 } 309 else 310 { 311 throw new Error(callbacks[i].getClass().toString()); 312 } 313 } 314 } 315 } 316 317 static private class FaultCallbackHandler implements CallbackHandler{ 318 319 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { 320 for(int i=0;i<callbacks.length;i++){ 321 if(callbacks[i] instanceof NameCallback){ 322 NameCallback nc = (NameCallback)callbacks[i]; 323 nc.setName("leo"); 324 } 325 else if(callbacks[i] instanceof PasswordCallback){ 326 PasswordCallback pc = (PasswordCallback)callbacks[i]; 327 pc.setPassword("password".toCharArray()); 328 } 329 else 330 { 331 throw new Error(callbacks[i].getClass().toString()); 332 } 333 } 334 } 335 } 336} 337