1 // ======================================================================== 2 // Copyright 2007 Mort Bay Consulting Pty. Ltd. 3 // ------------------------------------------------------------------------ 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 // ======================================================================== 14 15 package org.mortbay.jetty.plus.jaas.spi; 16 17 import org.apache.directory.shared.ldap.util.Base64; 18 import org.apache.directory.shared.ldap.exception.LdapNameNotFoundException; 19 import org.codehaus.plexus.PlexusTestCase; 20 import org.codehaus.plexus.apacheds.ApacheDs; 21 import org.mortbay.jetty.security.Credential; 22 import org.mortbay.jetty.plus.jaas.callback.DefaultCallbackHandler; 23 import org.mortbay.jetty.plus.jaas.JAASRole; 24 25 import javax.naming.NamingEnumeration; 26 import javax.naming.NamingException; 27 import javax.naming.directory.Attribute; 28 import javax.naming.directory.Attributes; 29 import javax.naming.directory.BasicAttribute; 30 import javax.naming.directory.BasicAttributes; 31 import javax.naming.directory.DirContext; 32 import javax.naming.directory.InitialDirContext; 33 import javax.naming.directory.SearchControls; 34 import javax.naming.directory.SearchResult; 35 import javax.security.auth.Subject; 36 import java.util.HashMap; 37 import java.util.Map; 38 import java.util.Set; 39 40 public class LdapLoginModuleTest extends PlexusTestCase 41 { 42 private ApacheDs apacheDs; 43 44 private String suffix; 45 setUp()46 protected void setUp() 47 throws Exception 48 { 49 super.setUp(); 50 51 apacheDs = (ApacheDs)lookup(ApacheDs.ROLE, "test" ); 52 53 suffix = apacheDs.addSimplePartition( "test", new String[]{"jetty", "mortbay", "org"} ).getSuffix(); 54 55 System.out.println( "DN Suffix: " + suffix ); 56 57 apacheDs.startServer(); 58 59 makeUsers(); 60 } 61 tearDown()62 protected void tearDown() throws Exception 63 { 64 InitialDirContext context = apacheDs.getAdminContext(); 65 66 unbind(context, createDn( "ldap-admin" ) ); 67 unbind(context, createDn( "jesse" ) ); 68 69 apacheDs.stopServer(); 70 71 super.tearDown(); 72 } 73 testNothing()74 public void testNothing() throws Exception 75 { 76 } 77 78 BindingAuth()79 public void /*test*/BindingAuth() throws Exception 80 { 81 LdapLoginModule lm = new LdapLoginModule(); 82 83 Map options = new HashMap(); 84 options.put( "hostname", "localhost" ); 85 options.put( "port", "10390" ); 86 options.put( "contextFactory", "com.sun.jndi.ldap.LdapCtxFactory" ); 87 options.put( "bindDn", "uid=admin,ou=system" ); 88 options.put( "bindPassword", "secret" ); 89 options.put( "userBaseDn", "dc=jetty,dc=mortbay,dc=org" ); 90 options.put( "roleBaseDn", "dc=jetty,dc=mortbay,dc=org" ); 91 options.put( "roleNameAttribute", "cn" ); 92 options.put( "forceBindingLogin", "true" ); 93 options.put( "debug", "true" ); 94 95 Subject subject = new Subject(); 96 DefaultCallbackHandler callbackHandler = new DefaultCallbackHandler(); 97 callbackHandler.setUserName("jesse"); 98 callbackHandler.setCredential("foo"); 99 lm.initialize( subject, callbackHandler, null, options ); 100 101 assertTrue( lm.bindingLogin( "jesse", "foo" ) ); 102 103 assertTrue( lm.login() ); 104 assertTrue( lm.commit() ); 105 106 Set roles = subject.getPrincipals(JAASRole.class); 107 assertEquals(1, roles.size()); 108 assertTrue(roles.contains(new JAASRole("ldap-admin"))); 109 } 110 /* 111 public void testCredentialAuth() throws Exception 112 { 113 LdapLoginModule lm = new LdapLoginModule(); 114 115 Map options = new HashMap(); 116 options.put( "hostname", "localhost" ); 117 options.put( "port", "10390" ); 118 options.put( "contextFactory", "com.sun.jndi.ldap.LdapCtxFactory" ); 119 options.put( "bindDn", "uid=admin,ou=system" ); 120 options.put( "bindPassword", "secret" ); 121 options.put( "userBaseDn", "dc=jetty,dc=mortbay,dc=org" ); 122 options.put( "forceBindingLogin", "false" ); 123 124 125 lm.initialize( null, null, null, options ); 126 127 UserInfo info = lm.getUserInfo( "jesse" ); 128 129 assertTrue( lm.credentialLogin( info, "foo" ) ); 130 } 131 */ 132 133 // ----------------------------------------------------------------------- 134 // Private 135 // ----------------------------------------------------------------------- 136 makeUsers()137 private void makeUsers() throws Exception 138 { 139 InitialDirContext context = apacheDs.getAdminContext(); 140 141 unbind(context, createDn("ldap-admin")); 142 unbind(context, createDn( "jesse" ) ); 143 144 String jesse = bindUserObject( context, "jesse" ); 145 bindGroupObject( context, "ldap-admin", jesse ); 146 assertExist( context, "cn", "jesse" ); 147 } 148 bindUserObject(DirContext context, String cn)149 private String bindUserObject(DirContext context, String cn) 150 throws Exception 151 { 152 Attributes attributes = new BasicAttributes(true); 153 BasicAttribute objectClass = new BasicAttribute("objectClass"); 154 objectClass.add("top"); 155 objectClass.add("inetOrgPerson"); 156 objectClass.add("person"); 157 objectClass.add("organizationalperson"); 158 attributes.put(objectClass); 159 attributes.put("cn", cn); 160 attributes.put("sn", "foo"); 161 attributes.put("mail", "foo"); 162 //System.out.println("setting password to : " + LdapLoginModule.convertCredentialJettyToLdap( Credential.MD5.digest( "foo" ) )); 163 String pwd = Credential.MD5.digest( "foo" ); 164 pwd = pwd.substring("MD5:".length(), pwd.length() ); 165 //System.out.println(Credential.MD5.digest( "foo" )); 166 //System.out.println(pwd); 167 //System.out.println(Base64.encode( pwd.getBytes("ISO-8859-1") )); 168 //System.out.println(Base64.encode( pwd.getBytes("UTF-8") )); 169 attributes.put("userPassword", "{MD5}" + doStuff(pwd) ); 170 //attributes.put( "userPassword", "foo"); 171 attributes.put("givenName", "foo"); 172 String dn = createDn(cn); 173 context.createSubcontext(dn, attributes ); 174 return dn; 175 } 176 bindGroupObject(DirContext context, String cn, String initialMember)177 private void bindGroupObject(DirContext context, String cn, String initialMember) 178 throws Exception 179 { 180 Attributes attributes = new BasicAttributes(true); 181 BasicAttribute objectClass = new BasicAttribute("objectClass"); 182 objectClass.add("top"); 183 objectClass.add("groupOfUniqueNames"); 184 attributes.put(objectClass); 185 attributes.put("cn", cn); 186 attributes.put("uniqueMember", initialMember); 187 context.createSubcontext( createDn( cn ), attributes ); 188 } 189 doStuff( String hpwd )190 private String doStuff( String hpwd ) 191 { 192 String HEX_VAL = "0123456789abcdef"; 193 194 byte[] bpwd = new byte[hpwd.length()>>1]; 195 196 byte b = 0; 197 boolean high = true; 198 int pos = 0; 199 200 //for ( char c:hpwd.toCharArray() ) 201 for ( int i = 0 ; i < hpwd.toCharArray().length; ++i ) 202 { 203 char c = hpwd.toCharArray()[i]; 204 if ( high ) 205 { 206 high = false; 207 b = (byte)HEX_VAL.indexOf( c ); 208 } 209 else 210 { 211 high = true; 212 b <<= 4; 213 b += HEX_VAL.indexOf( c ); 214 bpwd[pos++] = b; 215 } 216 } 217 218 return new String( Base64.encode( bpwd ) ); 219 } 220 createDn( String cn )221 private String createDn( String cn ) 222 { 223 return "cn=" + cn + "," + suffix; 224 } 225 assertExist( DirContext context, String attribute, String value )226 private void assertExist( DirContext context, String attribute, String value ) throws NamingException 227 { 228 SearchControls ctls = new SearchControls(); 229 230 ctls.setDerefLinkFlag( true ); 231 ctls.setSearchScope( SearchControls.ONELEVEL_SCOPE ); 232 ctls.setReturningAttributes( new String[] { "*" } ); 233 234 BasicAttributes matchingAttributes = new BasicAttributes(); 235 matchingAttributes.put( attribute, value ); 236 BasicAttribute objectClass = new BasicAttribute("objectClass"); 237 objectClass.add("inetOrgPerson"); 238 matchingAttributes.put(objectClass); 239 240 NamingEnumeration results = context.search( suffix, matchingAttributes ); 241 // NamingEnumeration<SearchResult> results = context.search( suffix, "(" + attribute + "=" + value + ")", ctls 242 // ); 243 244 assertTrue( results.hasMoreElements() ); 245 SearchResult result = (SearchResult)results.nextElement(); 246 Attributes attrs = result.getAttributes(); 247 Attribute testAttr = attrs.get( attribute ); 248 assertEquals( value, testAttr.get() ); 249 } 250 unbind(InitialDirContext context, String dn)251 private void unbind(InitialDirContext context, String dn) throws NamingException { 252 try { 253 context.unbind(dn); 254 } catch (LdapNameNotFoundException e) { 255 // ignore 256 } 257 } 258 } 259