All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wildfly.security.auth.realm.ldap.LdapSecurityRealmBuilder Maven / Gradle / Ivy

The newest version!
/*
 * 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.common.Assert.assertNotNull;
import static org.wildfly.security.auth.realm.ldap.ElytronMessages.log;
import static org.wildfly.security.provider.util.ProviderUtil.INSTALLED_PROVIDERS;

import org.wildfly.common.Assert;
import org.wildfly.common.function.ExceptionSupplier;
import org.wildfly.security.auth.realm.ldap.LdapSecurityRealm.IdentityMapping;
import org.wildfly.security.auth.server.ModifiableSecurityRealm;
import org.wildfly.security.auth.server.NameRewriter;
import org.wildfly.security.password.spec.Encoding;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.ldap.LdapName;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.Provider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;

/**
 * Builder for the security realm implementation backed by LDAP.
 *
 * @author Darran Lofthouse
 */
public class LdapSecurityRealmBuilder {

    /*
     *  The LDAP security realm constructed by this builder expects no further modifications to the
     *  Collections it is passed.
     *
     *  This is the reason this builder and all child builders are implemented to prevent subsequent
     *  modification after the build is complete.
     */

    private static final int DEFAULT_SEARCH_TIME_LIMIT = 10000;

    private boolean built = false;
    private Supplier providers = INSTALLED_PROVIDERS;
    private ExceptionSupplier dirContextSupplier;
    private NameRewriter nameRewriter = NameRewriter.IDENTITY_REWRITER;
    private IdentityMapping identityMapping;
    private int pageSize = 50;

    private List credentialLoaders = new ArrayList<>();
    private List credentialPersisters = new ArrayList<>();
    private List evidenceVerifiers = new ArrayList<>();
    private Charset hashCharset = StandardCharsets.UTF_8;
    private Encoding hashEncoding = Encoding.BASE64;

    private LdapSecurityRealmBuilder() {
    }

    /**
     * Construct a new instance.
     *
     * @return the new builder instance
     */
    public static LdapSecurityRealmBuilder builder() {
        return new LdapSecurityRealmBuilder();
    }

    /**
     * The the Provider[] supplier.
     *
     * @param providers the supplier of Providers to be used by the realm
     * @return this builder
     */
    public LdapSecurityRealmBuilder setProviders(Supplier providers) {
        assertNotBuilt();
        this.providers = providers;

        return this;
    }

    /**
     * Set the directory context supplier.
     *
     * @param dirContextSupplier the directory context supplier
     * @return this builder
     */
    public LdapSecurityRealmBuilder setDirContextSupplier(final ExceptionSupplier dirContextSupplier) {
        assertNotBuilt();

        this.dirContextSupplier = dirContextSupplier;

        return this;
    }

    /**
     * Add a name rewriter to this builder.
     *
     * @param nameRewriter the name rewriter
     * @return this builder
     */
    public LdapSecurityRealmBuilder setNameRewriter(final NameRewriter nameRewriter) {
        Assert.checkNotNullParam("nameRewriter", nameRewriter);
        assertNotBuilt();

        this.nameRewriter = nameRewriter;

        return this;
    }

    /**
     * Set size of page for realm iterating
     *
     * @param pageSize size of page
     * @return this builder
     */
    public LdapSecurityRealmBuilder setPageSize(final int pageSize) {
        this.pageSize = pageSize;

        return this;
    }

    public IdentityMappingBuilder identityMapping() {
        assertNotBuilt();

        return new IdentityMappingBuilder();
    }

    /**
     * Add a principal mapping to this builder.
     *
     * @return the builder for the principal mapping
     */
    LdapSecurityRealmBuilder setIdentityMapping(IdentityMapping principalMapping) {
        this.identityMapping = principalMapping;

        return this;
    }

