├── COPYING ├── src └── main │ ├── resources │ ├── es-plugin.properties │ └── plugin-descriptor.properties │ ├── java │ └── com │ │ └── cleafy │ │ └── elasticsearch │ │ └── plugins │ │ └── http │ │ ├── utils │ │ ├── Globals.java │ │ └── LoggerUtils.java │ │ ├── auth │ │ ├── Authenticator.java │ │ ├── HttpBasicAuthenticator.java │ │ ├── HTTPHelper.java │ │ └── AuthCredentials.java │ │ ├── BasicRestFilter.java │ │ └── HttpBasicServerPlugin.java │ └── assemblies │ └── plugin.xml ├── reinstall.sh ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── pom.xml └── README.md /COPYING: -------------------------------------------------------------------------------- 1 | elasticsearch-http-basic is Copyright (c) 2011, Florian and Felix Gilcher 2 | -------------------------------------------------------------------------------- /src/main/resources/es-plugin.properties: -------------------------------------------------------------------------------- 1 | plugin=com.cleafy.elasticsearch.plugins.http.HttpBasicServerPlugin -------------------------------------------------------------------------------- /reinstall.sh: -------------------------------------------------------------------------------- 1 | ES=/usr/share/elasticsearch 2 | sudo $ES/bin/plugin remove http-basic 3 | mvn -DskipTests clean package 4 | FILE=`ls ./target/elasticsearch-*zip` 5 | sudo $ES/bin/plugin -url file:$FILE -install http-basic 6 | sudo service elasticsearch restart -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | *.class 3 | *.zip 4 | /build/ 5 | /bin/ 6 | /target/ 7 | *~ 8 | deploy.sh 9 | .gradle 10 | .DS_Store 11 | .classpath 12 | .metadata/ 13 | .project 14 | /.gradle/ 15 | .settings/ 16 | data/ 17 | /.local-execution-hints.log 18 | /.local-*-execution-hints.log 19 | *.iml 20 | -------------------------------------------------------------------------------- /src/main/resources/plugin-descriptor.properties: -------------------------------------------------------------------------------- 1 | classname=com.cleafy.elasticsearch.plugins.http.HttpBasicServerPlugin 2 | name=elasticsearch-http-basic-auth-plugin 3 | description=Plugin to enable HTTP basic authentication and/or Ip based authentication 4 | version=1.0.0 5 | java.version=1.8 6 | elasticsearch.version=7.13.3 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | script: 3 | - mvn clean verify 4 | - mvn package 5 | deploy: 6 | skip_cleanup: true 7 | provider: releases 8 | file: target/releases/elasticsearch-http-basic-plugin.zip 9 | api_key: b1f302f147825ef828d64a77cc5e37a9898f34a6 10 | on: 11 | repo: Sessa93/elasticsearch-http-basic 12 | tags: true 13 | branch: master 14 | -------------------------------------------------------------------------------- /src/main/java/com/cleafy/elasticsearch/plugins/http/utils/Globals.java: -------------------------------------------------------------------------------- 1 | package com.cleafy.elasticsearch.plugins.http.utils; 2 | 3 | public class Globals { 4 | public static final String SETTINGS_ENABLED = "http.basic.enabled"; 5 | public static final String SETTINGS_USERNAME = "http.basic.username"; 6 | public static final String SETTINGS_PASSWORD = "http.basic.password"; 7 | 8 | public static final String SETTINGS_LOG = "http.basic.log"; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/cleafy/elasticsearch/plugins/http/auth/Authenticator.java: -------------------------------------------------------------------------------- 1 | package com.cleafy.elasticsearch.plugins.http.auth; 2 | 3 | import org.elasticsearch.common.settings.Settings; 4 | import org.elasticsearch.rest.RestRequest; 5 | 6 | public abstract class Authenticator { 7 | private Settings settings; 8 | 9 | public Authenticator(Settings settings) { 10 | this.settings = settings; 11 | } 12 | 13 | public abstract boolean authenticate(RestRequest request); 14 | } 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this 4 | file. This file is structured according to http://keepachangelog.com/ 5 | Use `date "+%Y-%m-%d"` to get the correct date formatting 6 | 7 | - - - 8 | ## [1.5.1][2015-08-30] 9 | ### - Added 10 | - allow HEAD root url authentication #39 11 | - log http method on any request. #42 12 | - doc: 1.6.0, 1.7.0 support #52 13 | ### - Fix 14 | - test: adapt to method signature change after 1.5.1 #55 15 | - test: run custom install and test commands in ci 16 | 17 | ## [1.5.0][2015-07-04] 18 | 19 | ### - Added 20 | - allow disabling ipwhitelist by setting its value to `false` 21 | - updated pom to depend on elasticsearch-parent project 22 | - travis test matrix for different ES versions 23 | 24 | ### Changed 25 | - restored default healthcheck for authenticated users 26 | - unauthenticated healthcheck for `/` returns `"{\"OK\":{}}"` 27 | - thanks @feaster83 28 | 29 | ## [1.4.0] 30 | ## [1.0.3] 31 | 32 | ### - Added 33 | - Changelog 34 | - Disable Authentication for `/`, allowing it to be used for healtchecks. 35 | - thanks @archiloque 36 | -------------------------------------------------------------------------------- /src/main/java/com/cleafy/elasticsearch/plugins/http/auth/HttpBasicAuthenticator.java: -------------------------------------------------------------------------------- 1 | package com.cleafy.elasticsearch.plugins.http.auth; 2 | 3 | import org.elasticsearch.common.settings.Settings; 4 | import org.elasticsearch.rest.RestRequest; 5 | 6 | public class HttpBasicAuthenticator extends Authenticator { 7 | private final AuthCredentials credentials; 8 | 9 | public HttpBasicAuthenticator(Settings settings, AuthCredentials credentials) { 10 | super(settings); 11 | this.credentials = credentials; 12 | } 13 | 14 | @Override 15 | public boolean authenticate(RestRequest request) { 16 | return this.extractCredentials(request).equals(credentials); 17 | } 18 | 19 | private AuthCredentials extractCredentials(final RestRequest request) { 20 | final boolean forceLogin = request.paramAsBoolean("force_login", false); 21 | 22 | if (forceLogin) { 23 | return null; 24 | } 25 | 26 | final String authorizationHeader = request.header("Authorization"); 27 | return HTTPHelper.extractCredentials(authorizationHeader); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Florian Gilcher , Felix Gilcher 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/main/assemblies/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0.3.0 4 | 5 | zip 6 | 7 | false 8 | 9 | 10 | / 11 | src/main/resources 12 | 13 | *.properties 14 | 15 | 16 | 17 | 18 | 19 | / 20 | true 21 | true 22 | 23 | org.elasticsearch:elasticsearch 24 | 25 | 26 | 27 | / 28 | true 29 | true 30 | 31 | com.cleafy.elasticsearch:elasticsearch-http-basic 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/main/java/com/cleafy/elasticsearch/plugins/http/auth/HTTPHelper.java: -------------------------------------------------------------------------------- 1 | package com.cleafy.elasticsearch.plugins.http.auth; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | import java.util.Base64; 5 | 6 | public class HTTPHelper { 7 | public static AuthCredentials extractCredentials(String authorizationHeader) { 8 | 9 | if (authorizationHeader != null) { 10 | if (!authorizationHeader.trim().toLowerCase().startsWith("basic ")) { 11 | return null; 12 | } else { 13 | 14 | final String decodedBasicHeader = new String(Base64.getDecoder().decode(authorizationHeader.split(" ")[1]), 15 | StandardCharsets.UTF_8); 16 | 17 | final int firstColonIndex = decodedBasicHeader.indexOf(':'); 18 | 19 | String username = null; 20 | String password = null; 21 | 22 | if (firstColonIndex > 0) { 23 | username = decodedBasicHeader.substring(0, firstColonIndex); 24 | 25 | if (decodedBasicHeader.length() - 1 != firstColonIndex) { 26 | password = decodedBasicHeader.substring(firstColonIndex + 1); 27 | } else { 28 | //blank password 29 | password = ""; 30 | } 31 | } 32 | 33 | if (username == null || password == null) { 34 | return null; 35 | } else { 36 | return new AuthCredentials(username, password.getBytes(StandardCharsets.UTF_8)).markComplete(); 37 | } 38 | } 39 | } else { 40 | return null; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/cleafy/elasticsearch/plugins/http/utils/LoggerUtils.java: -------------------------------------------------------------------------------- 1 | package com.cleafy.elasticsearch.plugins.http.utils; 2 | 3 | import org.apache.logging.log4j.LogManager; 4 | import org.apache.logging.log4j.Logger; 5 | import org.elasticsearch.rest.RestRequest; 6 | 7 | import java.net.InetAddress; 8 | import java.net.InetSocketAddress; 9 | 10 | public class LoggerUtils { 11 | 12 | public static void logRequest(final RestRequest request, Class klass) { 13 | String addr = getAddress(request).getHostAddress(); 14 | String t = "Authorization:{}, type: {}, Host:{}, Path:{}, {}:{}, Request-IP:{}, " + 15 | "Client-IP:{}, X-Client-IP{}"; 16 | Logger log = LogManager.getLogger(klass); 17 | 18 | log.info(t, 19 | request.header("Authorization"), 20 | request.method(), 21 | request.header("Host"), 22 | request.path(), 23 | addr, 24 | request.header("X-Client-IP"), 25 | request.header("Client-IP")); 26 | } 27 | 28 | public static void logUnAuthorizedRequest(final RestRequest request, Class klass) { 29 | String addr = getAddress(request).getHostAddress(); 30 | String t = "UNAUTHORIZED type:{}, address:{}, path:{}, request:{}, content:{}"; 31 | Logger log = LogManager.getLogger(klass); 32 | 33 | log.error(t, 34 | request.method(), addr, request.path(), request.params(), 35 | request.content().utf8ToString()); 36 | } 37 | 38 | private static InetAddress getAddress(RestRequest request) { 39 | return ((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).getAddress(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/cleafy/elasticsearch/plugins/http/BasicRestFilter.java: -------------------------------------------------------------------------------- 1 | package com.cleafy.elasticsearch.plugins.http; 2 | 3 | import com.cleafy.elasticsearch.plugins.http.auth.AuthCredentials; 4 | import com.cleafy.elasticsearch.plugins.http.auth.HttpBasicAuthenticator; 5 | import com.cleafy.elasticsearch.plugins.http.utils.Globals; 6 | import com.cleafy.elasticsearch.plugins.http.utils.LoggerUtils; 7 | import org.elasticsearch.ElasticsearchException; 8 | import org.elasticsearch.client.node.NodeClient; 9 | import org.elasticsearch.common.settings.Settings; 10 | import org.elasticsearch.rest.*; 11 | import org.elasticsearch.transport.TransportException; 12 | 13 | public class BasicRestFilter { 14 | private final HttpBasicAuthenticator httpBasicAuthenticator; 15 | private final boolean isUnauthLogEnabled; 16 | 17 | public BasicRestFilter(final Settings settings) { 18 | super(); 19 | this.httpBasicAuthenticator = new HttpBasicAuthenticator(settings, new AuthCredentials(settings.get(Globals.SETTINGS_USERNAME, "pippo"), settings.get(Globals.SETTINGS_PASSWORD, "pluto").getBytes())); 20 | this.isUnauthLogEnabled = settings.getAsBoolean(Globals.SETTINGS_LOG, false); 21 | } 22 | 23 | public RestHandler wrap(RestHandler original) { 24 | return (request, channel, client) -> { 25 | if (!checkAndAuthenticateRequest(request, channel, client)) { 26 | original.handleRequest(request, channel, client); 27 | } 28 | }; 29 | } 30 | 31 | private boolean checkAndAuthenticateRequest(RestRequest request, RestChannel channel, NodeClient client) throws Exception { 32 | ElasticsearchException forbiddenException = new TransportException("Forbidden"); 33 | try { 34 | if (this.httpBasicAuthenticator.authenticate(request)) { 35 | LoggerUtils.logRequest(request, getClass()); 36 | return false; 37 | } 38 | 39 | if (this.isUnauthLogEnabled) { LoggerUtils.logUnAuthorizedRequest(request, getClass()); } 40 | channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, forbiddenException)); 41 | } catch (Exception e) { 42 | if (this.isUnauthLogEnabled) { LoggerUtils.logUnAuthorizedRequest(request, getClass()); } 43 | channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, forbiddenException)); 44 | return true; 45 | } 46 | return true; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/cleafy/elasticsearch/plugins/http/HttpBasicServerPlugin.java: -------------------------------------------------------------------------------- 1 | package com.cleafy.elasticsearch.plugins.http; 2 | 3 | import com.cleafy.elasticsearch.plugins.http.utils.Globals; 4 | import org.elasticsearch.common.inject.Inject; 5 | import org.elasticsearch.common.settings.Setting; 6 | import org.elasticsearch.common.settings.Settings; 7 | import org.elasticsearch.common.util.concurrent.ThreadContext; 8 | import org.elasticsearch.plugins.ActionPlugin; 9 | import org.elasticsearch.plugins.Plugin; 10 | import org.elasticsearch.rest.RestHandler; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.function.UnaryOperator; 15 | 16 | 17 | /** 18 | * @author Andrea Sessa (andrea.sessa@cleafy.com) 19 | */ 20 | public class HttpBasicServerPlugin extends Plugin implements ActionPlugin { 21 | 22 | private final boolean enabledByDefault = false; 23 | private final Settings settings; 24 | BasicRestFilter basicFilter; 25 | 26 | @Inject 27 | public HttpBasicServerPlugin(Settings settings) { 28 | this.settings = settings; 29 | this.basicFilter = new BasicRestFilter(this.settings); 30 | } 31 | 32 | public String name() { 33 | return "http-basic-server-plugin"; 34 | } 35 | 36 | public String description() { 37 | return "HTTP Basic Server Plugin"; 38 | } 39 | 40 | @Override 41 | public UnaryOperator getRestHandlerWrapper(final ThreadContext threadContext) { 42 | if (this.settings.getAsBoolean(Globals.SETTINGS_ENABLED, enabledByDefault)) { 43 | return rh -> basicFilter.wrap(rh); 44 | } 45 | return rh -> rh; 46 | } 47 | 48 | @Override 49 | public Settings additionalSettings() { 50 | if (this.settings.getAsBoolean(Globals.SETTINGS_ENABLED, enabledByDefault)) { 51 | final Settings.Builder builder = Settings.builder(); 52 | builder.put(super.additionalSettings()); 53 | return builder.build(); 54 | } else { 55 | return Settings.EMPTY; 56 | } 57 | } 58 | 59 | @Override 60 | public List> getSettings() { 61 | 62 | List> settings = new ArrayList<>(super.getSettings()); 63 | 64 | settings.add(Setting.boolSetting(Globals.SETTINGS_ENABLED, enabledByDefault, Setting.Property.NodeScope, Setting.Property.Filtered)); 65 | settings.add(Setting.simpleString(Globals.SETTINGS_USERNAME, Setting.Property.NodeScope, Setting.Property.Filtered)); 66 | settings.add(Setting.simpleString(Globals.SETTINGS_PASSWORD, Setting.Property.NodeScope, Setting.Property.Filtered)); 67 | settings.add(Setting.boolSetting(Globals.SETTINGS_LOG, false, Setting.Property.NodeScope, Setting.Property.Filtered)); 68 | 69 | return settings; 70 | } 71 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | com.cleafy.elasticsearch 7 | elasticsearch-http-basic-auth-plugin 8 | 0.3.0 9 | jar 10 | Elasticsearch Http Basic plugin 11 | Adds HTTP Basic authentication (BA) to your Elasticsearch cluster 12 | https://github.com/Cleafy/elasticsearch-http-basic-auth-plugin 13 | 2018 14 | 15 | 16 | 1 17 | INFO 18 | UTF-8 19 | 20 | 21 | 22 | 23 | org.elasticsearch 24 | elasticsearch 25 | 7.13.3 26 | provided 27 | 28 | 29 | org.elasticsearch.test 30 | framework 31 | 7.12.0 32 | test 33 | 34 | 35 | net.java.dev.jna 36 | jna 37 | 4.1.0 38 | test 39 | 40 | 41 | 42 | 43 | elasticsearch-http-basic-auth-plugin 44 | 45 | 46 | src/main/resources 47 | false 48 | 49 | 50 | 51 | 52 | 53 | org.apache.maven.plugins 54 | maven-assembly-plugin 55 | 2.6 56 | 57 | true 58 | ${project.build.directory}/releases/ 59 | 60 | ${basedir}/src/main/assemblies/plugin.xml 61 | 62 | 63 | 64 | 65 | package 66 | 67 | single 68 | 69 | 70 | 71 | 72 | 73 | 74 | org.apache.maven.plugins 75 | maven-compiler-plugin 76 | 3.3 77 | 78 | 1.8 79 | 1.8 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Build Status](https://travis-ci.org/Cleafy/elasticsearch6-http-basic.svg?branch=master)](https://github.com/Cleafy/elasticsearch6-http-basic) 3 | 4 | 5 | # HTTP Basic auth for ElasticSearch 6 | 7 | This plugin provides an extension of ElasticSearchs HTTP Transport module to enable **HTTP basic authentication** and/or 8 | **Ip based authentication**. 9 | 10 | Requesting `/` does not request authentication to simplify health check configuration. 11 | 12 | There is no way to configure this on a per index basis. 13 | 14 | 15 | ## Version Mapping 16 | 17 | | Http Basic Plugin | elasticsearch | 18 | |-----------------------------|------------------------------| 19 | | v0.0.1 | 6.3.2 | 20 | | v0.1.0 | 7.6.0 | 21 | | v0.2.0 | 7.12.0 | 22 | | v0.3.0 | 7.13.3 | 23 | 24 | ## Installation 25 | 26 | Download the desired version from https://github.com/Cleafy/elasticsearch6-http-basic/releases and copy it to `plugins/http-basic`. 27 | 28 | ## Configuration 29 | 30 | Once the plugin is installed it can be configured in the [elasticsearch modules configuration file](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/setup-configuration.html#settings). See the [elasticserach directory layout information](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/setup-dir-layout.html) for more information about the default paths of an ES installation. 31 | 32 | | Setting key | Default value | Notes | 33 | |-----------------------------------|------------------------------|-------------------------------------------------------------------------| 34 | | `http.basic.enabled` | true | **true** disables the default ES HTTP Transport module | 35 | | `http.basic.user` | "admin" | | 36 | | `http.basic.password` | "admin_pw" | 37 | | `http.basic.log` | false | enables plugin logging to ES log. Unauthenticated requests are always logged. | 38 | 39 | **Be aware that the password is stored in plain text.** 40 | 41 | ## Http basic authentication 42 | 43 | see [this article](https://en.wikipedia.org/wiki/Basic_access_authentication) 44 | 45 | ## Configuration example 46 | 47 | The following code enables plugin logging, sets user and password. 48 | 49 | ``` 50 | http.basic.enable: true 51 | http.basic.log: true 52 | http.basic.user: "some_user" 53 | http.basic.password: "some_password" 54 | ``` 55 | 56 | ## Testing 57 | 58 | **note:** localhost is a whitelisted ip as default. 59 | Considering a default configuration with **my_username** and **my_password** configured. 60 | 61 | Correct credentials 62 | ``` 63 | $ curl -v --user my_username:my_password no_local_host:9200/foo # works (returns 200) (if credentials are set in configuration) 64 | ``` 65 | 66 | Wrong credentials 67 | ``` 68 | $ curl -v --user my_username:wrong_password no_local_host:9200/ # health check, returns 200 with "{\"OK\":{}}" although Unauthorized 69 | $ curl -v --user my_username:password no_local_host:9200/foo # returns 401 70 | ``` 71 | 72 | 73 | ## Issues 74 | 75 | Please file your issue here: 76 | https://github.com/Cleafy/elasticsearch6-http-basic/issues 77 | -------------------------------------------------------------------------------- /src/main/java/com/cleafy/elasticsearch/plugins/http/auth/AuthCredentials.java: -------------------------------------------------------------------------------- 1 | package com.cleafy.elasticsearch.plugins.http.auth; 2 | 3 | import org.elasticsearch.ElasticsearchSecurityException; 4 | 5 | import java.security.MessageDigest; 6 | import java.security.NoSuchAlgorithmException; 7 | import java.util.*; 8 | 9 | public class AuthCredentials { 10 | private static final String DIGEST_ALGORITHM = "SHA-256"; 11 | private final String username; 12 | private byte[] password; 13 | private Object nativeCredentials; 14 | private final Set backendRoles = new HashSet<>(); 15 | private boolean complete; 16 | private final byte[] internalPasswordHash; 17 | private final Map attributes = new HashMap<>(); 18 | 19 | 20 | /** 21 | * Create new credentials with a username and password 22 | * 23 | * @param username The username, must not be null or empty 24 | * @param password The password, must not be null or empty 25 | * @throws IllegalArgumentException if username or password is null or empty 26 | */ 27 | public AuthCredentials(final String username, final byte[] password) { 28 | this(username, password, null); 29 | 30 | if (password == null || password.length == 0) { 31 | throw new IllegalArgumentException("password must not be null or empty"); 32 | } 33 | } 34 | 35 | private AuthCredentials(final String username, byte[] password, Object nativeCredentials, String... backendRoles) { 36 | super(); 37 | 38 | if (username == null || username.isEmpty()) { 39 | throw new IllegalArgumentException("username must not be null or empty"); 40 | } 41 | 42 | this.username = username; 43 | // make defensive copy 44 | this.password = password == null ? null : Arrays.copyOf(password, password.length); 45 | 46 | if (this.password != null) { 47 | try { 48 | MessageDigest digester = MessageDigest.getInstance(DIGEST_ALGORITHM); 49 | internalPasswordHash = digester.digest(this.password); 50 | } catch (NoSuchAlgorithmException e) { 51 | throw new ElasticsearchSecurityException("Unable to digest password", e); 52 | } 53 | } else { 54 | internalPasswordHash = null; 55 | } 56 | 57 | if (password != null) { 58 | Arrays.fill(password, (byte) '\0'); 59 | password = null; 60 | } 61 | 62 | this.nativeCredentials = nativeCredentials; 63 | nativeCredentials = null; 64 | 65 | if (backendRoles != null && backendRoles.length > 0) { 66 | this.backendRoles.addAll(Arrays.asList(backendRoles)); 67 | } 68 | } 69 | 70 | /** 71 | * Wipe password and native credentials 72 | */ 73 | public void clearSecrets() { 74 | if (password != null) { 75 | Arrays.fill(password, (byte) '\0'); 76 | password = null; 77 | } 78 | 79 | nativeCredentials = null; 80 | } 81 | 82 | public String getUsername() { 83 | return username; 84 | } 85 | 86 | /** 87 | * @return Defensive copy of the password4 88 | */ 89 | public byte[] getPassword() { 90 | // make defensive copy 91 | return password == null ? null : Arrays.copyOf(password, password.length); 92 | } 93 | 94 | public Object getNativeCredentials() { 95 | return nativeCredentials; 96 | } 97 | 98 | @Override 99 | public int hashCode() { 100 | final int prime = 31; 101 | int result = 1; 102 | result = prime * result + Arrays.hashCode(internalPasswordHash); 103 | result = prime * result + ((username == null) ? 0 : username.hashCode()); 104 | return result; 105 | } 106 | 107 | @Override 108 | public boolean equals(Object obj) { 109 | if (this == obj) 110 | return true; 111 | if (obj == null) 112 | return false; 113 | if (getClass() != obj.getClass()) 114 | return false; 115 | AuthCredentials other = (AuthCredentials) obj; 116 | if (internalPasswordHash == null || other.internalPasswordHash == null || !MessageDigest.isEqual(internalPasswordHash, other.internalPasswordHash)) 117 | return false; 118 | if (username == null) { 119 | return other.username == null; 120 | } else return username.equals(other.username); 121 | } 122 | 123 | @Override 124 | public String toString() { 125 | return "AuthCredentials [username=" + username + ", password empty=" + (password == null) + ", nativeCredentials empty=" 126 | + (nativeCredentials == null) + ",backendRoles=" + backendRoles + "]"; 127 | } 128 | 129 | /** 130 | * @return Defensive copy of the roles this user is member of. 131 | */ 132 | public Set getBackendRoles() { 133 | return new HashSet<>(backendRoles); 134 | } 135 | 136 | public boolean isComplete() { 137 | return complete; 138 | } 139 | 140 | /** 141 | * If the credentials are complete and no further roundtrips with the originator are due 142 | * then this method must be called so that the authentication flow can proceed. 143 | *

144 | * If this credentials are already marked a complete then a call to this method does nothing. 145 | * 146 | * @return this 147 | */ 148 | public AuthCredentials markComplete() { 149 | this.complete = true; 150 | return this; 151 | } 152 | 153 | public void addAttribute(String name, String value) { 154 | if (name != null && !name.isEmpty()) { 155 | this.attributes.put(name, value); 156 | } 157 | } 158 | 159 | public Map getAttributes() { 160 | return Collections.unmodifiableMap(this.attributes); 161 | } 162 | } 163 | --------------------------------------------------------------------------------