1 /*
   2  * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @test
  26  * @author Vincent Ryan
  27  * @bug 4814522
  28  * @summary Check that an LdapLoginModule can be initialized using various
  29  *          JAAS configurations.
  30  *          (LdapLoginModule replaces the JndiLoginModule for LDAP access)
  31  *
  32  * Run this test twice, once using the default security manager:
  33  *
  34  * @run main/othervm CheckConfigs
  35  * @run main/othervm/policy=CheckConfigs.policy CheckConfigs
  36  */
  37 
  38 import java.io.IOException;
  39 import java.util.Collections;
  40 import java.util.Map;
  41 import java.util.HashMap;
  42 
  43 import javax.naming.CommunicationException;
  44 import javax.security.auth.*;
  45 import javax.security.auth.login.*;
  46 import javax.security.auth.callback.*;
  47 import com.sun.security.auth.module.LdapLoginModule;
  48 
  49 public class CheckConfigs {
  50 
  51     public static void main(String[] args) throws Exception {
  52         SecurityManager securityManager = System.getSecurityManager();
  53         System.out.println(securityManager == null
  54             ? "[security manager is not running]"
  55             : "[security manager is running: " +
  56                 securityManager.getClass().getName() + "]");
  57         init();
  58         checkConfigModes();
  59     }
  60 
  61     private static void init() throws Exception {
  62     }
  63 
  64     private static void checkConfigModes() throws Exception {
  65 
  66         LoginContext ldapLogin;
  67 
  68         // search-first mode
  69         System.out.println("Testing search-first mode...");
  70         try {
  71             ldapLogin = new LoginContext(LdapConfiguration.LOGIN_CONFIG_NAME,
  72                 null, new TestCallbackHandler(), new SearchFirstMode());
  73             ldapLogin.login();
  74             throw new SecurityException("expected a LoginException");
  75 
  76         } catch (LoginException le) {
  77             // expected behaviour (because no LDAP server is available)
  78             if (!(le.getCause() instanceof CommunicationException)) {
  79                 throw le;
  80             }
  81         }
  82 
  83         // authentication-first mode
  84         System.out.println("\nTesting authentication-first mode...");
  85         try {
  86             ldapLogin = new LoginContext(LdapConfiguration.LOGIN_CONFIG_NAME,
  87                 null, new TestCallbackHandler(), new AuthFirstMode());
  88             ldapLogin.login();
  89             throw new SecurityException("expected a LoginException");
  90 
  91         } catch (LoginException le) {
  92             // expected behaviour (because no LDAP server is available)
  93             if (!(le.getCause() instanceof CommunicationException)) {
  94                 throw le;
  95             }
  96         }
  97 
  98         // authentication-only mode
  99         System.out.println("\nTesting authentication-only mode...");
 100         try {
 101             ldapLogin = new LoginContext(LdapConfiguration.LOGIN_CONFIG_NAME,
 102                 null, new TestCallbackHandler(), new AuthOnlyMode());
 103             ldapLogin.login();
 104             throw new SecurityException("expected a LoginException");
 105 
 106         } catch (LoginException le) {
 107             // expected behaviour (because no LDAP server is available)
 108             if (!(le.getCause() instanceof CommunicationException)) {
 109                 throw le;
 110             }
 111         }
 112     }
 113 
 114     private static class TestCallbackHandler implements CallbackHandler {
 115 
 116         public void handle(Callback[] callbacks)
 117                 throws IOException, UnsupportedCallbackException {
 118 
 119             for (int i = 0; i < callbacks.length; i++) {
 120                 if (callbacks[i] instanceof NameCallback) {
 121                     ((NameCallback)callbacks[i]).setName("myname");
 122 
 123                 } else if (callbacks[i] instanceof PasswordCallback) {
 124                     ((PasswordCallback)callbacks[i])
 125                         .setPassword("mypassword".toCharArray());
 126 
 127                 } else {
 128                     throw new UnsupportedCallbackException
 129                         (callbacks[i], "Unrecognized callback");
 130                 }
 131             }
 132         }
 133     }
 134 }
 135 
 136 class LdapConfiguration extends Configuration {
 137 
 138     // The JAAS configuration name for ldap-based authentication
 139     public static final String LOGIN_CONFIG_NAME = "TestAuth";
 140 
 141     // The JAAS configuration for ldap-based authentication
 142     protected static AppConfigurationEntry[] entries;
 143 
 144     // The classname of the login module for ldap-based authentication
 145     protected static final String LDAP_LOGIN_MODULE =
 146         LdapLoginModule.class.getName();
 147 
 148     /**
 149      * Gets the JAAS configuration for ldap-based authentication
 150      */
 151     public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
 152         return name.equals(LOGIN_CONFIG_NAME) ? entries : null;
 153     }
 154 
 155     /**
 156      * Refreshes the configuration.
 157      */
 158     public void refresh() {
 159         // the configuration is fixed
 160     }
 161 }
 162 
 163 /**
 164  * This class defines the JAAS configuration for ldap-based authentication.
 165  * It is equivalent to the following textual configuration entry:
 166  * <pre>
 167  *     TestAuth {
 168  *         com.sun.security.auth.module.LdapLoginModule REQUIRED
 169  *             userProvider="ldap://localhost:23456/dc=example,dc=com"
 170  *             userFilter="(&(uid={USERNAME})(objectClass=inetOrgPerson))"
 171  *             authzIdentity="{EMPLOYEENUMBER}"
 172  *             debug=true;
 173  *     };
 174  * </pre>
 175  */
 176 class SearchFirstMode extends LdapConfiguration {
 177 
 178     public SearchFirstMode() {
 179         super();
 180 
 181         Map<String, String> options = new HashMap<>(4);
 182         options.put("userProvider", "ldap://localhost:23456/dc=example,dc=com");
 183         options.put("userFilter",
 184             "(&(uid={USERNAME})(objectClass=inetOrgPerson))");
 185         options.put("authzIdentity", "{EMPLOYEENUMBER}");
 186         options.put("debug", "true");
 187 
 188         entries = new AppConfigurationEntry[] {
 189             new AppConfigurationEntry(LDAP_LOGIN_MODULE,
 190                 AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
 191                     options)
 192         };
 193     }
 194 
 195 }
 196 
 197 /**
 198  * This class defines the JAAS configuration for ldap-based authentication.
 199  * It is equivalent to the following textual configuration entry:
 200  * <pre>
 201  *     TestAuth {
 202  *         com.sun.security.auth.module.LdapLoginModule REQUIRED
 203  *             userProvider="ldap://localhost:23456/dc=example,dc=com"
 204  *             authIdentity="{USERNAME}"
 205  *             userFilter="(&(|(samAccountName={USERNAME})(userPrincipalName={USERNAME})(cn={USERNAME}))(objectClass=user))"
 206  *             useSSL=false
 207  *             debug=true;
 208  *     };
 209  * </pre>
 210  */
 211 class AuthFirstMode extends LdapConfiguration {
 212 
 213     public AuthFirstMode() {
 214         super();
 215 
 216         Map<String, String> options = new HashMap<>(5);
 217         options.put("userProvider", "ldap://localhost:23456/dc=example,dc=com");
 218         options.put("authIdentity", "{USERNAME}");
 219         options.put("userFilter",
 220             "(&(|(samAccountName={USERNAME})(userPrincipalName={USERNAME})" +
 221             "(cn={USERNAME}))(objectClass=user))");
 222         options.put("useSSL", "false");
 223         options.put("debug", "true");
 224 
 225         entries = new AppConfigurationEntry[] {
 226             new AppConfigurationEntry(LDAP_LOGIN_MODULE,
 227                 AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
 228                     options)
 229         };
 230     }
 231 }
 232 
 233 /**
 234  * This class defines the JAAS configuration for ldap-based authentication.
 235  * It is equivalent to the following textual configuration entry:
 236  * <pre>
 237  *     TestAuth {
 238  *         com.sun.security.auth.module.LdapLoginModule REQUIRED
 239  *             userProvider="ldap://localhost:23456 ldap://localhost:23457"
 240  *             authIdentity="cn={USERNAME},ou=people,dc=example,dc=com"
 241  *             authzIdentity="staff"
 242  *             debug=true;
 243  *     };
 244  * </pre>
 245  */
 246 class AuthOnlyMode extends LdapConfiguration {
 247 
 248     public AuthOnlyMode() {
 249         super();
 250 
 251         Map<String, String> options = new HashMap<>(4);
 252         options.put("userProvider",
 253             "ldap://localhost:23456 ldap://localhost:23457");
 254         options.put("authIdentity",
 255             "cn={USERNAME},ou=people,dc=example,dc=com");
 256         options.put("authzIdentity", "staff");
 257         options.put("debug", "true");
 258 
 259         entries = new AppConfigurationEntry[] {
 260             new AppConfigurationEntry(LDAP_LOGIN_MODULE,
 261                 AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
 262                     options)
 263         };
 264     }
 265 
 266 }