public SaslServerCallbackHandler(Configuration configuration) throws IOException { String serverSection = System.getProperty(ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY, ZooKeeperSaslServer.DEFAULT_LOGIN_CONTEXT_NAME); AppConfigurationEntry configurationEntries[] = configuration.getAppConfigurationEntry(serverSection); if (configurationEntries == null) { String errorMessage = "Could not find a 'Server' entry in this configuration: Server cannot start."; LOG.error(errorMessage); throw new IOException(errorMessage); } credentials.clear(); for(AppConfigurationEntry entry: configurationEntries) { Map<String,?> options = entry.getOptions(); // Populate DIGEST-MD5 user -> password map with JAAS configuration entries from the "Server" section. // Usernames are distinguished from other options by prefixing the username with a "user_" prefix. for(Map.Entry<String, ?> pair : options.entrySet()) { String key = pair.getKey(); if (key.startsWith(USER_PREFIX)) { String userName = key.substring(USER_PREFIX.length()); credentials.put(userName,(String)pair.getValue()); } } } }
/** * Gets the the specified AppConfigurationEntry from the login configuration * * @param loginModuleClass class name of loginModule to get * @return The configuredLoginModule value */ public static AppConfigurationEntry getConfiguredLoginModule(String loginModuleClass) { Configuration config = Configuration.getConfiguration(); try { if (loginModuleClass == null || loginModuleClass.trim().length() == 0) throw new Exception("no loginModuleClass provided"); if (config == null) throw new Exception("No configuration found"); AppConfigurationEntry[] entries = config.getAppConfigurationEntry("NCS"); if (entries == null) throw new Exception("No app config entries found"); for (int i = 0; i < entries.length; i++) { AppConfigurationEntry entry = entries[i]; String name = entry.getLoginModuleName(); if (loginModuleClass.equals(name)) return entry; } } catch (Throwable e) { prtlnErr("getConfiguredLoginModule WARNING: " + e.getMessage()); } return null; }
/** * A new instance of LoginConfigImpl must be created for each login request * since it's only used by a single (caller, mech) pair * @param caller defined in GSSUtil as CALLER_XXX final fields * @param oid defined in GSSUtil as XXX_MECH_OID final fields */ public LoginConfigImpl(GSSCaller caller, Oid mech) { this.caller = caller; if (mech.equals(GSSUtil.GSS_KRB5_MECH_OID)) { mechName = "krb5"; } else { throw new IllegalArgumentException(mech.toString() + " not supported"); } config = java.security.AccessController.doPrivileged (new java.security.PrivilegedAction <Configuration> () { public Configuration run() { return Configuration.getConfiguration(); } }); }
private String setJaasConfiguration(Properties config) throws Exception { String keytabFile = config.getProperty(ZOOKEEPER_KERBEROS_KEYTAB).trim(); if (keytabFile == null || keytabFile.length() == 0) { throw new IllegalArgumentException(ZOOKEEPER_KERBEROS_KEYTAB + " must be specified"); } String principal = config.getProperty(ZOOKEEPER_KERBEROS_PRINCIPAL) .trim(); if (principal == null || principal.length() == 0) { throw new IllegalArgumentException(ZOOKEEPER_KERBEROS_PRINCIPAL + " must be specified"); } // This is equivalent to writing a jaas.conf file and setting the system // property, "java.security.auth.login.config", to point to it JaasConfiguration jConf = new JaasConfiguration(JAAS_LOGIN_ENTRY_NAME, principal, keytabFile); Configuration.setConfiguration(jConf); return principal.split("[/@]")[0]; }
public static boolean isZkSecurityEnabled() { boolean zkSaslEnabled = Boolean.parseBoolean(System.getProperty(ZK_SASL_CLIENT, "true")); String zkLoginContextName = System.getProperty(ZK_LOGIN_CONTEXT_NAME_KEY, "Client"); boolean isSecurityEnabled; try { Configuration loginConf = Configuration.getConfiguration(); isSecurityEnabled = loginConf.getAppConfigurationEntry(zkLoginContextName) != null; } catch (Exception e) { throw new KafkaException("Exception while loading Zookeeper JAAS login context '" + zkLoginContextName + "'", e); } if (isSecurityEnabled && !zkSaslEnabled) { LOG.error("JAAS configuration is present, but system property " + ZK_SASL_CLIENT + " is set to false, which disables " + "SASL in the ZooKeeper client"); throw new KafkaException("Exception while determining if ZooKeeper is secure"); } return isSecurityEnabled; }
public static void testLogin(String confName, char[] passwd, Configuration cf, boolean expectException) { try { CallbackHandler ch = new MyCallbackHandler("testUser", passwd); LoginContext lc = new LoginContext(confName, new Subject(), ch, cf); lc.login(); if (expectException) { throw new RuntimeException("Login Test failed: " + "expected LoginException not thrown"); } } catch (LoginException le) { if (!expectException) { System.out.println("Login Test failed: " + "received Unexpected exception."); throw new RuntimeException(le); } } }
/** * A new instance of LoginConfigImpl must be created for each login request * since it's only used by a single (caller, mech) pair * @param caller defined in GSSUtil as CALLER_XXX final fields * @param mech defined in GSSUtil as XXX_MECH_OID final fields */ public LoginConfigImpl(GSSCaller caller, Oid mech) { this.caller = caller; if (mech.equals(GSSUtil.GSS_KRB5_MECH_OID)) { mechName = "krb5"; } else { throw new IllegalArgumentException(mech.toString() + " not supported"); } config = java.security.AccessController.doPrivileged (new java.security.PrivilegedAction <Configuration> () { public Configuration run() { return Configuration.getConfiguration(); } }); }
static void login(String test, String... conf) throws Exception { System.out.println("Testing " + test + "..."); StringBuilder sb = new StringBuilder(); sb.append("hello {\n"); for (int i=0; i<conf.length; i+=2) { sb.append(" com.sun.security.auth.module." + conf[i] + " " + conf[i+1] + ";\n"); } sb.append("};\n"); Files.write(Paths.get(test), sb.toString().getBytes()); // Must be called. Configuration has an internal static field. Configuration.setConfiguration(null); System.setProperty("java.security.auth.login.config", test); LoginContext lc = new LoginContext("hello"); lc.login(); System.out.println(lc.getSubject()); }
private int testDefault(int testnum) throws Exception { // get an instance of the default ConfigSpiFile Configuration c = Configuration.getInstance(JAVA_CONFIG, null); doTest(c, testnum++); // get an instance of FooConfig try { c = Configuration.getInstance("FooConfig", null); throw new SecurityException("test " + testnum++ + " failed"); } catch (NoSuchAlgorithmException nsae) { // good System.out.println("test " + testnum++ + " passed"); } return testnum; }
private int testStringProvider(int testnum) throws Exception { // get an instance of JavaLoginConfig from SUN Configuration c = Configuration.getInstance(JAVA_CONFIG, null, "SUN"); doTest(c, testnum++); // get an instance of JavaLoginConfig from SunRsaSign try { c = Configuration.getInstance(JAVA_CONFIG, null, "SunRsaSign"); throw new SecurityException("test " + testnum++ + " failed"); } catch (NoSuchAlgorithmException nsae) { // good System.out.println("test " + testnum++ + " passed"); } // get an instance of JavaLoginConfig from FOO try { c = Configuration.getInstance(JAVA_CONFIG, null, "FOO"); throw new SecurityException("test " + testnum++ + " failed"); } catch (NoSuchProviderException nspe) { // good System.out.println("test " + testnum++ + " passed"); } return testnum; }
private int testProvider(int testnum) throws Exception { // get an instance of JavaLoginConfig from SUN Configuration c = Configuration.getInstance(JAVA_CONFIG, null, Security.getProvider("SUN")); doTest(c, testnum++); // get an instance of JavaLoginConfig from SunRsaSign try { c = Configuration.getInstance(JAVA_CONFIG, null, Security.getProvider("SunRsaSign")); throw new SecurityException("test " + testnum++ + " failed"); } catch (NoSuchAlgorithmException nsae) { // good System.out.println("test " + testnum++ + " passed"); } return testnum; }
private void doCustomTest(Configuration c, int testnum, Provider custom) throws Exception { testnum = doCommon(c, testnum); // test getProvider if (custom == c.getProvider() && "GetInstanceProvider".equals(c.getProvider().getName())) { System.out.println("test " + testnum + " (getProvider) passed"); } else { throw new SecurityException ("test " + testnum + " (getProvider) failed"); } // test getType if ("GetInstanceConfigSpi".equals(c.getType())) { System.out.println("test " + testnum + "(getType) passed"); } else { throw new SecurityException("test " + testnum + " (getType) failed"); } }
private void doTest(Configuration c, int testnum) throws Exception { testnum = doCommon(c, testnum); // test getProvider if ("SUN".equals(c.getProvider().getName())) { System.out.println("test " + testnum + " (getProvider) passed"); } else { throw new SecurityException("test " + testnum + " (getProvider) failed"); } // test getType if (JAVA_CONFIG.equals(c.getType())) { System.out.println("test " + testnum + " (getType) passed"); } else { throw new SecurityException("test " + testnum + " (getType) failed"); } }
/** * Performs a kerberos login, possibly logging out first. * * @param prevContext The LoginContext from the previous login, or null * @param conf JAAS Configuration object * @param subject The JAAS Subject * @return The context and subject from the login * @throws LoginException If the login failed. */ Entry<LoginContext, Subject> login(LoginContext prevContext, Configuration conf, Subject subject) throws LoginException { // Is synchronized by the caller // If a context was provided, perform a logout first if (null != prevContext) { prevContext.logout(); } // Create a LoginContext given the Configuration and Subject LoginContext loginContext = createLoginContext(conf); // Invoke the login loginContext.login(); // Get the Subject from the context and verify it's non-null (null would imply failure) Subject loggedInSubject = loginContext.getSubject(); if (null == loggedInSubject) { throw new RuntimeException("Failed to perform Kerberos login"); } // Send it back to the caller to use with launchRenewalThread return new AbstractMap.SimpleEntry<>(loginContext, loggedInSubject); }
@Test public void noPreviousContextOnLogin() throws Exception { KerberosConnection krbUtil = mock(KerberosConnection.class); Subject subject = new Subject(); Subject loggedInSubject = new Subject(); Configuration conf = mock(Configuration.class); LoginContext context = mock(LoginContext.class); // Call the real login(LoginContext, Configuration, Subject) method when(krbUtil.login(nullable(LoginContext.class), any(Configuration.class), any(Subject.class))) .thenCallRealMethod(); // Return a fake LoginContext when(krbUtil.createLoginContext(conf)).thenReturn(context); // Return a fake Subject from that fake LoginContext when(context.getSubject()).thenReturn(loggedInSubject); Entry<LoginContext, Subject> pair = krbUtil.login(null, conf, subject); // Verify we get the fake LoginContext and Subject assertEquals(context, pair.getKey()); assertEquals(loggedInSubject, pair.getValue()); // login should be called on the LoginContext verify(context).login(); }
public SaslQuorumAuthLearner(boolean quorumRequireSasl, String quorumServicePrincipal, String loginContext) throws SaslException { this.quorumRequireSasl = quorumRequireSasl; this.quorumServicePrincipal = quorumServicePrincipal; try { AppConfigurationEntry entries[] = Configuration .getConfiguration() .getAppConfigurationEntry(loginContext); if (entries == null || entries.length == 0) { throw new LoginException("SASL-authentication failed because" + " the specified JAAS configuration " + "section '" + loginContext + "' could not be found."); } this.learnerLogin = new Login(loginContext, new SaslClientCallbackHandler(null, "QuorumLearner")); this.learnerLogin.startThreadIfNeeded(); } catch (LoginException e) { throw new SaslException("Failed to initialize authentication mechanism using SASL", e); } }
public SaslQuorumAuthServer(boolean quorumRequireSasl, String loginContext, Set<String> authzHosts) throws SaslException { this.quorumRequireSasl = quorumRequireSasl; try { AppConfigurationEntry entries[] = Configuration.getConfiguration() .getAppConfigurationEntry(loginContext); if (entries == null || entries.length == 0) { throw new LoginException("SASL-authentication failed" + " because the specified JAAS configuration " + "section '" + loginContext + "' could not be found."); } SaslQuorumServerCallbackHandler saslServerCallbackHandler = new SaslQuorumServerCallbackHandler( Configuration.getConfiguration(), loginContext, authzHosts); serverLogin = new Login(loginContext, saslServerCallbackHandler); serverLogin.startThreadIfNeeded(); } catch (Throwable e) { throw new SaslException( "Failed to initialize authentication mechanism using SASL", e); } }
public SaslQuorumServerCallbackHandler(Configuration configuration, String serverSection, Set<String> authzHosts) throws IOException { AppConfigurationEntry configurationEntries[] = configuration.getAppConfigurationEntry(serverSection); if (configurationEntries == null) { String errorMessage = "Could not find a '" + serverSection + "' entry in this configuration: Server cannot start."; LOG.error(errorMessage); throw new IOException(errorMessage); } credentials.clear(); for(AppConfigurationEntry entry: configurationEntries) { Map<String,?> options = entry.getOptions(); // Populate DIGEST-MD5 user -> password map with JAAS configuration entries from the "QuorumServer" section. // Usernames are distinguished from other options by prefixing the username with a "user_" prefix. for(Map.Entry<String, ?> pair : options.entrySet()) { String key = pair.getKey(); if (key.startsWith(USER_PREFIX)) { String userName = key.substring(USER_PREFIX.length()); credentials.put(userName,(String)pair.getValue()); } } } // authorized host lists this.authzHosts = authzHosts; }
public SaslServerCallbackHandler(Configuration configuration) throws IOException { String serverSection = System.getProperty( ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY, ZooKeeperSaslServer.DEFAULT_LOGIN_CONTEXT_NAME); AppConfigurationEntry configurationEntries[] = configuration.getAppConfigurationEntry(serverSection); if (configurationEntries == null) { String errorMessage = "Could not find a '" + serverSection + "' entry in this configuration: Server cannot start."; LOG.error(errorMessage); throw new IOException(errorMessage); } credentials.clear(); for(AppConfigurationEntry entry: configurationEntries) { Map<String,?> options = entry.getOptions(); // Populate DIGEST-MD5 user -> password map with JAAS configuration entries from the "Server" section. // Usernames are distinguished from other options by prefixing the username with a "user_" prefix. for(Map.Entry<String, ?> pair : options.entrySet()) { String key = pair.getKey(); if (key.startsWith(USER_PREFIX)) { String userName = key.substring(USER_PREFIX.length()); credentials.put(userName,(String)pair.getValue()); } } } }
static Subject getSubject() throws Exception { if (!secure) return new Subject(); /* * To authenticate the DemoClient, kinit should be invoked ahead. * Here we try to get the Kerberos credential from the ticket cache. */ LoginContext context = new LoginContext("", new Subject(), null, new Configuration() { @Override public AppConfigurationEntry[] getAppConfigurationEntry(String name) { Map<String, String> options = new HashMap<String, String>(); options.put("useKeyTab", "false"); options.put("storeKey", "false"); options.put("doNotPrompt", "true"); options.put("useTicketCache", "true"); options.put("renewTGT", "true"); options.put("refreshKrb5Config", "true"); options.put("isInitiator", "true"); String ticketCache = System.getenv("KRB5CCNAME"); if (ticketCache != null) { options.put("ticketCache", ticketCache); } options.put("debug", "true"); return new AppConfigurationEntry[]{ new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options)}; } }); context.login(); return context.getSubject(); }
private void createSaslServer(String mechanism) throws IOException { this.saslMechanism = mechanism; callbackHandler = new SaslServerCallbackHandler(Configuration.getConfiguration(), kerberosNamer); callbackHandler.configure(configs, Mode.SERVER, subject, saslMechanism); if (mechanism.equals(SaslConfigs.GSSAPI_MECHANISM)) { if (subject.getPrincipals().isEmpty()) throw new IllegalArgumentException("subject must have at least one principal"); saslServer = createSaslKerberosServer(callbackHandler, configs); } else { try { saslServer = Subject.doAs(subject, new PrivilegedExceptionAction<SaslServer>() { public SaslServer run() throws SaslException { return Sasl.createSaslServer(saslMechanism, "kafka", host, configs, callbackHandler); } }); } catch (PrivilegedActionException e) { throw new SaslException("Kafka Server failed to create a SaslServer to interact with a client during session authentication", e.getCause()); } } }
@Override public LoginContext login() throws LoginException { String jaasConfigFile = System.getProperty(JaasUtils.JAVA_LOGIN_CONFIG_PARAM); if (jaasConfigFile == null) { log.debug("System property '" + JaasUtils.JAVA_LOGIN_CONFIG_PARAM + "' is not set, using default JAAS configuration."); } AppConfigurationEntry[] configEntries = Configuration.getConfiguration().getAppConfigurationEntry(loginContextName); if (configEntries == null) { String errorMessage = "Could not find a '" + loginContextName + "' entry in the JAAS configuration. System property '" + JaasUtils.JAVA_LOGIN_CONFIG_PARAM + "' is " + (jaasConfigFile == null ? "not set" : jaasConfigFile); throw new IllegalArgumentException(errorMessage); } loginContext = new LoginContext(loginContextName, new LoginCallbackHandler()); loginContext.login(); log.info("Successfully logged in."); return loginContext; }
public static boolean isZkSecurityEnabled() { boolean isSecurityEnabled = false; boolean zkSaslEnabled = Boolean.parseBoolean(System.getProperty(ZK_SASL_CLIENT, "true")); String zkLoginContextName = System.getProperty(ZK_LOGIN_CONTEXT_NAME_KEY, "Client"); try { Configuration loginConf = Configuration.getConfiguration(); isSecurityEnabled = loginConf.getAppConfigurationEntry(zkLoginContextName) != null; } catch (Exception e) { throw new KafkaException("Exception while loading Zookeeper JAAS login context '" + zkLoginContextName + "'", e); } if (isSecurityEnabled && !zkSaslEnabled) { LOG.error("JAAS configuration is present, but system property " + ZK_SASL_CLIENT + " is set to false, which disables " + "SASL in the ZooKeeper client"); throw new KafkaException("Exception while determining if ZooKeeper is secure"); } return isSecurityEnabled; }
public SaslServerCallbackHandler(Configuration configuration) throws IOException { AppConfigurationEntry configurationEntries[] = configuration.getAppConfigurationEntry(JASS_SERVER_SECTION); if (configurationEntries == null) { String errorMessage = "Could not find a '" + JASS_SERVER_SECTION + "' entry in this configuration: Server cannot start."; throw new IOException(errorMessage); } credentials.clear(); for (AppConfigurationEntry entry : configurationEntries) { Map<String, ?> options = entry.getOptions(); // Populate DIGEST-MD5 user -> password map with JAAS configuration entries from the "Server" section. // Usernames are distinguished from other options by prefixing the username with a "user_" prefix. for (Map.Entry<String, ?> pair : options.entrySet()) { String key = pair.getKey(); if (key.startsWith(USER_PREFIX)) { String userName = key.substring(USER_PREFIX.length()); credentials.put(userName, (String) pair.getValue()); } } } }
private Subject loginClient() throws SaslException, PrivilegedActionException, LoginException { String clientSection = "HerdDBClient"; AppConfigurationEntry[] entries = Configuration.getConfiguration().getAppConfigurationEntry(clientSection); if (entries == null) { LOG.log(Level.FINEST, "No JAAS Configuration found with section HerdDBClient"); return null; } try { LoginContext loginContext = new LoginContext(clientSection, new ClientCallbackHandler(null)); loginContext.login(); LOG.log(Level.SEVERE, "Using JAAS Configuration subject: " + loginContext.getSubject()); return loginContext.getSubject(); } catch (LoginException error) { LOG.log(Level.SEVERE, "Error JAAS Configuration subject: " + error, error); return null; } }
/** * Tests various authentication methods */ public void testAuthMethods() { // null should the same as "simple" for (String authMethod : new String[] { null, "simple", "DIGEST-MD5" }) { OscarConfiguration config = (OscarConfiguration) Configuration.getConfiguration(); config.setOption(LdapLoginModule.OPTION_AUTH_METHOD, authMethod); // now test the end-to-end login try { LoginContext loginContext = LoginModuleFactory.createContext(new OscarCallbackHandler("oscardoc", "mac2002")); loginContext.login(); loginContext.logout(); } catch (LoginException e) { fail(); } } }