    /**
     * Set the character set to use when converting the password string
     * to a byte array. Set to UTF-8 by default.
     * @param hashCharset the name of the character set (must not be {@code null}).
     *
     * @return this builder
     */
    public LdapSecurityRealmBuilder setHashCharset(Charset hashCharset) {
        assertNotNull(hashCharset);
        this.hashCharset = hashCharset;

        return this;
    }

    /**
     *  Set the string format for the password in the properties file if they are not
     *  stored in plain text. Set to base64 by default.
     * @param hashEncoding specifies the string format for the hashed password
     *
     * @return this builder
     */
    public LdapSecurityRealmBuilder setHashEncoding(Encoding hashEncoding) {
        assertNotNull(hashEncoding);
        this.hashEncoding = hashEncoding;

        return this;
    }

    public UserPasswordCredentialLoaderBuilder userPasswordCredentialLoader() {
        assertNotBuilt();

        return new UserPasswordCredentialLoaderBuilder();
    }

    public OtpCredentialLoaderBuilder otpCredentialLoader() {
        assertNotBuilt();

        return new OtpCredentialLoaderBuilder();
    }

    public X509EvidenceVerifierBuilder x509EvidenceVerifier() {
        assertNotBuilt();

        return new X509EvidenceVerifierBuilder();
    }

    LdapSecurityRealmBuilder addCredentialLoader(CredentialLoader credentialLoader) {
        credentialLoaders.add(credentialLoader);

        return this;
    }

    LdapSecurityRealmBuilder addCredentialPersister(CredentialPersister credentialPersister) {
        credentialPersisters.add(credentialPersister);

        return this;
    }

    LdapSecurityRealmBuilder addEvidenceVerifier(EvidenceVerifier evidenceVerifier) {
        evidenceVerifiers.add(evidenceVerifier);

        return this;
    }

    public LdapSecurityRealmBuilder addDirectEvidenceVerification() {
        return addDirectEvidenceVerification(false);
    }

    public LdapSecurityRealmBuilder addDirectEvidenceVerification(boolean allowBlankPassword) {
        assertNotBuilt();

        return addEvidenceVerifier(new DirectEvidenceVerifier(allowBlankPassword));
    }

    /**
     * Build this realm.
     *
     * @return the built realm
     */
    public ModifiableSecurityRealm build() {
        assertNotBuilt();
        if (dirContextSupplier == null) {
            throw log.noDirContextSupplierSet();
        }
        if (identityMapping == null) {
            throw log.noPrincipalMappingDefinition();
        }

        built = true;
        return new LdapSecurityRealm(providers, dirContextSupplier, nameRewriter,
                identityMapping, credentialLoaders, credentialPersisters, evidenceVerifiers,
                pageSize, hashCharset, hashEncoding);
    }

    private void assertNotBuilt() {
        if (built) {
            throw log.builderAlreadyBuilt();
        }
    }

    /**
     * A builder for a principal mapping.
     */
    public class IdentityMappingBuilder {

        private boolean built = false;

        private String searchDn = null;
        private boolean searchRecursive = false;
        private String nameAttribute;
        private int searchTimeLimit = DEFAULT_SEARCH_TIME_LIMIT;
        private List attributes = new ArrayList<>();
        private LdapName newIdentityParent = null;
        private Attributes newIdentityAttributes = null;
        private String filterName;
        private String iteratorFilter;

