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

com.amazon.opendistroforelasticsearch.security.user.AuthCredentials Maven / Gradle / Ivy

There is a newer version: 1.13.1.0
Show newest version
/*
 * Copyright 2015-2018 _floragunn_ GmbH
 * 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.
 */

/*
 * Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * or in the "license" file accompanying this file. This file 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 com.amazon.opendistroforelasticsearch.security.user;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.elasticsearch.ElasticsearchSecurityException;

/**
 * AuthCredentials are an abstraction to encapsulate credentials like passwords or generic
 * native credentials like GSS tokens.
 *
 */
public final class AuthCredentials {

    private static final String DIGEST_ALGORITHM = "SHA-256";
    private final String username;
    private byte[] password;
    private Object nativeCredentials;
    private final Set backendRoles = new HashSet();
    private boolean complete;
    private final byte[] internalPasswordHash;
    private final Map attributes = new HashMap<>();

    /**
     * Create new credentials with a username and native credentials
     *
     * @param username The username, must not be null or empty
     * @param nativeCredentials Arbitrary credentials (like GSS tokens), must not be null
     * @throws IllegalArgumentException if username or nativeCredentials are null or empty
     */
    public AuthCredentials(final String username, final Object nativeCredentials) {
        this(username, null, nativeCredentials);

        if (nativeCredentials == null) {
            throw new IllegalArgumentException("nativeCredentials must not be null or empty");
        }
    }

    /**
     * Create new credentials with a username and password
     *
     * @param username The username, must not be null or empty
     * @param password The password, must not be null or empty
     * @throws IllegalArgumentException if username or password is null or empty
     */
    public AuthCredentials(final String username, final byte[] password) {
        this(username, password, null);

        if (password == null || password.length == 0) {
            throw new IllegalArgumentException("password must not be null or empty");
        }
    }

    /**
     * Create new credentials with a username, a initial optional set of roles and empty password/native credentials

     * @param username The username, must not be null or empty
     * @param backendRoles set of roles this user is a member of
     * @throws IllegalArgumentException if username is null or empty
     */
    public AuthCredentials(final String username, String... backendRoles) {
        this(username, null, null, backendRoles);
    }

    private AuthCredentials(final String username, byte[] password, Object nativeCredentials, String... backendRoles) {
        super();

        if (username == null || username.isEmpty()) {
            throw new IllegalArgumentException("username must not be null or empty");
        }

        this.username = username;
        // make defensive copy
        this.password = password == null ? null : Arrays.copyOf(password, password.length);

        if(this.password != null) {
            try {
                MessageDigest digester = MessageDigest.getInstance(DIGEST_ALGORITHM);
                internalPasswordHash = digester.digest(this.password);
            } catch (NoSuchAlgorithmException e) {
                throw new ElasticsearchSecurityException("Unable to digest password", e);
            }
        } else {
            internalPasswordHash = null;
        }

        if(password != null) {
            Arrays.fill(password, (byte) '\0');
            password = null;
        }

        this.nativeCredentials = nativeCredentials;
        nativeCredentials = null;

        if(backendRoles != null && backendRoles.length > 0) {
            this.backendRoles.addAll(Arrays.asList(backendRoles));
        }
    }

    /**
     * Wipe password and native credentials
     */
    public void clearSecrets() {
        if (password != null) {
            Arrays.fill(password, (byte) '\0');
            password = null;
        }

        nativeCredentials = null;
    }

    public String getUsername() {
        return username;
    }

    /**
     *
     * @return Defensive copy of the password
     */
    public byte[] getPassword() {
        // make defensive copy
        return password == null ? null : Arrays.copyOf(password, password.length);
    }

    public Object getNativeCredentials() {
        return nativeCredentials;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(internalPasswordHash);
        result = prime * result + ((username == null) ? 0 : username.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        AuthCredentials other = (AuthCredentials) obj;
        if (internalPasswordHash == null || other.internalPasswordHash == null || !MessageDigest.isEqual(internalPasswordHash, other.internalPasswordHash))
            return false;
        if (username == null) {
            if (other.username != null)
                return false;
        } else if (!username.equals(other.username))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "AuthCredentials [username=" + username + ", password empty=" + (password == null) + ", nativeCredentials empty="
                + (nativeCredentials == null) + ",backendRoles="+backendRoles+"]";
    }

    /**
     *
     * @return Defensive copy of the roles this user is member of.
     */
    public Set getBackendRoles() {
        return new HashSet(backendRoles);
    }

    public boolean isComplete() {
        return complete;
    }

    /**
     * If the credentials are complete and no further roundtrips with the originator are due
     * then this method must be called so that the authentication flow can proceed.
     * 

* If this credentials are already marked a complete then a call to this method does nothing. * * @return this */ public AuthCredentials markComplete() { this.complete = true; return this; } public void addAttribute(String name, String value) { if(name != null && !name.isEmpty()) { this.attributes.put(name, value); } } public Map getAttributes() { return Collections.unmodifiableMap(this.attributes); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy