/* * Copyright 2015 floragunn UG (haftungsbeschränkt) * * 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 com.floragunn.searchguard.user; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import org.elasticsearch.ElasticsearchSecurityException; 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<String> backendRoles = new HashSet<String>(); private boolean complete; private final byte[] internalPasswordHash; 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"); } } 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"); } } public AuthCredentials(final String username, String... backendRoles) { this(username, null, null, backendRoles); } public AuthCredentials(final AuthCredentials creds) { this(creds.username, creds.password, creds.nativeCredentials); } 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)); } } public void clearSecrets() { if (password != null) { Arrays.fill(password, (byte) '\0'); password = null; } nativeCredentials = null; } public String getUsername() { return username; } 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 (!Arrays.equals(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+"]"; } public Set<String> getBackendRoles() { return new HashSet<String>(backendRoles); } public boolean isComplete() { return complete; } public AuthCredentials markComplete() { this.complete = true; return this; } }