Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* JBoss, Home of Professional Open Source
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wildfly.security.auth.realm.ldap;
import static org.wildfly.security.auth.realm.ldap.ElytronMessages.log;
import static org.wildfly.security.auth.realm.ldap.UserPasswordPasswordUtil.parseUserPassword;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.Provider;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.util.Collection;
import java.util.function.Supplier;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.NoSuchAttributeException;
import org.wildfly.common.Assert;
import org.wildfly.security.auth.server.RealmUnavailableException;
import org.wildfly.security.auth.SupportLevel;
import org.wildfly.security.credential.Credential;
import org.wildfly.security.credential.PasswordCredential;
import org.wildfly.security.evidence.Evidence;
import org.wildfly.security.password.Password;
import org.wildfly.security.password.spec.Encoding;
import org.wildfly.security.util.LdapUtil;
/**
* A {@link CredentialLoader} for loading credentials stored within the 'userPassword' attribute of LDAP entries.
*
* @author Darran Lofthouse
*/
class UserPasswordCredentialLoader implements CredentialPersister {
static final String DEFAULT_USER_PASSWORD_ATTRIBUTE_NAME = "userPassword";
private final String userPasswordAttributeName;
/**
* Construct a new {@link UserPasswordCredentialLoader} for a specific attribute name.
*
* @param userPasswordAttributeName the name of the attribute within the LDAP entry that holds the credential.
*/
UserPasswordCredentialLoader(final String userPasswordAttributeName) {
Assert.checkNotNullParam("userPasswordAttributeName", userPasswordAttributeName);
this.userPasswordAttributeName = userPasswordAttributeName;
}
@Override
public SupportLevel getCredentialAcquireSupport(final Class credentialType, final String credentialAlgorithm, final AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException {
if (credentialType == PasswordCredential.class) {
if (credentialAlgorithm == null) return SupportLevel.SUPPORTED;
if (UserPasswordPasswordUtil.isAlgorithmSupported(credentialAlgorithm)) return SupportLevel.POSSIBLY_SUPPORTED;
}
return SupportLevel.UNSUPPORTED;
}
@Override
public IdentityCredentialPersister forIdentity(DirContext dirContext, String distinguishedName, Attributes attributes) {
return new ForIdentityLoader(dirContext, distinguishedName, attributes);
}
@Override
public IdentityCredentialPersister forIdentity(DirContext dirContext, String distinguishedName, Attributes attributes, Encoding hashEncoding) {
return new ForIdentityLoader(dirContext, distinguishedName, attributes, hashEncoding);
}
@Override
public void addRequiredIdentityAttributes(Collection attributes) {
attributes.add(userPasswordAttributeName);
}
EvidenceVerifier toEvidenceVerifier() {
return new EvidenceVerifier() {
@Override
public SupportLevel getEvidenceVerifySupport(final Class evidenceType, final String evidenceAlgorithm) throws RealmUnavailableException {
// If we can acquire PasswordCredential and it support provided evidence, we can verify.
if ( ! PasswordCredential.canVerifyEvidence(evidenceType, evidenceAlgorithm)) return SupportLevel.UNSUPPORTED;
return getCredentialAcquireSupport(PasswordCredential.class, evidenceAlgorithm, null);
}
@Override
public IdentityEvidenceVerifier forIdentity(final DirContext dirContext, final String distinguishedName, final String url, Attributes attributes) throws RealmUnavailableException {
return new ForIdentityLoader(dirContext, distinguishedName, attributes);
}
@Override
public IdentityEvidenceVerifier forIdentity(DirContext dirContext, String distinguishedName, String url, Attributes attributes, Encoding hashEncoding) throws RealmUnavailableException {
return new ForIdentityLoader(dirContext, distinguishedName, attributes, hashEncoding);
}
@Override
public void addRequiredIdentityAttributes(Collection attributes) {
attributes.add(userPasswordAttributeName);
}
};
}
private class ForIdentityLoader implements IdentityCredentialPersister, IdentityEvidenceVerifier {
private final DirContext context;
private final String distinguishedName;
private final Attributes attributes;
private final Encoding hashEncoding;
public ForIdentityLoader(DirContext context, String distinguishedName, Attributes attributes) {
this(context, distinguishedName, attributes, Encoding.BASE64);
}
public ForIdentityLoader(DirContext context, String distinguishedName, Attributes attributes, Encoding hashEncoding) {
this.context = context;
this.distinguishedName = distinguishedName;
this.attributes = attributes;
this.hashEncoding = hashEncoding;
}
@Override
public SupportLevel getCredentialAcquireSupport(final Class credentialType, final String credentialAlgorithm, final AlgorithmParameterSpec parameterSpec, final Supplier providers) {
Credential credential = getCredential(credentialType, credentialAlgorithm, parameterSpec, providers);
// By this point it is either supported or it isn't - no in-between.
if (credential != null) {
return SupportLevel.SUPPORTED;
}
return SupportLevel.UNSUPPORTED;
}
@Override
public SupportLevel getEvidenceVerifySupport(final Class evidenceType, final String evidenceAlgorithm, final Supplier providers) throws RealmUnavailableException {
// If we can acquire PasswordCredential and it support provided evidence, we can verify.
if ( ! PasswordCredential.canVerifyEvidence(evidenceType, evidenceAlgorithm)) return SupportLevel.UNSUPPORTED;
return getCredentialAcquireSupport(PasswordCredential.class, null, null, providers);
}
@Override
public boolean verifyEvidence(Evidence evidence, Supplier providers) throws RealmUnavailableException {
return verifyEvidence(evidence, providers, StandardCharsets.UTF_8);
}
@Override
public C getCredential(final Class credentialType, final String credentialAlgorithm, final AlgorithmParameterSpec parameterSpec, Supplier providers) {
if (credentialType != PasswordCredential.class) {
return null;
}
try {
Attribute attribute = LdapUtil.getBinaryAttribute(attributes, userPasswordAttributeName);
if (attribute != null) {
final int size = attribute.size();
for (int i = 0; i < size; i++) {
byte[] value = (byte[]) attribute.get(i);
Password password = parseUserPassword(value, hashEncoding);
if (credentialType.isAssignableFrom(PasswordCredential.class) && (credentialAlgorithm == null || credentialAlgorithm.equals(password.getAlgorithm()))) {
return credentialType.cast(new PasswordCredential(password));
}
}
}
} catch (NamingException | InvalidKeySpecException e) {
if (log.isTraceEnabled()) {
log.trace("Getting user-password credential " + credentialType.getName() + " failed. dn=" + distinguishedName, e);
}
}
return null;
}
@Override
public boolean verifyEvidence(final Evidence evidence, Supplier providers, Charset hashCharset) throws RealmUnavailableException {
final PasswordCredential credential = getCredential(PasswordCredential.class, null, null, providers);
if (credential == null) return false;
return credential.verify(providers, evidence, hashCharset);
}
@Override
public boolean getCredentialPersistSupport(final Class credentialType, final String credentialAlgorithm, final AlgorithmParameterSpec parameterSpec) {
// for now, assume that the parameterSpec matches the credential algorithm.
return credentialType == PasswordCredential.class && (credentialAlgorithm == null || UserPasswordPasswordUtil.isAlgorithmSupported(credentialAlgorithm));
}
@Override
public void persistCredential(final Credential credential) throws RealmUnavailableException {
// TODO - We probably need some better resolution here of the existing attributes - i.e. different types we would want to add, same type we would want to replace.
try {
byte[] composedPassword = UserPasswordPasswordUtil.composeUserPassword(credential.castAndApply(PasswordCredential.class, PasswordCredential::getPassword), hashEncoding);
Assert.assertNotNull(composedPassword);
Attributes attributes = new BasicAttributes();
attributes.put(userPasswordAttributeName, composedPassword);
context.modifyAttributes(distinguishedName, DirContext.REPLACE_ATTRIBUTE, attributes);
} catch (NamingException | IOException e) {
throw log.ldapRealmCredentialPersistingFailed(credential.toString(), distinguishedName, e);
}
}
@Override
public void clearCredentials() throws RealmUnavailableException {
try {
Attributes attributes = new BasicAttributes();
attributes.put(new BasicAttribute(userPasswordAttributeName));
context.modifyAttributes(distinguishedName, DirContext.REMOVE_ATTRIBUTE, attributes);
} catch (NoSuchAttributeException e) {
// ignore if already clear
} catch (NamingException e) {
throw log.ldapRealmCredentialClearingFailed(distinguishedName, e);
}
}
}
}