/** * Utility method which loads the given properties file and returns a Properties object containing * the key,value pairs in that file. The properties files should be in the class path as this * method looks to the thread context class loader (TCL) to locate the resource. If the TCL is a * URLClassLoader the findResource(String) method is first tried. If this fails or the TCL is not * a URLClassLoader getResource(String) is tried. If not, an absolute path is tried. * * @param propertiesName - the name of the properties file resource * @return the loaded properties file if found * @exception java.io.IOException thrown if the properties file cannot be found or loaded */ static Properties loadProperties(String propertiesName) throws IOException { Properties bundle = null; ClassLoader loader = SecurityActions.getContextClassLoader(); URL url = null; // First check for local visibility via a URLClassLoader.findResource if (loader instanceof URLClassLoader) { URLClassLoader ucl = (URLClassLoader) loader; url = SecurityActions.findResource(ucl, propertiesName); PicketBoxLogger.LOGGER.traceAttemptToLoadResource(propertiesName); } // Do a general resource search if (url == null) { url = loader.getResource(propertiesName); if (url == null) { try { url = new URL(propertiesName); } catch (MalformedURLException mue) { PicketBoxLogger.LOGGER.debugFailureToOpenPropertiesFromURL(mue); File tmp = new File(propertiesName); if (tmp.exists()) url = tmp.toURI().toURL(); } } } if (url == null) { throw PicketBoxMessages.MESSAGES.unableToFindPropertiesFile(propertiesName); } Properties defaults = new Properties(); bundle = new Properties(defaults); if (url != null) { InputStream is = null; try { is = SecurityActions.openStream(url); } catch (PrivilegedActionException e) { throw new IOException(e.getLocalizedMessage()); } if (is != null) { try { bundle.load(is); } finally { safeClose(is); } } else { throw PicketBoxMessages.MESSAGES.unableToLoadPropertiesFile(propertiesName); } PicketBoxLogger.LOGGER.tracePropertiesFileLoaded(propertiesName, bundle.keySet()); } return bundle; }
private InitialLdapContext constructInitialLdapContext(String dn, Object credential) throws NamingException { Properties env = new Properties(); for (Entry<String, String> entry : options.entrySet()) { env.put(entry.getKey(), entry.getValue()); } // Set defaults for key values if they are missing String factoryName = env.getProperty(Context.INITIAL_CONTEXT_FACTORY); if (factoryName == null) { factoryName = "com.sun.jndi.ldap.LdapCtxFactory"; env.setProperty(Context.INITIAL_CONTEXT_FACTORY, factoryName); } String authType = env.getProperty(Context.SECURITY_AUTHENTICATION); if (authType == null) env.setProperty(Context.SECURITY_AUTHENTICATION, "simple"); String protocol = env.getProperty(Context.SECURITY_PROTOCOL); String providerURL = options.get(Context.PROVIDER_URL); if (providerURL == null) providerURL = "ldap://localhost:" + ((protocol != null && protocol.equals("ssl")) ? "636" : "389"); env.setProperty(Context.PROVIDER_URL, providerURL); distinguishedNameAttribute = options.get(DISTINGUISHED_NAME_ATTRIBUTE_OPT); if (distinguishedNameAttribute == null) distinguishedNameAttribute = "distinguishedName"; // JBAS-3555, allow anonymous login with no bindDN and bindCredential if (dn != null) env.setProperty(Context.SECURITY_PRINCIPAL, dn); if (credential != null) env.put(Context.SECURITY_CREDENTIALS, credential); PicketBoxLogger.LOGGER.traceLDAPConnectionEnv(env); return new InitialLdapContext(env, null); }
protected String getBindDN() { String bindDN = options.get(BIND_DN); if (bindDN == null || bindDN.length() == 0) { PicketBoxLogger.LOGGER.traceBindDNNotFound(); } return bindDN; }
/** * Create the set of roles the user belongs to by parsing the roles.properties data for * username=role1,role2,... and username.XXX=role1,role2,... patterns. * * @param targetUser - the username to obtain roles for * @param roles - the Properties containing the user=roles mappings * @param roleGroupSeperator - the character that seperates a username from a group name, e.g., * targetUser[.GroupName]=roles * @param aslm - the login module to use for Principal creation * @return Group[] containing the sets of roles */ static Group[] getRoleSets( String targetUser, Properties roles, char roleGroupSeperator, AbstractServerLoginModule aslm) { Enumeration<?> users = roles.propertyNames(); SimpleGroup rolesGroup = new SimpleGroup("Roles"); ArrayList<Group> groups = new ArrayList<Group>(); groups.add(rolesGroup); while (users.hasMoreElements() && targetUser != null) { String user = (String) users.nextElement(); String value = roles.getProperty(user); // See if this entry is of the form targetUser[.GroupName]=roles // JBAS-3742 - skip potential '.' in targetUser int index = user.indexOf(roleGroupSeperator, targetUser.length()); boolean isRoleGroup = false; boolean userMatch = false; if (index > 0 && targetUser.regionMatches(0, user, 0, index) == true) isRoleGroup = true; else userMatch = targetUser.equals(user); String groupName = "Roles"; // Check for username.RoleGroup pattern if (isRoleGroup == true) { groupName = user.substring(index + 1); PicketBoxLogger.LOGGER.traceAdditionOfRoleToGroup(value, groupName); if (groupName.equals("Roles")) { parseGroupMembers(rolesGroup, value, aslm); } else { SimpleGroup group = new SimpleGroup(groupName); parseGroupMembers(group, value, aslm); groups.add(group); } } else if (userMatch == true) { PicketBoxLogger.LOGGER.traceAdditionOfRoleToGroup(value, groupName); // Place these roles into the Default "Roles" group parseGroupMembers(rolesGroup, value, aslm); } } Group[] roleSets = new Group[groups.size()]; groups.toArray(roleSets); return roleSets; }
/** * Parse the comma delimited roles names given by value and add them to group. The type of * Principal created for each name is determined by the createIdentity method. * * @see AbstractServerLoginModule#createIdentity(String) * @param group - the Group to add the roles to. * @param roles - the comma delimited role names. */ static void parseGroupMembers(Group group, String roles, AbstractServerLoginModule aslm) { StringTokenizer tokenizer = new StringTokenizer(roles, ","); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); try { Principal p = aslm.createIdentity(token); group.addMember(p); } catch (Exception e) { PicketBoxLogger.LOGGER.debugFailureToCreatePrincipal(token, e); } } }
protected String getBindCredential() { String bindCredential = options.get(BIND_CREDENTIAL); if (bindCredential.startsWith("{EXT}")) { try { bindCredential = new String(org.jboss.security.Util.loadPassword(bindCredential)); } catch (Exception e1) { PicketBoxLogger.LOGGER.errorDecryptingBindCredential(e1); } } String securityDomain = options.get(SECURITY_DOMAIN_OPT); if (securityDomain != null) { try { ObjectName serviceName = new ObjectName(securityDomain); char[] tmp = DecodeAction.decode(bindCredential, serviceName); bindCredential = new String(tmp); } catch (Exception e) { PicketBoxLogger.LOGGER.errorDecryptingBindCredential(e); } } return bindCredential; }
/** * Calculate a password hash using a MessageDigest. * * @param hashAlgorithm - the MessageDigest algorithm name * @param hashEncoding - either base64 or hex to specify the type of encoding the MessageDigest as * a string. * @param hashCharset - the charset used to create the byte[] passed to the MessageDigestfrom the * password String. If null the platform default is used. * @param username - ignored in default version * @param password - the password string to be hashed * @param callback - the callback used to allow customization of the hash to occur. The preDigest * method is called before the password is added and the postDigest method is called after the * password has been added. * @return the hashed string if successful, null if there is a digest exception */ public static String createPasswordHash( String hashAlgorithm, String hashEncoding, String hashCharset, String username, String password, DigestCallback callback) { byte[] passBytes; String passwordHash = null; // convert password to byte data try { if (hashCharset == null) passBytes = password.getBytes(); else passBytes = password.getBytes(hashCharset); } catch (UnsupportedEncodingException uee) { PicketBoxLogger.LOGGER.errorFindingCharset(hashCharset, uee); passBytes = password.getBytes(); } // calculate the hash and apply the encoding. try { MessageDigest md = MessageDigest.getInstance(hashAlgorithm); if (callback != null) callback.preDigest(md); md.update(passBytes); if (callback != null) callback.postDigest(md); byte[] hash = md.digest(); if (hashEncoding.equalsIgnoreCase(BASE64_ENCODING)) { passwordHash = Util.encodeBase64(hash); } else if (hashEncoding.equalsIgnoreCase(BASE16_ENCODING)) { passwordHash = Util.encodeBase16(hash); } else if (hashEncoding.equalsIgnoreCase(RFC2617_ENCODING)) { passwordHash = Util.encodeRFC2617(hash); } else { PicketBoxLogger.LOGGER.unsupportedHashEncodingFormat(hashEncoding); } } catch (Exception e) { PicketBoxLogger.LOGGER.errorCalculatingPasswordHash(e); } return passwordHash; }
/** @see IdentityTrustManager#isTrusted(org.jboss.security.SecurityContext) */ public TrustDecision isTrusted(SecurityContext securityContext) { if (securityContext == null) throw PicketBoxMessages.MESSAGES.invalidNullArgument("securityContext"); if (this.identityTrustContext == null) this.identityTrustContext = new JBossIdentityTrustContext(securityDomain, securityContext); TrustDecision td = TrustDecision.NotApplicable; if (this.identityTrustContext == null) throw PicketBoxMessages.MESSAGES.invalidNullProperty("identityTrustContext"); try { td = this.identityTrustContext.isTrusted(); } catch (IdentityTrustException e) { PicketBoxLogger.LOGGER.debugIgnoredException(e); } return td; }
/** * Handle a {@code Callback} * * @param c callback * @throws UnsupportedCallbackException If the callback is not supported by this handler * @throws NamingException */ protected void handleCallBack(Callback c) throws UnsupportedCallbackException, NamingException { if (c instanceof VerifyPasswordCallback) { verifyPassword((VerifyPasswordCallback) c); return; } if (c instanceof PasswordCallback == false) return; PasswordCallback passwdCallback = (PasswordCallback) c; String bindDN = getBindDN(); String bindCredential = getBindCredential(); String tmp = options.get(PASSWORD_ATTRIBUTE_ID); if (tmp != null && tmp.length() > 0) { passwordAttributeID = tmp; } InitialLdapContext ctx; ClassLoader currentTCCL = SecurityActions.getContextClassLoader(); try { if (currentTCCL != null) SecurityActions.setContextClassLoader(null); ctx = this.constructInitialLdapContext(bindDN, bindCredential); } catch (NamingException e) { throw new RuntimeException(e); } String timeLimit = (String) options.get(SEARCH_TIME_LIMIT_OPT); if (timeLimit != null) { try { searchTimeLimit = Integer.parseInt(timeLimit); } catch (NumberFormatException e) { } } if (searchTimeLimit == 0) searchTimeLimit = 10000; String baseDN = options.get(BASE_CTX_DN); String baseFilter = options.get(BASE_FILTER_OPT); SearchControls constraints = new SearchControls(); constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); constraints.setTimeLimit(searchTimeLimit); NamingEnumeration<SearchResult> results = null; Object[] filterArgs = {userName}; try { if (baseDN == null) throw PicketBoxMessages.MESSAGES.invalidNullBaseContextDN(); results = ctx.search(baseDN, baseFilter, filterArgs, constraints); if (results.hasMore() == false) { safeClose(results); throw PicketBoxMessages.MESSAGES.failedToFindBaseContextDN(baseDN); } SearchResult sr = results.next(); String name = sr.getName(); String userDN = null; if (sr.isRelative() == true) userDN = name + "," + baseDN; else throw PicketBoxMessages.MESSAGES.unableToFollowReferralForAuth(name); ; safeClose(results); // Finished Authentication. Lets look for the attributes filterArgs = new Object[] {userName, userDN}; results = ctx.search(userDN, baseFilter, filterArgs, constraints); try { while (results.hasMore()) { sr = results.next(); Attributes attributes = sr.getAttributes(); NamingEnumeration<? extends javax.naming.directory.Attribute> ne = attributes.getAll(); while (ne != null && ne.hasMoreElements()) { javax.naming.directory.Attribute ldapAtt = ne.next(); if (passwordAttributeID.equalsIgnoreCase(ldapAtt.getID())) { Object thePass = ldapAtt.get(); setPasswordCallbackValue(thePass, passwdCallback); } } } } finally { safeClose(results); safeClose(ctx); if (currentTCCL != null) SecurityActions.setContextClassLoader(currentTCCL); } } catch (NamingException ne) { PicketBoxLogger.LOGGER.error(ne); } }