        /**
         * 

Set the name of the context to be used when executing queries. * *

This option is specially useful when authenticating users based on names that don't use a X.500 format such as plainUser. * In this case, you must also provide {@link #setRdnIdentifier(String)} with the attribute name that contains the user name.

* *

If the names used to authenticate users are based on the X.500 format, this configuration can be suppressed. * *

Please note that by using this option the realm is able to authenticate users based on their simple or X.500 names. * * @param searchDn the name of the context to search * @return this builder */ public IdentityMappingBuilder setSearchDn(final String searchDn) { assertNotBuilt(); this.searchDn = searchDn; return this; } /** * Indicate if queries are searchRecursive, searching the entire subtree rooted at the name specified in {@link #setSearchDn(String)}. * Otherwise search one level of the named context. * * @return this builder */ public IdentityMappingBuilder searchRecursive() { assertNotBuilt(); this.searchRecursive = true; return this; } /** * Sets the time limit of LDAP search in milliseconds. * * @param limit the limit in milliseconds. Defaults to {@value #DEFAULT_SEARCH_TIME_LIMIT} milliseconds. * @return this builder */ public IdentityMappingBuilder setSearchTimeLimit(int limit) { assertNotBuilt(); this.searchTimeLimit = limit; return this; } /** * Set the name of the attribute in LDAP that holds the user name and will appear in path of new entries. * * @param nameAttribute the name attribute * @return this builder */ public IdentityMappingBuilder setRdnIdentifier(final String nameAttribute) { assertNotBuilt(); this.nameAttribute = nameAttribute; return this; } public IdentityMappingBuilder setNewIdentityParent(LdapName newIdentityParent) { assertNotBuilt(); this.newIdentityParent = newIdentityParent; return this; } public IdentityMappingBuilder setNewIdentityAttributes(Attributes newIdentityAttributes) { assertNotBuilt(); this.newIdentityAttributes = newIdentityAttributes; return this; } public IdentityMappingBuilder setFilterName(String filterName) { assertNotBuilt(); this.filterName = filterName; return this; } public IdentityMappingBuilder setIteratorFilter(String iteratorFilter) { assertNotBuilt(); this.iteratorFilter = iteratorFilter; return this; } /** * Define an attribute mapping configuration. * * @param attributes one or more {@link AttributeMapping} configuration * @return this builder */ public IdentityMappingBuilder map(AttributeMapping... attributes) { assertNotBuilt(); this.attributes.addAll(Arrays.asList(attributes)); return this; } public LdapSecurityRealmBuilder build() { assertNotBuilt(); built = true; if (filterName == null) filterName = String.format("(%s={0})", nameAttribute); return LdapSecurityRealmBuilder.this.setIdentityMapping(new IdentityMapping( searchDn, searchRecursive, searchTimeLimit, nameAttribute, attributes, newIdentityParent, newIdentityAttributes, filterName, iteratorFilter)); } private void assertNotBuilt() { if (built) { throw log.builderAlreadyBuilt(); } LdapSecurityRealmBuilder.this.assertNotBuilt(); } } public class UserPasswordCredentialLoaderBuilder { private boolean built = false; private String userPasswordAttribute = UserPasswordCredentialLoader.DEFAULT_USER_PASSWORD_ATTRIBUTE_NAME; private boolean enablePersistence = false; private boolean enableVerification = true; /** * Set the name of the attribute within the LDAP entry that should be queries to load the credential. * * @param userPasswordAttribute the name of the attribute within the LDAP entry that should be queries to load the credential. * @return the {@link UserPasswordCredentialLoaderBuilder} to allow chaining of calls. */ public UserPasswordCredentialLoaderBuilder setUserPasswordAttribute(final String userPasswordAttribute) { assertNotBuilt(); this.userPasswordAttribute = userPasswordAttribute; return this; } /** * Enable persistence for the {@link UserPasswordCredentialLoader} being defined. * * @return the {@link UserPasswordCredentialLoaderBuilder} to allow chaining of calls. */ public UserPasswordCredentialLoaderBuilder enablePersistence() { assertNotBuilt(); enablePersistence = true; return this; } /** * By default if we can obtain a credential we support verification against it, this disables it. * * @return the {@link UserPasswordCredentialLoaderBuilder} to allow chaining of calls. */ public UserPasswordCredentialLoaderBuilder disableVerification() { assertNotBuilt(); enableVerification = false; return this; } public LdapSecurityRealmBuilder build() { assertNotBuilt(); built = true; UserPasswordCredentialLoader upcl = new UserPasswordCredentialLoader(userPasswordAttribute); LdapSecurityRealmBuilder.this.addCredentialLoader(upcl); if (enablePersistence) LdapSecurityRealmBuilder.this.addCredentialPersister(upcl); if (enableVerification) LdapSecurityRealmBuilder.this.addEvidenceVerifier(upcl.toEvidenceVerifier()); return LdapSecurityRealmBuilder.this; } private void assertNotBuilt() { if (built) { throw log.builderAlreadyBuilt(); } LdapSecurityRealmBuilder.this.assertNotBuilt(); } } public class OtpCredentialLoaderBuilder { private boolean built = false; private String otpAlgorithmAttribute = null; private String otpHashAttribute = null; private String otpSeedAttribute = null; private String otpSequenceAttribute = null; public OtpCredentialLoaderBuilder setOtpAlgorithmAttribute(final String otpAlgorithmAttribute) { assertNotBuilt(); this.otpAlgorithmAttribute = otpAlgorithmAttribute; return this; } public OtpCredentialLoaderBuilder setOtpHashAttribute(final String otpHashAttribute) { assertNotBuilt(); this.otpHashAttribute = otpHashAttribute; return this; } public OtpCredentialLoaderBuilder setOtpSeedAttribute(final String otpSeedAttribute) { assertNotBuilt(); this.otpSeedAttribute = otpSeedAttribute; return this; } public OtpCredentialLoaderBuilder setOtpSequenceAttribute(final String otpSequenceAttribute) { assertNotBuilt(); this.otpSequenceAttribute = otpSequenceAttribute; return this; } public LdapSecurityRealmBuilder build() { assertNotBuilt(); built = true; OtpCredentialLoader ocl = new OtpCredentialLoader(otpAlgorithmAttribute, otpHashAttribute, otpSeedAttribute, otpSequenceAttribute); LdapSecurityRealmBuilder.this.addCredentialLoader(ocl); LdapSecurityRealmBuilder.this.addCredentialPersister(ocl); return LdapSecurityRealmBuilder.this; } private void assertNotBuilt() { if (built) { throw log.builderAlreadyBuilt(); } LdapSecurityRealmBuilder.this.assertNotBuilt(); } } public class X509EvidenceVerifierBuilder { private boolean built = false; private List certificateVerifiers = new ArrayList<>(); public X509EvidenceVerifierBuilder addSerialNumberCertificateVerifier(final String ldapAttribute) { assertNotBuilt(); certificateVerifiers.add(new X509EvidenceVerifier.SerialNumberCertificateVerifier(ldapAttribute)); return this; } public X509EvidenceVerifierBuilder addSubjectDnCertificateVerifier(final String ldapAttribute) { assertNotBuilt(); certificateVerifiers.add(new X509EvidenceVerifier.SubjectDnCertificateVerifier(ldapAttribute)); return this; } public X509EvidenceVerifierBuilder addDigestCertificateVerifier(final String ldapAttribute, final String algorithm) { assertNotBuilt(); certificateVerifiers.add(new X509EvidenceVerifier.DigestCertificateVerifier(ldapAttribute, algorithm)); return this; } public X509EvidenceVerifierBuilder addEncodedCertificateVerifier(final String ldapAttribute) { assertNotBuilt(); certificateVerifiers.add(new X509EvidenceVerifier.EncodedCertificateVerifier(ldapAttribute)); return this; } public LdapSecurityRealmBuilder build() { assertNotBuilt(); Assert.checkNotEmptyParam("certificateVerifiers", certificateVerifiers); built = true; addEvidenceVerifier(new X509EvidenceVerifier(certificateVerifiers)); return LdapSecurityRealmBuilder.this; } private void assertNotBuilt() { if (built) { throw log.builderAlreadyBuilt(); } LdapSecurityRealmBuilder.this.assertNotBuilt(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy