diff --git a/pom.xml b/pom.xml
index ad3cfafcb5..49db4fc449 100644
--- a/pom.xml
+++ b/pom.xml
@@ -158,6 +158,12 @@
+
+ commons-validator
+ commons-validator
+ 1.7
+
+
com.google.guava
diff --git a/securityconfig/config.yml b/securityconfig/config.yml
index 251b13aef1..fe9dd32062 100644
--- a/securityconfig/config.yml
+++ b/securityconfig/config.yml
@@ -81,7 +81,24 @@ config:
###### more information about XFF https://en.wikipedia.org/wiki/X-Forwarded-For
###### and here https://tools.ietf.org/html/rfc7239
###### and https://tomcat.apache.org/tomcat-8.0-doc/config/valve.html#Remote_IP_Valve
+ #auth_token_provider:
+ # enabled: true
+ # jwt_signing_key_hs512: "test_abc"
+ # max_validity: "1y"
+ # max_tokens_per_user: 100
authc:
+ opendistro_issued_jwt_auth_domain:
+ description: "Authenticate via Json Web Tokens issued by Opendistro Security"
+ http_enabled: false
+ transport_enabled: false
+ # This auth domain is only available for HTTP
+ order: 1
+ http_authenticator:
+ type: auth_token
+ challenge: false
+ # This auth domain automatically pulls configuration from the auth_token_provider config above
+ authentication_backend:
+ type: auth_token
kerberos_auth_domain:
http_enabled: false
transport_enabled: false
diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java
index 49f673f6dc..745df7cd47 100644
--- a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java
+++ b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java
@@ -52,10 +52,10 @@ public abstract class AbstractHTTPJwtAuthenticator implements HTTPAuthenticator
private KeyProvider keyProvider;
private JwtVerifier jwtVerifier;
- private final String jwtHeaderName;
- private final boolean isDefaultAuthHeader;
- private final String jwtUrlParameter;
- private final String subjectKey;
+ private String jwtHeaderName;
+ private boolean isDefaultAuthHeader;
+ private String jwtUrlParameter;
+ private String subjectKey;
private final String rolesKey;
public AbstractHTTPJwtAuthenticator(Settings settings, Path configPath) {
@@ -232,4 +232,11 @@ public boolean reRequestAuthentication(RestChannel channel, AuthCredentials auth
return true;
}
+ public void setAuthenticatorSettings(String jwtHeaderName, String subjectKey) {
+ this.jwtHeaderName = jwtHeaderName;
+ this.isDefaultAuthHeader = HttpHeaders.AUTHORIZATION.equalsIgnoreCase(this.jwtHeaderName);
+ this.jwtUrlParameter = null;
+ this.subjectKey = subjectKey;
+ }
+
}
diff --git a/src/main/java/com/amazon/dlic/auth/ldap/backend/LDAPAuthenticationBackend.java b/src/main/java/com/amazon/dlic/auth/ldap/backend/LDAPAuthenticationBackend.java
index fc329728bc..33910e564f 100755
--- a/src/main/java/com/amazon/dlic/auth/ldap/backend/LDAPAuthenticationBackend.java
+++ b/src/main/java/com/amazon/dlic/auth/ldap/backend/LDAPAuthenticationBackend.java
@@ -26,6 +26,7 @@
import java.util.Set;
import java.util.UUID;
+
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -42,12 +43,12 @@
import com.amazon.dlic.auth.ldap.util.ConfigConstants;
import com.amazon.dlic.auth.ldap.util.LdapHelper;
import com.amazon.dlic.auth.ldap.util.Utils;
-import com.amazon.opendistroforelasticsearch.security.auth.AuthenticationBackend;
+import com.amazon.opendistroforelasticsearch.security.auth.SyncAuthenticationBackend;
import com.amazon.opendistroforelasticsearch.security.user.AuthCredentials;
import com.amazon.opendistroforelasticsearch.security.user.User;
import com.amazon.opendistroforelasticsearch.security.support.WildcardMatcher;
-public class LDAPAuthenticationBackend implements AuthenticationBackend {
+public class LDAPAuthenticationBackend implements SyncAuthenticationBackend {
static final int ZERO_PLACEHOLDER = 0;
static final String DEFAULT_USERBASE = "";
diff --git a/src/main/java/com/amazon/dlic/auth/ldap2/LDAPAuthenticationBackend2.java b/src/main/java/com/amazon/dlic/auth/ldap2/LDAPAuthenticationBackend2.java
index a576b773be..b6bc7fb67f 100755
--- a/src/main/java/com/amazon/dlic/auth/ldap2/LDAPAuthenticationBackend2.java
+++ b/src/main/java/com/amazon/dlic/auth/ldap2/LDAPAuthenticationBackend2.java
@@ -43,13 +43,13 @@
import com.amazon.dlic.auth.ldap.util.ConfigConstants;
import com.amazon.dlic.auth.ldap.util.Utils;
import com.amazon.dlic.util.SettingsBasedSSLConfigurator.SSLConfigException;
-import com.amazon.opendistroforelasticsearch.security.auth.AuthenticationBackend;
+import com.amazon.opendistroforelasticsearch.security.auth.SyncAuthenticationBackend;
import com.amazon.opendistroforelasticsearch.security.auth.Destroyable;
import com.amazon.opendistroforelasticsearch.security.user.AuthCredentials;
import com.amazon.opendistroforelasticsearch.security.user.User;
import com.amazon.opendistroforelasticsearch.security.support.WildcardMatcher;
-public class LDAPAuthenticationBackend2 implements AuthenticationBackend, Destroyable {
+public class LDAPAuthenticationBackend2 implements SyncAuthenticationBackend, Destroyable {
protected static final Logger log = LogManager.getLogger(LDAPAuthenticationBackend2.class);
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/OpenDistroSecurityPlugin.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/OpenDistroSecurityPlugin.java
index 42adff1243..570f9335db 100644
--- a/src/main/java/com/amazon/opendistroforelasticsearch/security/OpenDistroSecurityPlugin.java
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/OpenDistroSecurityPlugin.java
@@ -51,6 +51,7 @@
import com.amazon.opendistroforelasticsearch.security.auditlog.impl.AuditLogImpl;
import com.amazon.opendistroforelasticsearch.security.compliance.ComplianceIndexingOperationListenerImpl;
import com.amazon.opendistroforelasticsearch.security.configuration.DlsFlsValveImpl;
+import com.amazon.opendistroforelasticsearch.security.authtoken.AuthTokenService;
import com.amazon.opendistroforelasticsearch.security.configuration.OpenDistroSecurityFlsDlsIndexSearcherWrapper;
import com.amazon.opendistroforelasticsearch.security.configuration.PrivilegesInterceptorImpl;
import com.amazon.opendistroforelasticsearch.security.configuration.Salt;
@@ -798,7 +799,10 @@ public Collection
+ * @param user The authenticated user to populate with backend roles, never null
+ * @param credentials Credentials to authenticate to the authorization backend, maybe null.
+ * This parameter is for future usage, currently always empty credentials are passed!
+ * @throws ElasticsearchSecurityException in case when the authorization backend cannot be reached
+ * or the {@code credentials} are insufficient to authenticate to the authorization backend.
+ */
+ void fillRoles(User user, AuthCredentials credentials) throws ElasticsearchSecurityException;
+
+ default void retrieveRoles(User user, AuthCredentials credentials, Consumer> onSuccess, Consumer onFailure) {
+ try {
+ fillRoles(user, credentials);
+ // TODO notsonice
+
+ onSuccess.accept(Collections.emptyList());
+ } catch (Exception e) {
+ onFailure.accept(e);
+ }
+ }
+
+}
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/auth/internal/InternalAuthenticationBackend.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/auth/internal/InternalAuthenticationBackend.java
index 68aea3f5ce..808052dbcc 100644
--- a/src/main/java/com/amazon/opendistroforelasticsearch/security/auth/internal/InternalAuthenticationBackend.java
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/auth/internal/InternalAuthenticationBackend.java
@@ -39,17 +39,18 @@
import java.util.Map;
import java.util.Map.Entry;
+
import org.bouncycastle.crypto.generators.OpenBSDBCrypt;
import org.elasticsearch.ElasticsearchSecurityException;
-import com.amazon.opendistroforelasticsearch.security.auth.AuthenticationBackend;
-import com.amazon.opendistroforelasticsearch.security.auth.AuthorizationBackend;
+import com.amazon.opendistroforelasticsearch.security.auth.SyncAuthenticationBackend;
+import com.amazon.opendistroforelasticsearch.security.auth.SyncAuthorizationBackend;
import com.amazon.opendistroforelasticsearch.security.securityconf.InternalUsersModel;
import com.amazon.opendistroforelasticsearch.security.user.AuthCredentials;
import com.amazon.opendistroforelasticsearch.security.user.User;
import org.greenrobot.eventbus.Subscribe;
-public class InternalAuthenticationBackend implements AuthenticationBackend, AuthorizationBackend {
+public class InternalAuthenticationBackend implements SyncAuthenticationBackend, SyncAuthorizationBackend {
private InternalUsersModel internalUsersModel;
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/auth/internal/NoOpAuthenticationBackend.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/auth/internal/NoOpAuthenticationBackend.java
index e1ef693c3b..1ed75d07a1 100644
--- a/src/main/java/com/amazon/opendistroforelasticsearch/security/auth/internal/NoOpAuthenticationBackend.java
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/auth/internal/NoOpAuthenticationBackend.java
@@ -32,13 +32,14 @@
import java.nio.file.Path;
+
import org.elasticsearch.common.settings.Settings;
-import com.amazon.opendistroforelasticsearch.security.auth.AuthenticationBackend;
+import com.amazon.opendistroforelasticsearch.security.auth.SyncAuthenticationBackend;
import com.amazon.opendistroforelasticsearch.security.user.AuthCredentials;
import com.amazon.opendistroforelasticsearch.security.user.User;
-public class NoOpAuthenticationBackend implements AuthenticationBackend {
+public class NoOpAuthenticationBackend implements SyncAuthenticationBackend {
public NoOpAuthenticationBackend(final Settings settings, final Path configPath) {
super();
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/AuthToken.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/AuthToken.java
new file mode 100644
index 0000000000..b69bcad289
--- /dev/null
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/AuthToken.java
@@ -0,0 +1,46 @@
+package com.amazon.opendistroforelasticsearch.security.authtoken;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.time.Instant;
+
+public class AuthToken {
+
+ private static final Logger log = LogManager.getLogger(AuthToken.class);
+
+ private static final long serialVersionUID = 6038589333544878668L;
+ private String userName;
+ private String tokenName;
+ private String id;
+ private Instant creationTime;
+ private Instant expiryTime;
+ private Instant revokedAt;
+
+ AuthToken(){
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public String getTokenName() {
+ return tokenName;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public Instant getCreationTime() {
+ return creationTime;
+ }
+
+ public Instant getExpiryTime() {
+ return expiryTime;
+ }
+
+ public Instant getRevokedAt() {
+ return revokedAt;
+ }
+}
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/AuthTokenService.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/AuthTokenService.java
new file mode 100644
index 0000000000..725e8d56f3
--- /dev/null
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/AuthTokenService.java
@@ -0,0 +1,30 @@
+package com.amazon.opendistroforelasticsearch.security.authtoken;
+
+import com.amazon.opendistroforelasticsearch.security.authtoken.config.AuthTokenServiceConfig;
+import org.apache.cxf.rs.security.jose.jwt.JwtException;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+
+import java.util.Map;
+public class AuthTokenService {
+
+ public static final String USER_TYPE = "opendistro_security_auth_token";
+ public static final String USER_TYPE_FULL_CURRENT_PERMISSIONS = "opendistro_security_auth_token_full_current_permissions";
+
+ public AuthTokenService() {
+ }
+
+ public void setConfig(AuthTokenServiceConfig config) {
+ }
+
+ public AuthToken getTokenByClaims(Map claims) {
+ return null;
+ }
+
+ public JwtToken createToken() {
+ return null;
+ }
+
+ public JwtToken getVerifiedJwtToken(String encodedJwt) throws JwtException {
+ return null;
+ }
+}
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/authenticator/AuthTokenAuthenticationBackend.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/authenticator/AuthTokenAuthenticationBackend.java
new file mode 100644
index 0000000000..7dff8dac48
--- /dev/null
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/authenticator/AuthTokenAuthenticationBackend.java
@@ -0,0 +1,48 @@
+package com.amazon.opendistroforelasticsearch.security.authtoken.authenticator;
+
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.function.Consumer;
+
+import com.amazon.opendistroforelasticsearch.security.auth.AuthenticationBackend;
+import com.amazon.opendistroforelasticsearch.security.authtoken.AuthTokenService;
+import com.amazon.opendistroforelasticsearch.security.user.AuthCredentials;
+import com.amazon.opendistroforelasticsearch.security.user.User;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.elasticsearch.common.settings.Settings;
+
+public class AuthTokenAuthenticationBackend implements AuthenticationBackend {
+
+ private static final Logger log = LogManager.getLogger(AuthTokenAuthenticationBackend.class);
+
+ private AuthTokenService authTokenService;
+
+ public AuthTokenAuthenticationBackend(final Settings settings, final Path configPath) {
+ }
+
+ public void setAuthTokenService(AuthTokenService authTokenService) {
+ this.authTokenService = authTokenService;
+ }
+
+ @Override
+ public String getType() {
+ return "opendistro_security_auth_token";
+ }
+
+ @Override
+ public void authenticate(AuthCredentials credentials, Consumer onSuccess, Consumer onFailure) {
+ }
+
+ @Override
+ public boolean exists(User user) {
+ // This is only related to impersonation. Auth tokens don't support impersonation.
+ return false;
+ }
+
+ @Override
+ public UserCachingPolicy userCachingPolicy() {
+ return UserCachingPolicy.NEVER;
+ }
+
+}
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/authenticator/AuthTokenHttpJwtAuthenticator.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/authenticator/AuthTokenHttpJwtAuthenticator.java
new file mode 100644
index 0000000000..e44ea4e29a
--- /dev/null
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/authenticator/AuthTokenHttpJwtAuthenticator.java
@@ -0,0 +1,73 @@
+package com.amazon.opendistroforelasticsearch.security.authtoken.authenticator;
+
+import java.nio.file.Path;
+
+import com.amazon.dlic.auth.http.jwt.AbstractHTTPJwtAuthenticator;
+import com.amazon.dlic.auth.http.jwt.keybyoidc.KeyProvider;
+import com.amazon.opendistroforelasticsearch.security.authtoken.AuthTokenService;
+import com.amazon.opendistroforelasticsearch.security.user.AuthCredentials;
+import org.apache.cxf.rs.security.jose.jwt.JwtClaims;
+import org.apache.cxf.rs.security.jose.jwt.JwtConstants;
+import org.apache.cxf.rs.security.jose.jwt.JwtException;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.elasticsearch.ElasticsearchSecurityException;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.rest.RestRequest;
+
+public class AuthTokenHttpJwtAuthenticator extends AbstractHTTPJwtAuthenticator {
+
+ private final static Logger log = LogManager.getLogger(AuthTokenHttpJwtAuthenticator.class);
+
+ private AuthTokenService authTokenService;
+
+ public AuthTokenHttpJwtAuthenticator(final Settings settings, final Path configPath) {
+ super(settings, configPath);
+ setAuthenticatorSettings("Authorization", JwtConstants.CLAIM_SUBJECT);
+ }
+
+ public void setAuthTokenService(AuthTokenService authTokenService) {
+ this.authTokenService = authTokenService;
+ }
+
+ private AuthCredentials extractCredentials0(RestRequest request) throws ElasticsearchSecurityException {
+ String encodedJwt = getJwtTokenString(request);
+ if (Strings.isNullOrEmpty(encodedJwt)) {
+ return null;
+ }
+
+ try {
+ JwtToken jwt = authTokenService.getVerifiedJwtToken(encodedJwt);
+
+ JwtClaims claims = jwt.getClaims();
+
+ String subject = extractSubject(claims);
+
+ if (subject == null) {
+ log.error("No subject found in JWT token: " + claims);
+ return null;
+ }
+ return AuthCredentials.forUser(subject).claims(claims.asMap()).complete().build();
+
+ } catch (JwtException e) {
+ log.info("JWT is invalid", e);
+ return null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+
+ }
+
+ @Override
+ protected KeyProvider initKeyProvider(Settings settings, Path configPath) throws Exception {
+ return null;
+ }
+
+ @Override
+ public String getType() {
+ return "opendistro_security_auth_token";
+ }
+}
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/config/AuthTokenServiceConfig.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/config/AuthTokenServiceConfig.java
new file mode 100644
index 0000000000..7c10200a41
--- /dev/null
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/authtoken/config/AuthTokenServiceConfig.java
@@ -0,0 +1,13 @@
+package com.amazon.opendistroforelasticsearch.security.authtoken.config;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+
+public class AuthTokenServiceConfig {
+
+ public static final String DEFAULT_AUDIENCE = "opendistro_security_authtoken";
+
+ public static AuthTokenServiceConfig parse(JsonNode jsonNode) {
+ return null;
+ }
+}
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigFactory.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigFactory.java
index e971ced989..36f1d5c46f 100644
--- a/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigFactory.java
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigFactory.java
@@ -40,9 +40,12 @@
import java.util.concurrent.atomic.AtomicBoolean;
import com.amazon.opendistroforelasticsearch.security.auditlog.config.AuditConfig;
+import com.amazon.opendistroforelasticsearch.security.authtoken.AuthTokenService;
+import com.amazon.opendistroforelasticsearch.security.authtoken.config.AuthTokenServiceConfig;
import com.amazon.opendistroforelasticsearch.security.securityconf.impl.NodesDn;
import com.amazon.opendistroforelasticsearch.security.securityconf.impl.WhitelistingSettings;
import com.amazon.opendistroforelasticsearch.security.support.WildcardMatcher;
+import com.fasterxml.jackson.core.JsonPointer;
import com.google.common.collect.ImmutableList;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -83,6 +86,7 @@ public class DynamicConfigFactory implements Initializable, ConfigurationChangeL
private static SecurityDynamicConfiguration staticActionGroups = SecurityDynamicConfiguration.empty();
private static SecurityDynamicConfiguration staticTenants = SecurityDynamicConfiguration.empty();
private static final WhitelistingSettings defaultWhitelistingSettings = new WhitelistingSettings();
+ private final String auth_token_provider_path = "/dynamic/auth_token_provider";
static void resetStatics() {
staticRoles = SecurityDynamicConfiguration.empty();
@@ -127,15 +131,17 @@ public final static SecurityDynamicConfiguration> addStatics(SecurityDynamicCo
private final Settings esSettings;
private final Path configPath;
private final InternalAuthenticationBackend iab = new InternalAuthenticationBackend();
+ private final AuthTokenService authTokenService;
SecurityDynamicConfiguration> config;
public DynamicConfigFactory(ConfigurationRepository cr, final Settings esSettings,
- final Path configPath, Client client, ThreadPool threadPool, ClusterInfoHolder cih) {
+ final Path configPath, Client client, ThreadPool threadPool, ClusterInfoHolder cih, AuthTokenService authTokenService) {
super();
this.cr = cr;
this.esSettings = esSettings;
this.configPath = configPath;
+ this.authTokenService = authTokenService;
if(esSettings.getAsBoolean(ConfigConstants.OPENDISTRO_SECURITY_UNSUPPORTED_LOAD_STATIC_RESOURCES, true)) {
try {
@@ -235,12 +241,19 @@ public void onChange(Map> typeToConfig) {
//rebuild v7 Models
- dcm = new DynamicConfigModelV7(getConfigV7(config), esSettings, configPath, iab);
+ ConfigV7 configV7 = getConfigV7(config);
+ dcm = new DynamicConfigModelV7(configV7, esSettings, configPath, iab, authTokenService);
ium = new InternalUsersModelV7((SecurityDynamicConfiguration) internalusers,
(SecurityDynamicConfiguration) roles,
(SecurityDynamicConfiguration) rolesmapping);
cm = new ConfigModelV7((SecurityDynamicConfiguration) roles,(SecurityDynamicConfiguration)rolesmapping, (SecurityDynamicConfiguration)actionGroups, (SecurityDynamicConfiguration) tenants,dcm, esSettings);
-
+ try{
+ AuthTokenServiceConfig config = AuthTokenServiceConfig.parse(getAuthTokenConfig(configV7));
+ authTokenService.setConfig(config);
+ } catch (Exception exception) {
+ log.error("Error occured while parsing the auth_token_provider configuration");
+ exception.printStackTrace();
+ }
} else {
//rebuild v6 Models
@@ -263,6 +276,25 @@ public void onChange(Map> typeToConfig) {
initialized.set(true);
}
+
+ private JsonNode getAuthTokenConfig(Object entry) {
+
+
+ if (entry == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("No config entry 'config'" + " in " + config);
+ }
+ }
+
+ JsonNode subNode = DefaultObjectMapper.objectMapper.valueToTree(entry).at(JsonPointer.compile(auth_token_provider_path));
+
+ if (subNode == null || subNode.isMissingNode()) {
+ if (log.isDebugEnabled()) {
+ log.debug("JsonPointer " + auth_token_provider_path + " not found");
+ }
+ }
+ return subNode;
+ }
private static ConfigV6 getConfigV6(SecurityDynamicConfiguration> sdc) {
@SuppressWarnings("unchecked")
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigModel.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigModel.java
index c3d00265fa..80bac8fc9c 100644
--- a/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigModel.java
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigModel.java
@@ -39,6 +39,8 @@
import java.util.Set;
import java.util.SortedSet;
+import com.amazon.opendistroforelasticsearch.security.authtoken.authenticator.AuthTokenAuthenticationBackend;
+import com.amazon.opendistroforelasticsearch.security.authtoken.authenticator.AuthTokenHttpJwtAuthenticator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -108,6 +110,9 @@ public DynamicConfigModel() {
authImplMap.put("ldap2_c", "com.amazon.dlic.auth.ldap2.LDAPAuthenticationBackend2");
authImplMap.put("ldap2_z", "com.amazon.dlic.auth.ldap2.LDAPAuthorizationBackend2");
+ authImplMap.put("auth_token_h", AuthTokenHttpJwtAuthenticator.class.getName());
+ authImplMap.put("auth_token_c", AuthTokenAuthenticationBackend.class.getName());
+
authImplMap.put("basic_h", HTTPBasicAuthenticator.class.getName());
authImplMap.put("proxy_h", HTTPProxyAuthenticator.class.getName());
authImplMap.put("extended-proxy_h", HTTPExtendedProxyAuthenticator.class.getName());
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigModelV7.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigModelV7.java
index 16aca8c6da..4dd71cfb8c 100644
--- a/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigModelV7.java
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/DynamicConfigModelV7.java
@@ -43,6 +43,9 @@
import java.util.SortedSet;
import java.util.TreeSet;
+import com.amazon.opendistroforelasticsearch.security.authtoken.AuthTokenService;
+import com.amazon.opendistroforelasticsearch.security.authtoken.authenticator.AuthTokenAuthenticationBackend;
+import com.amazon.opendistroforelasticsearch.security.authtoken.authenticator.AuthTokenHttpJwtAuthenticator;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
@@ -76,18 +79,20 @@ public class DynamicConfigModelV7 extends DynamicConfigModel {
private Set transportAuthorizers;
private List destroyableComponents;
private final InternalAuthenticationBackend iab;
+ private final AuthTokenService authTokenService;
private List ipAuthFailureListeners;
private Multimap authBackendFailureListeners;
private List> ipClientBlockRegistries;
private Multimap> authBackendClientBlockRegistries;
- public DynamicConfigModelV7(ConfigV7 config, Settings esSettings, Path configPath, InternalAuthenticationBackend iab) {
+ public DynamicConfigModelV7(ConfigV7 config, Settings esSettings, Path configPath, InternalAuthenticationBackend iab, AuthTokenService authTokenService) {
super();
this.config = config;
this.esSettings = esSettings;
this.configPath = configPath;
this.iab = iab;
+ this.authTokenService = authTokenService;
buildAAA();
}
@Override
@@ -282,6 +287,10 @@ private void buildAAA() {
, configPath);
}
+ if (authenticationBackend instanceof AuthTokenAuthenticationBackend) {
+ ((AuthTokenAuthenticationBackend) authenticationBackend).setAuthTokenService(this.authTokenService);
+ }
+
String httpAuthenticatorType = ad.getValue().http_authenticator.type; //no default
HTTPAuthenticator httpAuthenticator = httpAuthenticatorType==null?null: (HTTPAuthenticator) newInstance(httpAuthenticatorType,"h",
Settings.builder().put(esSettings)
@@ -290,6 +299,10 @@ private void buildAAA() {
, configPath);
+ if ( httpAuthenticator instanceof AuthTokenHttpJwtAuthenticator) {
+ ((AuthTokenHttpJwtAuthenticator) httpAuthenticator).setAuthTokenService(this.authTokenService);
+ }
+
final AuthDomain _ad = new AuthDomain(authenticationBackend, httpAuthenticator,
ad.getValue().http_authenticator.challenge, ad.getValue().order);
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/impl/v7/ConfigV7.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/impl/v7/ConfigV7.java
index 656d428324..fb894dac18 100644
--- a/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/impl/v7/ConfigV7.java
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/securityconf/impl/v7/ConfigV7.java
@@ -124,11 +124,12 @@ public static class Dynamic {
public String hosts_resolver_mode = "ip-only";
public String transport_userrname_attribute;
public boolean do_not_fail_on_forbidden_empty;
-
+ public HashMap auth_token_provider = null;
+
@Override
public String toString() {
return "Dynamic [filtered_alias_mode=" + filtered_alias_mode + ", kibana=" + kibana + ", http=" + http + ", authc=" + authc + ", authz="
- + authz + "]";
+ + authz + ", auth_token_provider=" + auth_token_provider + "]";
}
}
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/support/ModuleType.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/support/ModuleType.java
index 46a1261fb3..ccde4a4c17 100644
--- a/src/main/java/com/amazon/opendistroforelasticsearch/security/support/ModuleType.java
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/support/ModuleType.java
@@ -46,6 +46,8 @@
import com.amazon.opendistroforelasticsearch.security.http.proxy.HTTPExtendedProxyAuthenticator;
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor;
import com.amazon.opendistroforelasticsearch.security.transport.InterClusterRequestEvaluator;
+import com.amazon.opendistroforelasticsearch.security.authtoken.authenticator.AuthTokenAuthenticationBackend;
+import com.amazon.opendistroforelasticsearch.security.authtoken.authenticator.AuthTokenHttpJwtAuthenticator;
public enum ModuleType implements Serializable {
@@ -60,9 +62,11 @@ public enum ModuleType implements Serializable {
OPENID_AUTHENTICATION_BACKEND("OpenID authentication backend", "com.amazon.dlic.auth.http.jwt.keybyoidc.HTTPJwtKeyByOpenIdConnectAuthenticator", Boolean.TRUE),
SAML_AUTHENTICATION_BACKEND("SAML authentication backend", "com.amazon.dlic.auth.http.saml.HTTPSamlAuthenticator", Boolean.TRUE),
INTERNAL_USERS_AUTHENTICATION_BACKEND("Internal users authentication backend", InternalAuthenticationBackend.class.getName(), Boolean.FALSE),
+ AUTHTOKEN_AUTHENTICATION_BACKEND("Internal users authentication backend", AuthTokenAuthenticationBackend.class.getName(), Boolean.FALSE),
NOOP_AUTHENTICATION_BACKEND("Noop authentication backend", NoOpAuthenticationBackend.class.getName(), Boolean.FALSE),
NOOP_AUTHORIZATION_BACKEND("Noop authorization backend", NoOpAuthorizationBackend.class.getName(), Boolean.FALSE),
HTTP_BASIC_AUTHENTICATOR("HTTP Basic Authenticator", HTTPBasicAuthenticator.class.getName(), Boolean.FALSE),
+ HTTP_AUTHTOKEN_AUTHENTICATOR("HTTP Auth Token Authenticator" , AuthTokenHttpJwtAuthenticator.class.getName(), Boolean.TRUE),
HTTP_PROXY_AUTHENTICATOR("HTTP Proxy Authenticator", HTTPProxyAuthenticator.class.getName(), Boolean.FALSE),
HTTP_EXT_PROXY_AUTHENTICATOR("HTTP Extended Proxy Authenticator", HTTPExtendedProxyAuthenticator.class.getName(), Boolean.FALSE),
HTTP_CLIENTCERT_AUTHENTICATOR("HTTP Client Certificate Authenticator", HTTPClientCertAuthenticator.class.getName(), Boolean.FALSE),
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/user/AuthCredentials.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/user/AuthCredentials.java
index 94fca45b5b..df9c6d7e3d 100644
--- a/src/main/java/com/amazon/opendistroforelasticsearch/security/user/AuthCredentials.java
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/user/AuthCredentials.java
@@ -30,6 +30,7 @@
package com.amazon.opendistroforelasticsearch.security.user;
+import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
@@ -57,6 +58,10 @@ public final class AuthCredentials {
private boolean complete;
private final byte[] internalPasswordHash;
private final Map attributes = new HashMap<>();
+ // claims obtained from AuthToken
+ private Map claims = new HashMap<>();
+ // User roles wont be cached by BackendRegistry if set to true
+ private boolean authzComplete;
/**
* Create new credentials with a username and native credentials
@@ -66,7 +71,7 @@ public final class AuthCredentials {
* @throws IllegalArgumentException if username or nativeCredentials are null or empty
*/
public AuthCredentials(final String username, final Object nativeCredentials) {
- this(username, null, nativeCredentials);
+ this(username, null, nativeCredentials, null, null);
if (nativeCredentials == null) {
throw new IllegalArgumentException("nativeCredentials must not be null or empty");
@@ -81,7 +86,7 @@ public AuthCredentials(final String username, final Object nativeCredentials) {
* @throws IllegalArgumentException if username or password is null or empty
*/
public AuthCredentials(final String username, final byte[] password) {
- this(username, password, null);
+ this(username, password, null, null, null);
if (password == null || password.length == 0) {
throw new IllegalArgumentException("password must not be null or empty");
@@ -96,10 +101,11 @@ public AuthCredentials(final String username, final byte[] password) {
* @throws IllegalArgumentException if username is null or empty
*/
public AuthCredentials(final String username, String... backendRoles) {
- this(username, null, null, backendRoles);
+ this(username, null, null, null, backendRoles);
}
- private AuthCredentials(final String username, byte[] password, Object nativeCredentials, String... backendRoles) {
+ private AuthCredentials(final String username, byte[] password, Object nativeCredentials, Map claims,
+ String... backendRoles) {
super();
if (username == null || username.isEmpty()) {
@@ -132,6 +138,12 @@ private AuthCredentials(final String username, byte[] password, Object nativeCre
if(backendRoles != null && backendRoles.length > 0) {
this.backendRoles.addAll(Arrays.asList(backendRoles));
}
+
+ if (claims != null) {
+ this.claims = Collections.unmodifiableMap(claims);
+ } else {
+ this.claims = new HashMap<>();
+ }
}
/**
@@ -191,8 +203,9 @@ public boolean equals(Object obj) {
@Override
public String toString() {
- return "AuthCredentials [username=" + username + ", password empty=" + (password == null) + ", nativeCredentials empty="
- + (nativeCredentials == null) + ",backendRoles="+backendRoles+"]";
+ return "AuthCredentials [username=" + username + ", password empty=" + (password == null) + ", " +
+ "nativeCredentials empty="
+ + (nativeCredentials == null) + ",backendRoles=" + backendRoles + "]";
}
/**
@@ -229,4 +242,138 @@ public void addAttribute(String name, String value) {
public Map getAttributes() {
return Collections.unmodifiableMap(this.attributes);
}
+
+ public Map getClaims() {
+ return claims;
+ }
+
+ public boolean isAuthzComplete() {
+ return authzComplete;
+ }
+
+ public static class Builder {
+ private static final String DIGEST_ALGORITHM = "SHA-256";
+ private String username;
+ private byte[] password;
+ private Object nativeCredentials;
+ private Set backendRoles = new HashSet<>();
+ private boolean complete;
+ private byte[] internalPasswordHash;
+ private Map attributes = new HashMap<>();
+ private Map claims = new HashMap<>();
+ private boolean authzComplete;
+
+ public Builder() {
+
+ }
+
+ public Builder username(String username) {
+ this.username = username;
+ return this;
+ }
+
+ public Builder password(byte[] password) {
+ if (password == null || password.length == 0) {
+ throw new IllegalArgumentException("password must not be null or empty");
+ }
+
+ this.password = Arrays.copyOf(password, password.length);
+
+ try {
+ MessageDigest digester = MessageDigest.getInstance(DIGEST_ALGORITHM);
+ internalPasswordHash = digester.digest(this.password);
+ } catch (NoSuchAlgorithmException e) {
+ throw new ElasticsearchSecurityException("Unable to digest password", e);
+ }
+
+ Arrays.fill(password, (byte) '\0');
+
+ return this;
+ }
+
+ public Builder password(String password) {
+ return this.password(password.getBytes(StandardCharsets.UTF_8));
+ }
+
+ public Builder nativeCredentials(Object nativeCredentials) {
+ if (nativeCredentials == null) {
+ throw new IllegalArgumentException("nativeCredentials must not be null or empty");
+ }
+ this.nativeCredentials = nativeCredentials;
+ return this;
+ }
+
+ public Builder backendRoles(String... backendRoles) {
+ if (backendRoles == null) {
+ return this;
+ }
+
+ this.backendRoles.addAll(Arrays.asList(backendRoles));
+ return this;
+ }
+
+ /**
+ * 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.
+ */
+ public Builder complete() {
+ this.complete = true;
+ return this;
+ }
+
+ public Builder authzComplete() {
+ this.authzComplete = true;
+ return this;
+ }
+
+ public Builder oldAttribute(String name, String value) {
+ if (name != null && !name.isEmpty()) {
+ this.attributes.put(name, value);
+ }
+ return this;
+ }
+
+ public Builder oldAttributes(Map map) {
+ this.attributes.putAll(map);
+ return this;
+ }
+
+ public Builder prefixOldAttributes(String keyPrefix, Map map) {
+ for (Map.Entry entry : map.entrySet()) {
+ this.attributes.put(keyPrefix + entry.getKey(), entry.getValue() != null ?
+ entry.getValue().toString() : null);
+ }
+ return this;
+ }
+
+ public Builder claims(Map map) {
+ this.claims.putAll(map);
+ return this;
+ }
+
+
+ public String getUsername() {
+ return username;
+ }
+
+ public AuthCredentials build() {
+ int n = backendRoles.size();
+ String roles[] = new String[n];
+ System.arraycopy(backendRoles.toArray(), 0, roles, 0, n);
+
+ AuthCredentials result = new AuthCredentials(username, password, nativeCredentials, claims, roles);
+ result.complete = this.complete;
+ result.authzComplete = this.authzComplete;
+ this.password = null;
+ this.nativeCredentials = null;
+ this.internalPasswordHash = null;
+ return result;
+ }
+ }
+
+ public static Builder forUser(String username) {
+ return new Builder().username(username);
+ }
}
diff --git a/src/main/java/com/amazon/opendistroforelasticsearch/security/user/User.java b/src/main/java/com/amazon/opendistroforelasticsearch/security/user/User.java
index c04f8de536..5e968ba1b6 100644
--- a/src/main/java/com/amazon/opendistroforelasticsearch/security/user/User.java
+++ b/src/main/java/com/amazon/opendistroforelasticsearch/security/user/User.java
@@ -39,6 +39,7 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.Arrays;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
@@ -55,7 +56,7 @@
public class User implements Serializable, Writeable, CustomAttributesAware {
public static final User ANONYMOUS = new User("opendistro_security_anonymous", Lists.newArrayList("opendistro_security_anonymous_backendrole"), null);
-
+
private static final long serialVersionUID = -5500938501822658596L;
private final String name;
/**
@@ -66,19 +67,27 @@ public class User implements Serializable, Writeable, CustomAttributesAware {
private String requestedTenant;
private Map attributes = new HashMap<>();
private boolean isInjected = false;
+ // To check the user is of type AuthToken
+ private String type;
+ // Contains the id for authToken
+ private final Object specialAuthzConfig;
+ // User roles wont be cached by BackendRegistry if set to true
+ private boolean authzComplete;
public User(final StreamInput in) throws IOException {
super();
name = in.readString();
+ type = in.readOptionalString();
roles.addAll(in.readList(StreamInput::readString));
requestedTenant = in.readString();
attributes = in.readMap(StreamInput::readString, StreamInput::readString);
openDistroSecurityRoles.addAll(in.readList(StreamInput::readString));
+ specialAuthzConfig = null;
}
-
+
/**
* Create a new authenticated user
- *
+ *
* @param name The username (must not be null or empty)
* @param roles Roles of which the user is a member off (maybe null)
* @param customAttributes Custom attributes associated with this (maybe null)
@@ -92,20 +101,37 @@ public User(final String name, final Collection roles, final AuthCredent
}
this.name = name;
+ this.type = null;
+ this.specialAuthzConfig = null;
+ configureUser(name, roles, customAttributes);
+ }
+
+ public User(final String name, String type, final Collection roles, final Set openDistroSecurityRoles, final AuthCredentials customAttributes, Object specialAuthzConfig) {
+ super();
+ if (name == null || name.isEmpty()) {
+ throw new IllegalArgumentException("name must not be null or empty");
+ }
+ this.name = name;
+ this.type = type;
+ this.openDistroSecurityRoles.addAll(openDistroSecurityRoles);
+ this.specialAuthzConfig = specialAuthzConfig;
+ configureUser(name, roles, customAttributes);
+ }
+
+ private void configureUser(final String name, final Collection roles, final AuthCredentials customAttributes) {
if (roles != null) {
this.addRoles(roles);
}
-
- if(customAttributes != null) {
+
+ if (customAttributes != null) {
this.attributes.putAll(customAttributes.getAttributes());
}
-
}
/**
* Create a new authenticated user without roles and attributes
- *
+ *
* @param name The username (must not be null or empty)
* @throws IllegalArgumentException if name is null or empty
*/
@@ -118,7 +144,7 @@ public final String getName() {
}
/**
- *
+ *
* @return A unmodifiable set of the backend roles this user is a member of
*/
public final Set getRoles() {
@@ -127,7 +153,7 @@ public final Set getRoles() {
/**
* Associate this user with a backend role
- *
+ *
* @param role The backend role
*/
public final void addRole(final String role) {
@@ -136,7 +162,7 @@ public final void addRole(final String role) {
/**
* Associate this user with a set of backend roles
- *
+ *
* @param roles The backend roles
*/
public final void addRoles(final Collection roles) {
@@ -147,7 +173,7 @@ public final void addRoles(final Collection roles) {
/**
* Check if this user is a member of a backend role
- *
+ *
* @param role The backend role
* @return true if this user is a member of the backend role, false otherwise
*/
@@ -157,7 +183,7 @@ public final boolean isUserInRole(final String role) {
/**
* Associate this user with a set of backend roles
- *
+ *
* @param roles The backend roles
*/
public final void addAttributes(final Map attributes) {
@@ -165,7 +191,7 @@ public final void addAttributes(final Map attributes) {
this.attributes.putAll(attributes);
}
}
-
+
public final String getRequestedTenant() {
return requestedTenant;
}
@@ -173,8 +199,8 @@ public final String getRequestedTenant() {
public final void setRequestedTenant(String requestedTenant) {
this.requestedTenant = requestedTenant;
}
-
-
+
+
public boolean isInjected() {
return isInjected;
}
@@ -224,7 +250,7 @@ public final boolean equals(final Object obj) {
/**
* Copy all backend roles from another user
- *
+ *
* @param user The user from which the backend roles should be copied over
*/
public final void copyRolesFrom(final User user) {
@@ -244,7 +270,7 @@ public void writeTo(StreamOutput out) throws IOException {
/**
* Get the custom attributes associated with this user
- *
+ *
* @return A modifiable map with all the current custom attributes associated with this user
*/
public synchronized final Map getCustomAttributesMap() {
@@ -253,14 +279,128 @@ public synchronized final Map getCustomAttributesMap() {
}
return attributes;
}
-
+
public final void addOpenDistroSecurityRoles(final Collection securityRoles) {
if(securityRoles != null && this.openDistroSecurityRoles != null) {
this.openDistroSecurityRoles.addAll(securityRoles);
}
}
-
+
public final Set getOpenDistroSecurityRoles() {
return this.openDistroSecurityRoles == null ? Collections.emptySet() : Collections.unmodifiableSet(this.openDistroSecurityRoles);
}
+
+ public String getType() {
+ return type;
+ }
+
+ public Object getSpecialAuthzConfig() {
+ return specialAuthzConfig;
+ }
+
+ public boolean isAuthzComplete() {
+ return authzComplete;
+ }
+
+ public Builder copy() {
+ Builder builder = new Builder();
+ builder.name = name;
+ builder.type = type;
+ builder.backendRoles.addAll(roles);
+ builder.openDistroSecurityRoles.addAll(openDistroSecurityRoles);
+ builder.requestedTenant = requestedTenant;
+ builder.attributes.putAll(attributes);
+ builder.isInjected = isInjected;
+ builder.specialAuthzConfig = specialAuthzConfig;
+ builder.authzComplete = authzComplete;
+
+ return builder;
+ }
+
+
+ public static class Builder {
+ private String name;
+ private String type;
+ private final Set backendRoles = new HashSet();
+ private final Set openDistroSecurityRoles = new HashSet();
+ private String requestedTenant;
+ private Map attributes = new HashMap<>();
+ private boolean isInjected;
+ private Object specialAuthzConfig;
+ private boolean authzComplete;
+
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder type(String type) {
+ this.type = type;
+ return this;
+ }
+
+ public Builder requestedTenant(String requestedTenant) {
+ this.requestedTenant = requestedTenant;
+ return this;
+ }
+
+ public Builder backendRoles(String... backendRoles) {
+ return this.backendRoles(Arrays.asList(backendRoles));
+ }
+
+ public Builder backendRoles(Collection backendRoles) {
+ if (backendRoles != null) {
+ this.backendRoles.addAll(backendRoles);
+ }
+ return this;
+ }
+
+ public Builder openDistroSecurityRoles(String... openDistroSecurityRoles) {
+ return this.openDistroSecurityRoles(Arrays.asList(openDistroSecurityRoles));
+ }
+
+ public Builder openDistroSecurityRoles(Collection openDistroSecurityRoles) {
+ if (openDistroSecurityRoles != null) {
+ this.openDistroSecurityRoles.addAll(openDistroSecurityRoles);
+ }
+ return this;
+ }
+
+ @Deprecated
+ public Builder oldAttributes(Map attributes) {
+ this.attributes.putAll(attributes);
+ return this;
+ }
+
+ @Deprecated
+ public Builder oldAttribute(String key, String value) {
+ this.attributes.put(key, value);
+ return this;
+ }
+
+ public Builder injected() {
+ this.isInjected = true;
+ return this;
+ }
+
+ public Builder specialAuthzConfig(Object specialAuthzConfig) {
+ this.specialAuthzConfig = specialAuthzConfig;
+ return this;
+ }
+
+ public Builder authzComplete() {
+ this.authzComplete = true;
+ return this;
+ }
+
+ public User build() {
+ User user = new User(name, type, backendRoles, openDistroSecurityRoles, null, specialAuthzConfig);
+ user.authzComplete = this.authzComplete;
+ return user;
+ }
+ }
+
+ public static Builder forUser(String username) {
+ return new Builder().name(username);
+ }
}
diff --git a/src/test/java/com/amazon/opendistroforelasticsearch/security/cache/DummyAuthenticationBackend.java b/src/test/java/com/amazon/opendistroforelasticsearch/security/cache/DummyAuthenticationBackend.java
index 446b398817..f478dbea44 100644
--- a/src/test/java/com/amazon/opendistroforelasticsearch/security/cache/DummyAuthenticationBackend.java
+++ b/src/test/java/com/amazon/opendistroforelasticsearch/security/cache/DummyAuthenticationBackend.java
@@ -20,13 +20,12 @@
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.settings.Settings;
-import com.amazon.opendistroforelasticsearch.security.auth.AuthenticationBackend;
-import com.amazon.opendistroforelasticsearch.security.auth.AuthorizationBackend;
+import com.amazon.opendistroforelasticsearch.security.auth.SyncAuthenticationBackend;
import com.amazon.opendistroforelasticsearch.security.user.AuthCredentials;
import com.amazon.opendistroforelasticsearch.security.user.User;
-public class DummyAuthenticationBackend implements AuthenticationBackend {
+public class DummyAuthenticationBackend implements SyncAuthenticationBackend {
private static volatile long authCount;
private static volatile long existsCount;
diff --git a/src/test/java/com/amazon/opendistroforelasticsearch/security/securityconf/impl/v7/ConfigV7Test.java b/src/test/java/com/amazon/opendistroforelasticsearch/security/securityconf/impl/v7/ConfigV7Test.java
index 93df87b8f5..838f4d3598 100644
--- a/src/test/java/com/amazon/opendistroforelasticsearch/security/securityconf/impl/v7/ConfigV7Test.java
+++ b/src/test/java/com/amazon/opendistroforelasticsearch/security/securityconf/impl/v7/ConfigV7Test.java
@@ -1,6 +1,12 @@
package com.amazon.opendistroforelasticsearch.security.securityconf.impl.v7;
+import com.amazon.opendistroforelasticsearch.security.dlic.rest.api.AbstractRestApiUnitTest;
+import com.amazon.opendistroforelasticsearch.security.support.ConfigConstants;
+import com.amazon.opendistroforelasticsearch.security.test.helper.rest.RestHelper;
import com.fasterxml.jackson.databind.JsonNode;
+import org.apache.http.Header;
+import org.apache.http.HttpStatus;
+import org.elasticsearch.common.settings.Settings;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -11,7 +17,7 @@
import com.google.common.collect.ImmutableList;
@RunWith(Parameterized.class)
-public class ConfigV7Test {
+public class ConfigV7Test extends AbstractRestApiUnitTest {
private final boolean omitDefaults;
@Parameterized.Parameters
@@ -97,4 +103,29 @@ public void testKibana() throws Exception {
assertEquals(kibana, DefaultObjectMapper.readTree(json));
assertEquals(kibana, DefaultObjectMapper.readValue(json, ConfigV7.Kibana.class));
}
+
+ @Test
+ public void testConfigAuthTokenProvider() throws Exception {
+ Settings settings = Settings.builder().put(ConfigConstants.OPENDISTRO_SECURITY_UNSUPPORTED_RESTAPI_ALLOW_SECURITYCONFIG_MODIFICATION, true).build();
+ setup(settings);
+
+ rh.sendAdminCertificate = true;
+
+ RestHelper.HttpResponse response = rh.executeGetRequest("/_opendistro/_security/api/securityconfig");
+ Assert.assertTrue(!response.getBody().contains("auth_token_provider"));
+
+ String authTokenProviderPayload = "{\"max_tokens_per_user\" : 100," +
+ " \"max_validity\" : \"1y\"," +
+ " \"jwt_signing_key_hs512\" : \"abc\"," +
+ " \"enabled\" : true}";
+
+ response = rh.executePatchRequest("/_opendistro/_security/api/securityconfig",
+ "[{\"op\": \"add\",\"path\": \"/config/dynamic/auth_token_provider\"," +
+ "\"value\": " + authTokenProviderPayload + "}]", new Header[0]);
+
+ Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode());
+
+ response = rh.executeGetRequest("/_opendistro/_security/api/securityconfig");
+ Assert.assertTrue(response.getBody().contains("auth_token_provider"));
+ }
}
diff --git a/src/test/java/com/amazon/opendistroforelasticsearch/security/user/AuthCredentialsTests.java b/src/test/java/com/amazon/opendistroforelasticsearch/security/user/AuthCredentialsTests.java
index ad30e3051d..3ebcebcb52 100644
--- a/src/test/java/com/amazon/opendistroforelasticsearch/security/user/AuthCredentialsTests.java
+++ b/src/test/java/com/amazon/opendistroforelasticsearch/security/user/AuthCredentialsTests.java
@@ -3,6 +3,9 @@
import org.junit.Assert;
import org.junit.Test;
+import java.util.HashMap;
+import java.util.Map;
+
public class AuthCredentialsTests {
@Test
public void testEquality() {
@@ -29,4 +32,24 @@ public void testEquality() {
new AuthCredentials("george", "secret".getBytes()),
new AuthCredentials("george", "admin"));
}
+
+ @Test
+ public void testAuthCredentialsBuilder() {
+ AuthCredentials.Builder builder = AuthCredentials.forUser("test_user");
+ builder.backendRoles("role1", "role2");
+
+
+ Map claims = new HashMap<>();
+ claims.put("sub", "test_user");
+ claims.put("aud", "opendistro_security_authtoken");
+ claims.put("jti", "some_random_identifier");
+
+ builder.claims(claims);
+
+ AuthCredentials authCredentials = builder.authzComplete().build();
+
+ Assert.assertEquals(authCredentials.getBackendRoles().size(), 2);
+ Assert.assertEquals(authCredentials.getUsername(), "test_user");
+ Assert.assertEquals(authCredentials.getClaims(), claims);
+ }
}
diff --git a/src/test/java/com/amazon/opendistroforelasticsearch/security/user/UserTests.java b/src/test/java/com/amazon/opendistroforelasticsearch/security/user/UserTests.java
new file mode 100644
index 0000000000..4a3dd12fc4
--- /dev/null
+++ b/src/test/java/com/amazon/opendistroforelasticsearch/security/user/UserTests.java
@@ -0,0 +1,53 @@
+package com.amazon.opendistroforelasticsearch.security.user;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class UserTests {
+
+ Set opendistroSecurityRoles = new HashSet();
+
+ @Test
+ public void testUsersCopy() {
+ opendistroSecurityRoles.add("role_1");
+
+ User user = new User("test_user", "auth_token", null, opendistroSecurityRoles, null, "some_random_id");
+
+ User copyUser = user.copy().build();
+
+ Assert.assertEquals(user.getName(), copyUser.getName());
+ Assert.assertEquals(user.getRoles(), copyUser.getRoles());
+ Assert.assertEquals(user.getOpenDistroSecurityRoles(), copyUser.getOpenDistroSecurityRoles());
+ Assert.assertEquals(user.getType(), copyUser.getType());
+ }
+
+ @Test
+ public void testUserBuilder() {
+ User.Builder builder = new User.Builder();
+ builder.openDistroSecurityRoles(opendistroSecurityRoles);
+
+ opendistroSecurityRoles.add("role_1");
+ builder.backendRoles(opendistroSecurityRoles);
+
+ String userType = "auth_token";
+ builder.type(userType);
+
+ builder.name("auth_token_");
+
+ User user = builder.build();
+
+ Assert.assertEquals(user.getName(), "auth_token_");
+ Assert.assertEquals(user.getType(), userType);
+ Assert.assertEquals(user.getOpenDistroSecurityRoles().size(), 0);
+ Assert.assertEquals(user.getRoles().size(), 1);
+
+
+ }
+
+
+}