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