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

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

Go to download

This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 35.0.0.Beta1
Show 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 - 2025 Weber Informatics LLC | Privacy Policy