mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-24 17:09:48 +00:00
The OpenID Connect specification defines a number of ways for a client (RP) to authenticate itself to the OP when accessing the Token Endpoint. We currently only support `client_secret_basic`. This change introduces support for 2 additional authentication methods, namely `client_secret_post` (where the client credentials are passed in the body of the POST request to the OP) and `client_secret_jwt` where the client constructs a JWT and signs it using the the client secret as a key. Support for the above, and especially `client_secret_jwt` in our integration tests meant that the OP we use ( Connect2id server ) should be able to validate the JWT that we send it from the RP. Since we run the OP in docker and it listens on an ephemeral port we would have no way of knowing the port so that we can configure the ES running via the testcluster to know the "correct" Token Endpoint, and even if we did, this would not be the Token Endpoint URL that the OP would think it listens on. To alleviate this, we run an ES single node cluster in docker, alongside the OP so that we can configured it with the correct hostname and port within the docker network. Co-authored-by: Ioannis Kakavas <ioannis@elastic.co>
This commit is contained in:
parent
24a24d050a
commit
a11dfbe031
@ -32,9 +32,15 @@ public class OpenIdConnectRealmSettings {
|
||||
private OpenIdConnectRealmSettings() {
|
||||
}
|
||||
|
||||
private static final List<String> SUPPORTED_SIGNATURE_ALGORITHMS = Collections.unmodifiableList(
|
||||
Arrays.asList("HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512"));
|
||||
private static final List<String> RESPONSE_TYPES = Arrays.asList("code", "id_token", "id_token token");
|
||||
public static final List<String> SUPPORTED_SIGNATURE_ALGORITHMS =
|
||||
org.elasticsearch.common.collect.List.of(
|
||||
"HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512");
|
||||
private static final List<String> RESPONSE_TYPES = org.elasticsearch.common.collect.List.of(
|
||||
"code", "id_token", "id_token token");
|
||||
public static final List<String> CLIENT_AUTH_METHODS = org.elasticsearch.common.collect.List.of(
|
||||
"client_secret_basic", "client_secret_post", "client_secret_jwt");
|
||||
public static final List<String> SUPPORTED_CLIENT_AUTH_JWT_ALGORITHMS = org.elasticsearch.common.collect.List.of(
|
||||
"HS256", "HS384", "HS512");
|
||||
public static final String TYPE = "oidc";
|
||||
|
||||
public static final Setting.AffixSetting<String> RP_CLIENT_ID
|
||||
@ -78,7 +84,22 @@ public class OpenIdConnectRealmSettings {
|
||||
public static final Setting.AffixSetting<List<String>> RP_REQUESTED_SCOPES = Setting.affixKeySetting(
|
||||
RealmSettings.realmSettingPrefix(TYPE), "rp.requested_scopes",
|
||||
key -> Setting.listSetting(key, Collections.singletonList("openid"), Function.identity(), Setting.Property.NodeScope));
|
||||
|
||||
public static final Setting.AffixSetting<String> RP_CLIENT_AUTH_METHOD
|
||||
= Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "rp.client_auth_method",
|
||||
key -> new Setting<>(key, "client_secret_basic", Function.identity(), v -> {
|
||||
if (CLIENT_AUTH_METHODS.contains(v) == false) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid value [" + v + "] for [" + key + "]. Allowed values are " + CLIENT_AUTH_METHODS + "}]");
|
||||
}
|
||||
}, Setting.Property.NodeScope));
|
||||
public static final Setting.AffixSetting<String> RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM
|
||||
= Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "rp.client_auth_jwt_signature_algorithm",
|
||||
key -> new Setting<>(key, "HS384", Function.identity(), v -> {
|
||||
if (SUPPORTED_CLIENT_AUTH_JWT_ALGORITHMS.contains(v) == false) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid value [" + v + "] for [" + key + "]. Allowed values are " + SUPPORTED_CLIENT_AUTH_JWT_ALGORITHMS + "}]");
|
||||
}
|
||||
}, Setting.Property.NodeScope));
|
||||
public static final Setting.AffixSetting<String> OP_AUTHORIZATION_ENDPOINT
|
||||
= Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "op.authorization_endpoint",
|
||||
key -> Setting.simpleString(key, v -> {
|
||||
@ -194,8 +215,9 @@ public class OpenIdConnectRealmSettings {
|
||||
public static Set<Setting.AffixSetting<?>> getSettings() {
|
||||
final Set<Setting.AffixSetting<?>> set = Sets.newHashSet(
|
||||
RP_CLIENT_ID, RP_REDIRECT_URI, RP_RESPONSE_TYPE, RP_REQUESTED_SCOPES, RP_CLIENT_SECRET, RP_SIGNATURE_ALGORITHM,
|
||||
RP_POST_LOGOUT_REDIRECT_URI, OP_AUTHORIZATION_ENDPOINT, OP_TOKEN_ENDPOINT, OP_USERINFO_ENDPOINT,
|
||||
OP_ENDSESSION_ENDPOINT, OP_ISSUER, OP_JWKSET_PATH, POPULATE_USER_METADATA, HTTP_CONNECT_TIMEOUT, HTTP_CONNECTION_READ_TIMEOUT,
|
||||
RP_POST_LOGOUT_REDIRECT_URI, RP_CLIENT_AUTH_METHOD, RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM, OP_AUTHORIZATION_ENDPOINT,
|
||||
OP_TOKEN_ENDPOINT, OP_USERINFO_ENDPOINT, OP_ENDSESSION_ENDPOINT, OP_ISSUER, OP_JWKSET_PATH,
|
||||
POPULATE_USER_METADATA, HTTP_CONNECT_TIMEOUT, HTTP_CONNECTION_READ_TIMEOUT,
|
||||
HTTP_SOCKET_TIMEOUT, HTTP_MAX_CONNECTIONS, HTTP_MAX_ENDPOINT_CONNECTIONS, HTTP_PROXY_HOST, HTTP_PROXY_PORT,
|
||||
HTTP_PROXY_SCHEME, ALLOWED_CLOCK_SKEW);
|
||||
set.addAll(DelegatedAuthorizationSettings.getSettings(TYPE));
|
||||
|
@ -22,6 +22,8 @@ import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
|
||||
import com.nimbusds.oauth2.sdk.ErrorObject;
|
||||
import com.nimbusds.oauth2.sdk.ResponseType;
|
||||
import com.nimbusds.oauth2.sdk.TokenErrorResponse;
|
||||
import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
|
||||
import com.nimbusds.oauth2.sdk.auth.ClientSecretJWT;
|
||||
import com.nimbusds.oauth2.sdk.auth.Secret;
|
||||
import com.nimbusds.oauth2.sdk.id.State;
|
||||
import com.nimbusds.oauth2.sdk.token.AccessToken;
|
||||
@ -85,6 +87,7 @@ import org.elasticsearch.watcher.FileWatcher;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
|
||||
import org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||
|
||||
@ -463,19 +466,36 @@ public class OpenIdConnectAuthenticator {
|
||||
try {
|
||||
final AuthorizationCodeGrant codeGrant = new AuthorizationCodeGrant(code, rpConfig.getRedirectUri());
|
||||
final HttpPost httpPost = new HttpPost(opConfig.getTokenEndpoint());
|
||||
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
final List<NameValuePair> params = new ArrayList<>();
|
||||
for (Map.Entry<String, List<String>> entry : codeGrant.toParameters().entrySet()) {
|
||||
// All parameters of AuthorizationCodeGrant are singleton lists
|
||||
params.add(new BasicNameValuePair(entry.getKey(), entry.getValue().get(0)));
|
||||
}
|
||||
if (rpConfig.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)) {
|
||||
UsernamePasswordCredentials creds =
|
||||
new UsernamePasswordCredentials(URLEncoder.encode(rpConfig.getClientId().getValue(), StandardCharsets.UTF_8.name()),
|
||||
URLEncoder.encode(rpConfig.getClientSecret().toString(), StandardCharsets.UTF_8.name()));
|
||||
httpPost.addHeader(new BasicScheme().authenticate(creds, httpPost, null));
|
||||
} else if (rpConfig.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.CLIENT_SECRET_POST)) {
|
||||
params.add(new BasicNameValuePair("client_id", rpConfig.getClientId().getValue()));
|
||||
params.add(new BasicNameValuePair("client_secret", rpConfig.getClientSecret().toString()));
|
||||
} else if (rpConfig.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.CLIENT_SECRET_JWT)) {
|
||||
ClientSecretJWT clientSecretJWT = new ClientSecretJWT(rpConfig.getClientId(), opConfig.getTokenEndpoint(),
|
||||
rpConfig.getClientAuthenticationJwtAlgorithm(), new Secret(rpConfig.getClientSecret().toString()));
|
||||
for (Map.Entry<String, List<String>> entry : clientSecretJWT.toParameters().entrySet()) {
|
||||
// Both client_assertion and client_assertion_type are singleton lists
|
||||
params.add(new BasicNameValuePair(entry.getKey(), entry.getValue().get(0)));
|
||||
}
|
||||
} else {
|
||||
tokensListener.onFailure(new ElasticsearchSecurityException("Failed to exchange code for Id Token using Token Endpoint." +
|
||||
"Expected client authentication method to be one of " + OpenIdConnectRealmSettings.CLIENT_AUTH_METHODS
|
||||
+ " but was [" + rpConfig.getClientAuthenticationMethod() + "]"));
|
||||
}
|
||||
httpPost.setEntity(new UrlEncodedFormEntity(params));
|
||||
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
UsernamePasswordCredentials creds =
|
||||
new UsernamePasswordCredentials(URLEncoder.encode(rpConfig.getClientId().getValue(), StandardCharsets.UTF_8.name()),
|
||||
URLEncoder.encode(rpConfig.getClientSecret().toString(), StandardCharsets.UTF_8.name()));
|
||||
httpPost.addHeader(new BasicScheme().authenticate(creds, httpPost, null));
|
||||
SpecialPermission.check();
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||
|
||||
httpClient.execute(httpPost, new FutureCallback<HttpResponse>() {
|
||||
@Override
|
||||
public void completed(HttpResponse result) {
|
||||
@ -496,7 +516,7 @@ public class OpenIdConnectAuthenticator {
|
||||
});
|
||||
return null;
|
||||
});
|
||||
} catch (AuthenticationException | UnsupportedEncodingException e) {
|
||||
} catch (AuthenticationException | UnsupportedEncodingException | JOSEException e) {
|
||||
tokensListener.onFailure(
|
||||
new ElasticsearchSecurityException("Failed to exchange code for Id Token using the Token Endpoint.", e));
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.oauth2.sdk.ParseException;
|
||||
import com.nimbusds.oauth2.sdk.ResponseType;
|
||||
import com.nimbusds.oauth2.sdk.Scope;
|
||||
import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
|
||||
import com.nimbusds.oauth2.sdk.id.ClientID;
|
||||
import com.nimbusds.oauth2.sdk.id.Issuer;
|
||||
import com.nimbusds.oauth2.sdk.id.State;
|
||||
@ -73,6 +74,8 @@ import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectReal
|
||||
import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.OP_USERINFO_ENDPOINT;
|
||||
import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.POPULATE_USER_METADATA;
|
||||
import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.PRINCIPAL_CLAIM;
|
||||
import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM;
|
||||
import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.RP_CLIENT_AUTH_METHOD;
|
||||
import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.RP_CLIENT_ID;
|
||||
import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.RP_CLIENT_SECRET;
|
||||
import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.RP_POST_LOGOUT_REDIRECT_URI;
|
||||
@ -266,9 +269,11 @@ public class OpenIdConnectRealm extends Realm implements Releasable {
|
||||
requestedScope.add("openid");
|
||||
}
|
||||
final JWSAlgorithm signatureAlgorithm = JWSAlgorithm.parse(require(config, RP_SIGNATURE_ALGORITHM));
|
||||
|
||||
final ClientAuthenticationMethod clientAuthenticationMethod =
|
||||
ClientAuthenticationMethod.parse(require(config, RP_CLIENT_AUTH_METHOD));
|
||||
final JWSAlgorithm clientAuthJwtAlgorithm = JWSAlgorithm.parse(require(config, RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM));
|
||||
return new RelyingPartyConfiguration(clientId, clientSecret, redirectUri, responseType, requestedScope,
|
||||
signatureAlgorithm, postLogoutRedirectUri);
|
||||
signatureAlgorithm, clientAuthenticationMethod, clientAuthJwtAlgorithm, postLogoutRedirectUri);
|
||||
}
|
||||
|
||||
private OpenIdConnectProviderConfiguration buildOpenIdConnectProviderConfiguration(RealmConfig config) {
|
||||
|
@ -8,6 +8,7 @@ package org.elasticsearch.xpack.security.authc.oidc;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.oauth2.sdk.ResponseType;
|
||||
import com.nimbusds.oauth2.sdk.Scope;
|
||||
import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
|
||||
import com.nimbusds.oauth2.sdk.id.ClientID;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
@ -26,15 +27,22 @@ public class RelyingPartyConfiguration {
|
||||
private final Scope requestedScope;
|
||||
private final JWSAlgorithm signatureAlgorithm;
|
||||
private final URI postLogoutRedirectUri;
|
||||
private final ClientAuthenticationMethod clientAuthenticationMethod;
|
||||
private final JWSAlgorithm clientAuthenticationJwtAlgorithm;
|
||||
|
||||
public RelyingPartyConfiguration(ClientID clientId, SecureString clientSecret, URI redirectUri, ResponseType responseType,
|
||||
Scope requestedScope, JWSAlgorithm algorithm, @Nullable URI postLogoutRedirectUri) {
|
||||
Scope requestedScope, JWSAlgorithm algorithm, ClientAuthenticationMethod clientAuthenticationMethod,
|
||||
JWSAlgorithm clientAuthenticationJwtAlgorithm, @Nullable URI postLogoutRedirectUri) {
|
||||
this.clientId = Objects.requireNonNull(clientId, "clientId must be provided");
|
||||
this.clientSecret = Objects.requireNonNull(clientSecret, "clientSecret must be provided");
|
||||
this.redirectUri = Objects.requireNonNull(redirectUri, "redirectUri must be provided");
|
||||
this.responseType = Objects.requireNonNull(responseType, "responseType must be provided");
|
||||
this.requestedScope = Objects.requireNonNull(requestedScope, "responseType must be provided");
|
||||
this.signatureAlgorithm = Objects.requireNonNull(algorithm, "algorithm must be provided");
|
||||
this.clientAuthenticationMethod = Objects.requireNonNull(clientAuthenticationMethod,
|
||||
"clientAuthenticationMethod must be provided");
|
||||
this.clientAuthenticationJwtAlgorithm = Objects.requireNonNull(clientAuthenticationJwtAlgorithm,
|
||||
"clientAuthenticationJwtAlgorithm must be provided");
|
||||
this.postLogoutRedirectUri = postLogoutRedirectUri;
|
||||
}
|
||||
|
||||
@ -65,4 +73,12 @@ public class RelyingPartyConfiguration {
|
||||
public URI getPostLogoutRedirectUri() {
|
||||
return postLogoutRedirectUri;
|
||||
}
|
||||
|
||||
public ClientAuthenticationMethod getClientAuthenticationMethod() {
|
||||
return clientAuthenticationMethod;
|
||||
}
|
||||
|
||||
public JWSAlgorithm getClientAuthenticationJwtAlgorithm() {
|
||||
return clientAuthenticationJwtAlgorithm;
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import com.nimbusds.jwt.SignedJWT;
|
||||
import com.nimbusds.jwt.proc.BadJWTException;
|
||||
import com.nimbusds.oauth2.sdk.ResponseType;
|
||||
import com.nimbusds.oauth2.sdk.Scope;
|
||||
import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
|
||||
import com.nimbusds.oauth2.sdk.auth.Secret;
|
||||
import com.nimbusds.oauth2.sdk.id.ClientID;
|
||||
import com.nimbusds.oauth2.sdk.id.Issuer;
|
||||
@ -892,8 +893,11 @@ public class OpenIdConnectAuthenticatorTests extends OpenIdConnectTestCase {
|
||||
new ResponseType("id_token", "token"),
|
||||
new Scope("openid"),
|
||||
JWSAlgorithm.RS384,
|
||||
ClientAuthenticationMethod.CLIENT_SECRET_BASIC,
|
||||
JWSAlgorithm.HS384,
|
||||
new URI("https://rp.elastic.co/successfull_logout"));
|
||||
}
|
||||
|
||||
private RelyingPartyConfiguration getRpConfig(String alg) throws URISyntaxException {
|
||||
return new RelyingPartyConfiguration(
|
||||
new ClientID("rp-my"),
|
||||
@ -902,6 +906,8 @@ public class OpenIdConnectAuthenticatorTests extends OpenIdConnectTestCase {
|
||||
new ResponseType("id_token", "token"),
|
||||
new Scope("openid"),
|
||||
JWSAlgorithm.parse(alg),
|
||||
ClientAuthenticationMethod.CLIENT_SECRET_BASIC,
|
||||
JWSAlgorithm.HS384,
|
||||
new URI("https://rp.elastic.co/successfull_logout"));
|
||||
}
|
||||
|
||||
@ -913,6 +919,8 @@ public class OpenIdConnectAuthenticatorTests extends OpenIdConnectTestCase {
|
||||
new ResponseType("id_token"),
|
||||
new Scope("openid"),
|
||||
JWSAlgorithm.parse(alg),
|
||||
ClientAuthenticationMethod.CLIENT_SECRET_BASIC,
|
||||
JWSAlgorithm.HS384,
|
||||
new URI("https://rp.elastic.co/successfull_logout"));
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,43 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
|
||||
threadContext = new ThreadContext(globalSettings);
|
||||
}
|
||||
|
||||
public void testAllSettings() {
|
||||
final Settings.Builder settingsBuilder = Settings.builder()
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_TOKEN_ENDPOINT), "https://op.example.com/token")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_USERINFO_ENDPOINT), "https://op.example.com/userinfo")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_ISSUER), "https://op.example.com")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_JWKSET_PATH), "https://op.example.com/jwks.json")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.POPULATE_USER_METADATA), randomBoolean())
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.GROUPS_CLAIM.getClaim()), "group1")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.DN_CLAIM.getClaim()), "uid=sub,ou=people,dc=example,dc=com")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.NAME_CLAIM.getClaim()), "name")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.MAIL_CLAIM.getClaim()), "e@mail.com")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REQUESTED_SCOPES), "openid")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_SIGNATURE_ALGORITHM),
|
||||
randomFrom(OpenIdConnectRealmSettings.SUPPORTED_SIGNATURE_ALGORITHMS))
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_POST_LOGOUT_REDIRECT_URI), "https://my.rp.com/logout")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_METHOD),
|
||||
randomFrom(OpenIdConnectRealmSettings.CLIENT_AUTH_METHODS))
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM),
|
||||
randomFrom(OpenIdConnectRealmSettings.SUPPORTED_CLIENT_AUTH_JWT_ALGORITHMS))
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_CONNECT_TIMEOUT), "5s")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_CONNECTION_READ_TIMEOUT), "5s")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_SOCKET_TIMEOUT), "5s")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_MAX_CONNECTIONS), "5")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_MAX_ENDPOINT_CONNECTIONS), "5")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_PROXY_HOST), "host")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_PROXY_PORT), "8080")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_PROXY_SCHEME), "http")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.ALLOWED_CLOCK_SKEW), "10s");
|
||||
settingsBuilder.setSecureSettings(getSecureSettings());
|
||||
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
|
||||
}
|
||||
|
||||
public void testIncorrectResponseTypeThrowsError() {
|
||||
final Settings.Builder settingsBuilder = Settings.builder()
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login")
|
||||
@ -115,10 +152,8 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
|
||||
settingsBuilder.setSecureSettings(getSecureSettings());
|
||||
final OpenIdConnectRealm realm = new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
|
||||
assertNotNull(realm);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void testInvalidTokenEndpointThrowsError() {
|
||||
final Settings.Builder settingsBuilder = Settings.builder()
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login")
|
||||
@ -326,6 +361,45 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
|
||||
));
|
||||
}
|
||||
|
||||
public void testInvalidClientAuthenticationMethodThrowsError() {
|
||||
final Settings.Builder settingsBuilder = Settings.builder()
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_ISSUER), "https://op.example.com")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_JWKSET_PATH), "https://op.example.com/jwks.json")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_TOKEN_ENDPOINT), "https://op.example.com/token")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_METHOD), "none")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
|
||||
settingsBuilder.setSecureSettings(getSecureSettings());
|
||||
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> {
|
||||
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
|
||||
});
|
||||
assertThat(exception.getMessage(),
|
||||
Matchers.containsString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_METHOD)));
|
||||
}
|
||||
|
||||
public void testInvalidClientAuthenticationJwtAlgorithmThrowsError() {
|
||||
final Settings.Builder settingsBuilder = Settings.builder()
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_ISSUER), "https://op.example.com")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_JWKSET_PATH), "https://op.example.com/jwks.json")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_TOKEN_ENDPOINT), "https://op.example.com/token")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_METHOD), "client_secret_jwt")
|
||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM), "AB234");
|
||||
settingsBuilder.setSecureSettings(getSecureSettings());
|
||||
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> {
|
||||
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
|
||||
});
|
||||
assertThat(exception.getMessage(),
|
||||
Matchers.containsString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM)));
|
||||
}
|
||||
|
||||
private MockSecureSettings getSecureSettings() {
|
||||
MockSecureSettings secureSettings = new MockSecureSettings();
|
||||
secureSettings.setString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_SECRET),
|
||||
|
@ -11,82 +11,6 @@ dependencies {
|
||||
testImplementation project(path: xpackModule('security'), configuration: 'testArtifacts')
|
||||
}
|
||||
testFixtures.useFixture ":x-pack:test:idp-fixture", "oidc-provider"
|
||||
|
||||
String ephemeralOpPort
|
||||
String ephemeralProxyPort
|
||||
tasks.register("setupPorts") {
|
||||
// Don't attempt to get ephemeral ports when Docker is not available
|
||||
onlyIf { idpFixtureProject.postProcessFixture.state.skipped == false }
|
||||
dependsOn idpFixtureProject.postProcessFixture
|
||||
doLast {
|
||||
ephemeralOpPort = idpFixtureProject.postProcessFixture.ext."test.fixtures.oidc-provider.tcp.8080"
|
||||
ephemeralProxyPort = idpFixtureProject.postProcessFixture.ext."test.fixtures.http-proxy.tcp.8888"
|
||||
}
|
||||
}
|
||||
|
||||
integTest {
|
||||
dependsOn "setupPorts"
|
||||
}
|
||||
|
||||
testClusters.integTest {
|
||||
testDistribution = 'DEFAULT'
|
||||
setting 'xpack.license.self_generated.type', 'trial'
|
||||
setting 'xpack.security.enabled', 'true'
|
||||
setting 'xpack.security.http.ssl.enabled', 'false'
|
||||
setting 'xpack.security.authc.token.enabled', 'true'
|
||||
setting 'xpack.security.authc.realms.file.file.order', '0'
|
||||
setting 'xpack.security.authc.realms.native.native.order', '1'
|
||||
// OpenID Connect Realm 1 configured for authorization grant flow
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.order', '2'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.op.issuer', 'http://localhost:8080'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.op.authorization_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id-login" }
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.op.token_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/token" }
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.op.userinfo_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/userinfo" }
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.op.jwkset_path', 'op-jwks.json'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.rp.redirect_uri', 'https://my.fantastic.rp/cb'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.rp.client_id', 'https://my.elasticsearch.org/rp'
|
||||
keystore 'xpack.security.authc.realms.oidc.c2id.rp.client_secret', 'b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.rp.response_type', 'code'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.claims.principal', 'sub'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.claims.name', 'name'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.claims.mail', 'email'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id.claims.groups', 'groups'
|
||||
// OpenID Connect Realm 2 configured for implicit flow
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.order', '3'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.op.issuer', 'http://localhost:8080'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.op.authorization_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id-login" }
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.op.token_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/token" }
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.op.userinfo_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/userinfo" }
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.op.jwkset_path', 'op-jwks.json'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.rp.redirect_uri', 'https://my.fantastic.rp/cb'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.rp.client_id', 'elasticsearch-rp'
|
||||
keystore 'xpack.security.authc.realms.oidc.c2id-implicit.rp.client_secret', 'b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.rp.response_type', 'id_token token'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.claims.principal', 'sub'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.claims.name', 'name'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.claims.mail', 'email'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-implicit.claims.groups', 'groups'
|
||||
// OpenID Connect Realm 3 configured to use a proxy
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.order', '4'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.op.issuer', 'http://localhost:8080'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.op.authorization_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id-login" }
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.op.token_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/token" }
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.op.userinfo_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/userinfo" }
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.op.jwkset_path', 'op-jwks.json'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.rp.redirect_uri', 'https://my.fantastic.rp/cb'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.rp.client_id', 'https://my.elasticsearch.org/rp'
|
||||
keystore 'xpack.security.authc.realms.oidc.c2id-proxy.rp.client_secret', 'b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.rp.response_type', 'code'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.claims.principal', 'sub'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.claims.name', 'name'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.claims.mail', 'email'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.claims.groups', 'groups'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.http.proxy.host', '127.0.0.1'
|
||||
setting 'xpack.security.authc.realms.oidc.c2id-proxy.http.proxy.port', {"${ephemeralProxyPort}"}
|
||||
setting 'xpack.ml.enabled', 'false'
|
||||
extraConfigFile 'op-jwks.json', idpFixtureProject.file("oidc/op-jwks.json")
|
||||
|
||||
user username: "test_admin", password: "x-pack-test-password"
|
||||
}
|
||||
testFixtures.useFixture ":x-pack:test:idp-fixture", "elasticsearch-node"
|
||||
|
||||
thirdPartyAudit.enabled = false
|
||||
|
@ -9,6 +9,7 @@ import net.minidev.json.JSONObject;
|
||||
import net.minidev.json.parser.JSONParser;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
@ -29,10 +30,12 @@ import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.ResponseException;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.common.CheckedFunction;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.io.PathUtils;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
@ -47,8 +50,11 @@ import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -65,16 +71,34 @@ public class OpenIdConnectAuthIT extends ESRestTestCase {
|
||||
private static final String REALM_NAME = "c2id";
|
||||
private static final String REALM_NAME_IMPLICIT = "c2id-implicit";
|
||||
private static final String REALM_NAME_PROXY = "c2id-proxy";
|
||||
private static final String REALM_NAME_CLIENT_POST_AUTH = "c2id-post";
|
||||
private static final String REALM_NAME_CLIENT_JWT_AUTH = "c2id-jwt";
|
||||
private static final String FACILITATOR_PASSWORD = "f@cilit@t0r";
|
||||
private static final String REGISTRATION_URL = "http://127.0.0.1:" + getEphemeralPortFromProperty("8080") + "/c2id/clients";
|
||||
private static final String LOGIN_API = "http://127.0.0.1:" + getEphemeralPortFromProperty("8080") + "/c2id-login/api/";
|
||||
private static final String REGISTRATION_URL = "http://127.0.0.1:" + getEphemeralTcpPortFromProperty("oidc-provider", "8080")
|
||||
+ "/c2id/clients";
|
||||
private static final String LOGIN_API = "http://127.0.0.1:" + getEphemeralTcpPortFromProperty("oidc-provider", "8080")
|
||||
+ "/c2id-login/api/";
|
||||
private static final String CLIENT_SECRET = "b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2";
|
||||
// SHA256 of this is defined in x-pack/test/idp-fixture/oidc/override.properties
|
||||
private static final String OP_API_BEARER_TOKEN = "811fa888f3e0fdc9e01d4201bfeee46a";
|
||||
private static final String ES_PORT = getEphemeralTcpPortFromProperty("elasticsearch-node", "9200");
|
||||
private static Path HTTP_TRUSTSTORE;
|
||||
|
||||
@Before
|
||||
public void setupUserAndRoles() throws IOException {
|
||||
public void setupUserAndRoles() throws Exception {
|
||||
setFacilitatorUser();
|
||||
setRoleMappings();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void readTrustStore() throws Exception {
|
||||
final URL resource = OpenIdConnectAuthIT.class.getResource("/tls/testnode.jks");
|
||||
if (resource == null) {
|
||||
throw new FileNotFoundException("Cannot find classpath resource /tls/testnode.jks");
|
||||
}
|
||||
HTTP_TRUSTSTORE = PathUtils.get(resource.toURI());
|
||||
}
|
||||
|
||||
/**
|
||||
* C2id server only supports dynamic registration, so we can't pre-seed it's config with our client data. Execute only once
|
||||
*/
|
||||
@ -85,40 +109,82 @@ public class OpenIdConnectAuthIT extends ESRestTestCase {
|
||||
"\"grant_types\": [\"authorization_code\"]," +
|
||||
"\"response_types\": [\"code\"]," +
|
||||
"\"preferred_client_id\":\"https://my.elasticsearch.org/rp\"," +
|
||||
"\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," +
|
||||
"\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]" +
|
||||
"\"preferred_client_secret\":\"" + CLIENT_SECRET + "\"," +
|
||||
"\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]," +
|
||||
"\"token_endpoint_auth_method\":\"client_secret_basic\"" +
|
||||
"}";
|
||||
String implicitClient = "{" +
|
||||
"\"grant_types\": [\"implicit\"]," +
|
||||
"\"response_types\": [\"token id_token\"]," +
|
||||
"\"preferred_client_id\":\"elasticsearch-rp\"," +
|
||||
"\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," +
|
||||
"\"preferred_client_secret\":\"" + CLIENT_SECRET + "\"," +
|
||||
"\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]" +
|
||||
"}";
|
||||
String postClient = "{" +
|
||||
"\"grant_types\": [\"authorization_code\"]," +
|
||||
"\"response_types\": [\"code\"]," +
|
||||
"\"preferred_client_id\":\"elasticsearch-post\"," +
|
||||
"\"preferred_client_secret\":\"" + CLIENT_SECRET + "\"," +
|
||||
"\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]," +
|
||||
"\"token_endpoint_auth_method\":\"client_secret_post\"" +
|
||||
"}";
|
||||
String jwtClient = "{" +
|
||||
"\"grant_types\": [\"authorization_code\"]," +
|
||||
"\"response_types\": [\"code\"]," +
|
||||
"\"preferred_client_id\":\"elasticsearch-post-jwt\"," +
|
||||
"\"preferred_client_secret\":\"" + CLIENT_SECRET + "\"," +
|
||||
"\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]," +
|
||||
"\"token_endpoint_auth_method\":\"client_secret_jwt\"" +
|
||||
"}";
|
||||
HttpPost httpPost = new HttpPost(REGISTRATION_URL);
|
||||
final BasicHttpContext context = new BasicHttpContext();
|
||||
httpPost.setEntity(new StringEntity(codeClient, ContentType.APPLICATION_JSON));
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
httpPost.setHeader("Content-type", "application/json");
|
||||
httpPost.setHeader("Authorization", "Bearer 811fa888f3e0fdc9e01d4201bfeee46a");
|
||||
CloseableHttpResponse response = SocketAccess.doPrivileged(() -> httpClient.execute(httpPost, context));
|
||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
||||
httpPost.setEntity(new StringEntity(implicitClient, ContentType.APPLICATION_JSON));
|
||||
httpPost.setHeader("Authorization", "Bearer " + OP_API_BEARER_TOKEN);
|
||||
|
||||
HttpPost httpPost2 = new HttpPost(REGISTRATION_URL);
|
||||
httpPost2.setEntity(new StringEntity(implicitClient, ContentType.APPLICATION_JSON));
|
||||
httpPost2.setHeader("Accept", "application/json");
|
||||
httpPost2.setHeader("Content-type", "application/json");
|
||||
httpPost2.setHeader("Authorization", "Bearer 811fa888f3e0fdc9e01d4201bfeee46a");
|
||||
CloseableHttpResponse response2 = SocketAccess.doPrivileged(() -> httpClient.execute(httpPost2, context));
|
||||
assertThat(response2.getStatusLine().getStatusCode(), equalTo(200));
|
||||
httpPost2.setHeader("Authorization", "Bearer " + OP_API_BEARER_TOKEN);
|
||||
|
||||
HttpPost httpPost3 = new HttpPost(REGISTRATION_URL);
|
||||
httpPost3.setEntity(new StringEntity(postClient, ContentType.APPLICATION_JSON));
|
||||
httpPost3.setHeader("Accept", "application/json");
|
||||
httpPost3.setHeader("Content-type", "application/json");
|
||||
httpPost3.setHeader("Authorization", "Bearer " + OP_API_BEARER_TOKEN);
|
||||
|
||||
HttpPost httpPost4 = new HttpPost(REGISTRATION_URL);
|
||||
httpPost4.setEntity(new StringEntity(jwtClient, ContentType.APPLICATION_JSON));
|
||||
httpPost4.setHeader("Accept", "application/json");
|
||||
httpPost4.setHeader("Content-type", "application/json");
|
||||
httpPost4.setHeader("Authorization", "Bearer " + OP_API_BEARER_TOKEN);
|
||||
|
||||
SocketAccess.doPrivileged(() -> {
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost, context)) {
|
||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(201));
|
||||
}
|
||||
try (CloseableHttpResponse response2 = httpClient.execute(httpPost2, context)) {
|
||||
assertThat(response2.getStatusLine().getStatusCode(), equalTo(201));
|
||||
}
|
||||
try (CloseableHttpResponse response3 = httpClient.execute(httpPost3, context)) {
|
||||
assertThat(response3.getStatusLine().getStatusCode(), equalTo(201));
|
||||
}
|
||||
try (CloseableHttpResponse response4 = httpClient.execute(httpPost4, context)) {
|
||||
assertThat(response4.getStatusLine().getStatusCode(), equalTo(201));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Settings restAdminSettings() {
|
||||
String token = basicAuthHeaderValue("test_admin", new SecureString("x-pack-test-password".toCharArray()));
|
||||
String token = basicAuthHeaderValue("x_pack_rest_user", new SecureString("x-pack-test-password".toCharArray()));
|
||||
return Settings.builder()
|
||||
.put(ThreadContext.PREFIX + ".Authorization", token)
|
||||
.put(TRUSTSTORE_PATH, HTTP_TRUSTSTORE)
|
||||
.put(TRUSTSTORE_PASSWORD, "testnode")
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -193,19 +259,21 @@ public class OpenIdConnectAuthIT extends ESRestTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private static String getEphemeralPortFromProperty(String port) {
|
||||
String key = "test.fixtures.oidc-provider.tcp." + port;
|
||||
private static String getEphemeralTcpPortFromProperty(String service, String port) {
|
||||
String key = "test.fixtures." + service + ".tcp." + port;
|
||||
final String value = System.getProperty(key);
|
||||
assertNotNull("Expected the actual value for port " + port + " to be in system property " + key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private Map<String, Object> callAuthenticateApiUsingAccessToken(String accessToken) throws IOException {
|
||||
private Map<String, Object> callAuthenticateApiUsingAccessToken(String accessToken) throws Exception {
|
||||
Request request = new Request("GET", "/_security/_authenticate");
|
||||
RequestOptions.Builder options = request.getOptions().toBuilder();
|
||||
options.addHeader("Authorization", "Bearer " + accessToken);
|
||||
request.setOptions(options);
|
||||
return entityAsMap(client().performRequest(request));
|
||||
try (RestClient restClient = getClient()) {
|
||||
return entityAsMap(restClient.performRequest(request));
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T execute(CloseableHttpClient client, HttpEntityEnclosingRequestBase request,
|
||||
@ -250,10 +318,25 @@ public class OpenIdConnectAuthIT extends ESRestTestCase {
|
||||
verifyElasticsearchAccessTokenForCodeFlow(tokens.v1());
|
||||
}
|
||||
|
||||
public void testAuthenticateWithCodeFlowAndClientPost() throws Exception {
|
||||
final PrepareAuthResponse prepareAuthResponse = getRedirectedFromFacilitator(REALM_NAME_CLIENT_POST_AUTH);
|
||||
final String redirectUri = authenticateAtOP(prepareAuthResponse.getAuthUri());
|
||||
Tuple<String, String> tokens = completeAuthentication(redirectUri, prepareAuthResponse.getState(),
|
||||
prepareAuthResponse.getNonce(), REALM_NAME_CLIENT_POST_AUTH);
|
||||
verifyElasticsearchAccessTokenForCodeFlow(tokens.v1());
|
||||
}
|
||||
|
||||
public void testAuthenticateWithCodeFlowAndClientJwtPost() throws Exception {
|
||||
final PrepareAuthResponse prepareAuthResponse = getRedirectedFromFacilitator(REALM_NAME_CLIENT_JWT_AUTH);
|
||||
final String redirectUri = authenticateAtOP(prepareAuthResponse.getAuthUri());
|
||||
Tuple<String, String> tokens = completeAuthentication(redirectUri, prepareAuthResponse.getState(),
|
||||
prepareAuthResponse.getNonce(), REALM_NAME_CLIENT_JWT_AUTH);
|
||||
verifyElasticsearchAccessTokenForCodeFlow(tokens.v1());
|
||||
}
|
||||
|
||||
public void testAuthenticateWithImplicitFlow() throws Exception {
|
||||
final PrepareAuthResponse prepareAuthResponse = getRedirectedFromFacilitator(REALM_NAME_IMPLICIT);
|
||||
final String redirectUri = authenticateAtOP(prepareAuthResponse.getAuthUri());
|
||||
|
||||
Tuple<String, String> tokens = completeAuthentication(redirectUri, prepareAuthResponse.getState(),
|
||||
prepareAuthResponse.getNonce(), REALM_NAME_IMPLICIT);
|
||||
verifyElasticsearchAccessTokenForImplicitFlow(tokens.v1());
|
||||
@ -280,7 +363,7 @@ public class OpenIdConnectAuthIT extends ESRestTestCase {
|
||||
assertThat(401, equalTo(e.getResponse().getStatusLine().getStatusCode()));
|
||||
}
|
||||
|
||||
private void verifyElasticsearchAccessTokenForCodeFlow(String accessToken) throws IOException {
|
||||
private void verifyElasticsearchAccessTokenForCodeFlow(String accessToken) throws Exception {
|
||||
final Map<String, Object> map = callAuthenticateApiUsingAccessToken(accessToken);
|
||||
logger.info("Authentication with token Response: " + map);
|
||||
assertThat(map.get("username"), equalTo("alice"));
|
||||
@ -289,10 +372,10 @@ public class OpenIdConnectAuthIT extends ESRestTestCase {
|
||||
assertThat(map.get("metadata"), instanceOf(Map.class));
|
||||
final Map<?, ?> metadata = (Map<?, ?>) map.get("metadata");
|
||||
assertThat(metadata.get("oidc(sub)"), equalTo("alice"));
|
||||
assertThat(metadata.get("oidc(iss)"), equalTo("http://localhost:8080"));
|
||||
assertThat(metadata.get("oidc(iss)"), equalTo("http://oidc-provider:8080/c2id"));
|
||||
}
|
||||
|
||||
private void verifyElasticsearchAccessTokenForImplicitFlow(String accessToken) throws IOException {
|
||||
private void verifyElasticsearchAccessTokenForImplicitFlow(String accessToken) throws Exception {
|
||||
final Map<String, Object> map = callAuthenticateApiUsingAccessToken(accessToken);
|
||||
logger.info("Authentication with token Response: " + map);
|
||||
assertThat(map.get("username"), equalTo("alice"));
|
||||
@ -301,22 +384,23 @@ public class OpenIdConnectAuthIT extends ESRestTestCase {
|
||||
assertThat(map.get("metadata"), instanceOf(Map.class));
|
||||
final Map<?, ?> metadata = (Map<?, ?>) map.get("metadata");
|
||||
assertThat(metadata.get("oidc(sub)"), equalTo("alice"));
|
||||
assertThat(metadata.get("oidc(iss)"), equalTo("http://localhost:8080"));
|
||||
assertThat(metadata.get("oidc(iss)"), equalTo("http://oidc-provider:8080/c2id"));
|
||||
}
|
||||
|
||||
|
||||
private PrepareAuthResponse getRedirectedFromFacilitator(String realmName) throws Exception {
|
||||
final Map<String, String> body = Collections.singletonMap("realm", realmName);
|
||||
Request request = buildRequest("POST", "/_security/oidc/prepare", body, facilitatorAuth());
|
||||
final Response prepare = client().performRequest(request);
|
||||
assertOK(prepare);
|
||||
final Map<String, Object> responseBody = parseResponseAsMap(prepare.getEntity());
|
||||
logger.info("Created OpenIDConnect authentication request {}", responseBody);
|
||||
final String state = (String) responseBody.get("state");
|
||||
final String nonce = (String) responseBody.get("nonce");
|
||||
final String authUri = (String) responseBody.get("redirect");
|
||||
final String realm = (String) responseBody.get("realm");
|
||||
return new PrepareAuthResponse(new URI(authUri), state, nonce, realm);
|
||||
Request request = buildRequest("POST", "/_security/oidc/prepare?error_trace=true", body, facilitatorAuth());
|
||||
try (RestClient restClient = getClient()) {
|
||||
final Response prepare = restClient.performRequest(request);
|
||||
assertOK(prepare);
|
||||
final Map<String, Object> responseBody = parseResponseAsMap(prepare.getEntity());
|
||||
logger.info("Created OpenIDConnect authentication request {}", responseBody);
|
||||
final String state = (String) responseBody.get("state");
|
||||
final String nonce = (String) responseBody.get("nonce");
|
||||
final String authUri = (String) responseBody.get("redirect");
|
||||
final String realm = (String) responseBody.get("realm");
|
||||
return new PrepareAuthResponse(new URI(authUri), state, nonce, realm);
|
||||
}
|
||||
}
|
||||
|
||||
private Tuple<String, String> completeAuthentication(String redirectUri, String state, String nonce, @Nullable String realm)
|
||||
@ -325,17 +409,19 @@ public class OpenIdConnectAuthIT extends ESRestTestCase {
|
||||
body.put("redirect_uri", redirectUri);
|
||||
body.put("state", state);
|
||||
body.put("nonce", nonce);
|
||||
if (realm != null){
|
||||
if (realm != null) {
|
||||
body.put("realm", realm);
|
||||
}
|
||||
Request request = buildRequest("POST", "/_security/oidc/authenticate", body, facilitatorAuth());
|
||||
final Response authenticate = client().performRequest(request);
|
||||
assertOK(authenticate);
|
||||
final Map<String, Object> responseBody = parseResponseAsMap(authenticate.getEntity());
|
||||
logger.info(" OpenIDConnect authentication response {}", responseBody);
|
||||
assertNotNull(responseBody.get("access_token"));
|
||||
assertNotNull(responseBody.get("refresh_token"));
|
||||
return Tuple.tuple(responseBody.get("access_token").toString(), responseBody.get("refresh_token").toString());
|
||||
try (RestClient restClient = getClient()) {
|
||||
final Response authenticate = restClient.performRequest(request);
|
||||
assertOK(authenticate);
|
||||
final Map<String, Object> responseBody = parseResponseAsMap(authenticate.getEntity());
|
||||
logger.info(" OpenIDConnect authentication response {}", responseBody);
|
||||
assertNotNull(responseBody.get("access_token"));
|
||||
assertNotNull(responseBody.get("refresh_token"));
|
||||
return Tuple.tuple(responseBody.get("access_token").toString(), responseBody.get("refresh_token").toString());
|
||||
}
|
||||
}
|
||||
|
||||
private Request buildRequest(String method, String endpoint, Map<String, ?> body, Header... headers) throws IOException {
|
||||
@ -371,47 +457,56 @@ public class OpenIdConnectAuthIT extends ESRestTestCase {
|
||||
* We create a user named `facilitator` with the appropriate privileges ( `manage_oidc` ). A facilitator web app
|
||||
* would need to create one also, in order to access the OIDC related APIs on behalf of the user.
|
||||
*/
|
||||
private void setFacilitatorUser() throws IOException {
|
||||
Request createRoleRequest = new Request("PUT", "/_security/role/facilitator");
|
||||
createRoleRequest.setJsonEntity("{ \"cluster\" : [\"manage_oidc\", \"manage_token\"] }");
|
||||
adminClient().performRequest(createRoleRequest);
|
||||
Request createUserRequest = new Request("PUT", "/_security/user/facilitator");
|
||||
createUserRequest.setJsonEntity("{ \"password\" : \"" + FACILITATOR_PASSWORD + "\", \"roles\" : [\"facilitator\"] }");
|
||||
adminClient().performRequest(createUserRequest);
|
||||
private void setFacilitatorUser() throws Exception {
|
||||
try (RestClient restClient = getClient()) {
|
||||
Request createRoleRequest = new Request("PUT", "/_security/role/facilitator");
|
||||
createRoleRequest.setJsonEntity("{ \"cluster\" : [\"manage_oidc\", \"manage_token\"] }");
|
||||
restClient.performRequest(createRoleRequest);
|
||||
Request createUserRequest = new Request("PUT", "/_security/user/facilitator");
|
||||
createUserRequest.setJsonEntity("{ \"password\" : \"" + FACILITATOR_PASSWORD + "\", \"roles\" : [\"facilitator\"] }");
|
||||
restClient.performRequest(createUserRequest);
|
||||
}
|
||||
}
|
||||
|
||||
private void setRoleMappings() throws IOException {
|
||||
Request createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_kibana");
|
||||
createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"kibana_admin\"]," +
|
||||
"\"enabled\": true," +
|
||||
"\"rules\": {" +
|
||||
" \"any\" : [" +
|
||||
" {\"field\": { \"realm.name\": \"" + REALM_NAME + "\"} }," +
|
||||
" {\"field\": { \"realm.name\": \"" + REALM_NAME_PROXY + "\"} }" +
|
||||
" ]" +
|
||||
"}" +
|
||||
"}");
|
||||
adminClient().performRequest(createRoleMappingRequest);
|
||||
private void setRoleMappings() throws Exception {
|
||||
try (RestClient restClient = getClient()) {
|
||||
Request createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_kibana");
|
||||
createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"kibana_admin\"]," +
|
||||
"\"enabled\": true," +
|
||||
"\"rules\": {" +
|
||||
" \"any\" : [" +
|
||||
" {\"field\": { \"realm.name\": \"" + REALM_NAME + "\"} }," +
|
||||
" {\"field\": { \"realm.name\": \"" + REALM_NAME_PROXY + "\"} }," +
|
||||
" {\"field\": { \"realm.name\": \"" + REALM_NAME_CLIENT_POST_AUTH + "\"} }," +
|
||||
" {\"field\": { \"realm.name\": \"" + REALM_NAME_CLIENT_JWT_AUTH + "\"} }" +
|
||||
" ]" +
|
||||
"}" +
|
||||
"}");
|
||||
restClient.performRequest(createRoleMappingRequest);
|
||||
|
||||
createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_limited");
|
||||
createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"limited_user\"]," +
|
||||
"\"enabled\": true," +
|
||||
"\"rules\": {" +
|
||||
"\"field\": { \"realm.name\": \"" + REALM_NAME_IMPLICIT + "\"}" +
|
||||
"}" +
|
||||
"}");
|
||||
adminClient().performRequest(createRoleMappingRequest);
|
||||
createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_limited");
|
||||
createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"limited_user\"]," +
|
||||
"\"enabled\": true," +
|
||||
"\"rules\": {" +
|
||||
"\"field\": { \"realm.name\": \"" + REALM_NAME_IMPLICIT + "\"}" +
|
||||
"}" +
|
||||
"}");
|
||||
restClient.performRequest(createRoleMappingRequest);
|
||||
|
||||
createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_auditor");
|
||||
createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"auditor\"]," +
|
||||
"\"enabled\": true," +
|
||||
"\"rules\": {" +
|
||||
"\"field\": { \"groups\": \"audit\"}" +
|
||||
"}" +
|
||||
"}");
|
||||
adminClient().performRequest(createRoleMappingRequest);
|
||||
createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_auditor");
|
||||
createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"auditor\"]," +
|
||||
"\"enabled\": true," +
|
||||
"\"rules\": {" +
|
||||
"\"field\": { \"groups\": \"audit\"}" +
|
||||
"}" +
|
||||
"}");
|
||||
restClient.performRequest(createRoleMappingRequest);
|
||||
}
|
||||
}
|
||||
|
||||
private RestClient getClient() throws Exception {
|
||||
return buildClient(restAdminSettings(), new HttpHost[]{new HttpHost("localhost", Integer.parseInt(ES_PORT), "https")});
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple POJO encapsulating a response to calling /_security/oidc/prepare
|
||||
|
BIN
x-pack/qa/oidc-op-tests/src/test/resources/tls/testnode.jks
Normal file
BIN
x-pack/qa/oidc-op-tests/src/test/resources/tls/testnode.jks
Normal file
Binary file not shown.
@ -1,4 +1,37 @@
|
||||
apply plugin: 'elasticsearch.build'
|
||||
apply plugin: 'elasticsearch.test.fixtures'
|
||||
import org.elasticsearch.gradle.VersionProperties
|
||||
import org.elasticsearch.gradle.Architecture
|
||||
|
||||
test.enabled = false
|
||||
apply plugin: 'elasticsearch.test.fixtures'
|
||||
apply plugin: 'elasticsearch.internal-distribution-download'
|
||||
|
||||
task copyKeystore(type: Sync) {
|
||||
from project(':x-pack:plugin:core')
|
||||
.file('src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks')
|
||||
into "${buildDir}/certs"
|
||||
doLast {
|
||||
file("${buildDir}/certs").setReadable(true, false)
|
||||
file("${buildDir}/certs/testnode.jks").setReadable(true, false)
|
||||
}
|
||||
}
|
||||
|
||||
elasticsearch_distributions {
|
||||
docker {
|
||||
type = 'docker'
|
||||
architecture = Architecture.current()
|
||||
flavor = System.getProperty('tests.distribution', 'default')
|
||||
version = VersionProperties.getElasticsearch()
|
||||
failIfUnavailable = false // This ensures we skip this testing if Docker is unavailable
|
||||
}
|
||||
}
|
||||
preProcessFixture {
|
||||
dependsOn copyKeystore, elasticsearch_distributions.docker
|
||||
doLast {
|
||||
File file = file("${buildDir}/logs/node1")
|
||||
file.mkdirs()
|
||||
file.setWritable(true, false)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named('composeUp').configure {
|
||||
dependsOn "preProcessFixture"
|
||||
}
|
||||
|
@ -1,8 +1,121 @@
|
||||
version: '3.1'
|
||||
version: '3.7'
|
||||
services:
|
||||
elasticsearch-node:
|
||||
image: elasticsearch:test
|
||||
environment:
|
||||
- node.name=elasticsearch-node
|
||||
- cluster.initial_master_nodes=elasticsearch-node
|
||||
- cluster.name=elasticsearch-node
|
||||
- bootstrap.memory_lock=true
|
||||
- network.publish_host=127.0.0.1
|
||||
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
|
||||
- path.repo=/tmp/es-repo
|
||||
- node.attr.testattr=test
|
||||
- cluster.routing.allocation.disk.watermark.low=1b
|
||||
- cluster.routing.allocation.disk.watermark.high=1b
|
||||
- cluster.routing.allocation.disk.watermark.flood_stage=1b
|
||||
- node.store.allow_mmap=false
|
||||
- xpack.license.self_generated.type=trial
|
||||
- xpack.security.enabled=true
|
||||
- xpack.security.http.ssl.enabled=true
|
||||
- xpack.security.http.ssl.keystore.path=testnode.jks
|
||||
- xpack.security.authc.token.enabled=true
|
||||
- xpack.security.authc.realms.file.file.order=0
|
||||
- xpack.security.authc.realms.native.native.order=1
|
||||
- xpack.security.authc.realms.oidc.c2id.order=2
|
||||
- xpack.security.authc.realms.oidc.c2id.op.issuer=http://oidc-provider:8080/c2id
|
||||
- xpack.security.authc.realms.oidc.c2id.op.authorization_endpoint=http://oidc-provider:8080/c2id-login
|
||||
- xpack.security.authc.realms.oidc.c2id.op.token_endpoint=http://oidc-provider:8080/c2id/token
|
||||
- xpack.security.authc.realms.oidc.c2id.op.userinfo_endpoint=http://oidc-provider:8080/c2id/userinfo
|
||||
- xpack.security.authc.realms.oidc.c2id.op.jwkset_path=op-jwks.json
|
||||
- xpack.security.authc.realms.oidc.c2id.rp.redirect_uri=https://my.fantastic.rp/cb
|
||||
- xpack.security.authc.realms.oidc.c2id.rp.client_id=https://my.elasticsearch.org/rp
|
||||
- xpack.security.authc.realms.oidc.c2id.rp.response_type=code
|
||||
- xpack.security.authc.realms.oidc.c2id.claims.principal=sub
|
||||
- xpack.security.authc.realms.oidc.c2id.claims.name=name
|
||||
- xpack.security.authc.realms.oidc.c2id.claims.mail=email
|
||||
- xpack.security.authc.realms.oidc.c2id.claims.groups=groups
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.order=3
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.op.issuer=http://oidc-provider:8080/c2id
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.op.authorization_endpoint=http://oidc-provider:8080/c2id-login
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.op.token_endpoint=http://oidc-provider:8080/c2id/token
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.op.userinfo_endpoint=http://oidc-provider:8080/c2id/userinfo
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.op.jwkset_path=op-jwks.json
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.rp.redirect_uri=https://my.fantastic.rp/cb
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.rp.client_id=elasticsearch-rp
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.rp.response_type=id_token token
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.claims.principal=sub
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.claims.name=name
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.claims.mail=email
|
||||
- xpack.security.authc.realms.oidc.c2id-implicit.claims.groups=groups
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.order=4
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.op.issuer=http://oidc-provider:8080/c2id
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.op.authorization_endpoint=http://oidc-provider:8080/c2id-login
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.op.token_endpoint=http://oidc-provider:8080/c2id/token
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.op.userinfo_endpoint=http://oidc-provider:8080/c2id/userinfo
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.op.jwkset_path=op-jwks.json
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.rp.redirect_uri=https://my.fantastic.rp/cb
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.rp.client_id=https://my.elasticsearch.org/rp
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.rp.response_type=code
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.claims.principal=sub
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.claims.name=name
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.claims.mail=email
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.claims.groups=groups
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.http.proxy.host=http-proxy
|
||||
- xpack.security.authc.realms.oidc.c2id-proxy.http.proxy.port=8888
|
||||
- xpack.security.authc.realms.oidc.c2id-post.order=5
|
||||
- xpack.security.authc.realms.oidc.c2id-post.op.issuer=http://oidc-provider:8080/c2id
|
||||
- xpack.security.authc.realms.oidc.c2id-post.op.authorization_endpoint=http://oidc-provider:8080/c2id-login
|
||||
- xpack.security.authc.realms.oidc.c2id-post.op.token_endpoint=http://oidc-provider:8080/c2id/token
|
||||
- xpack.security.authc.realms.oidc.c2id-post.op.userinfo_endpoint=http://oidc-provider:8080/c2id/userinfo
|
||||
- xpack.security.authc.realms.oidc.c2id-post.op.jwkset_path=op-jwks.json
|
||||
- xpack.security.authc.realms.oidc.c2id-post.rp.redirect_uri=https://my.fantastic.rp/cb
|
||||
- xpack.security.authc.realms.oidc.c2id-post.rp.client_id=elasticsearch-post
|
||||
- xpack.security.authc.realms.oidc.c2id-post.rp.client_auth_method=client_secret_post
|
||||
- xpack.security.authc.realms.oidc.c2id-post.rp.response_type=code
|
||||
- xpack.security.authc.realms.oidc.c2id-post.claims.principal=sub
|
||||
- xpack.security.authc.realms.oidc.c2id-post.claims.name=name
|
||||
- xpack.security.authc.realms.oidc.c2id-post.claims.mail=email
|
||||
- xpack.security.authc.realms.oidc.c2id-post.claims.groups=groups
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.order=6
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.op.issuer=http://oidc-provider:8080/c2id
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.op.authorization_endpoint=http://oidc-provider:8080/c2id-login
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.op.token_endpoint=http://oidc-provider:8080/c2id/token
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.op.userinfo_endpoint=http://oidc-provider:8080/c2id/userinfo
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.op.jwkset_path=op-jwks.json
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.rp.redirect_uri=https://my.fantastic.rp/cb
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.rp.client_id=elasticsearch-post-jwt
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.rp.client_auth_method=client_secret_jwt
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.rp.response_type=code
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.claims.principal=sub
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.claims.name=name
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.claims.mail=email
|
||||
- xpack.security.authc.realms.oidc.c2id-jwt.claims.groups=groups
|
||||
volumes:
|
||||
- ./build/logs/node1:/usr/share/elasticsearch/logs
|
||||
- ./build/certs/testnode.jks:/usr/share/elasticsearch/config/testnode.jks
|
||||
- ./docker-test-entrypoint.sh:/docker-test-entrypoint.sh
|
||||
- ./oidc/op-jwks.json:/usr/share/elasticsearch/config/op-jwks.json
|
||||
ports:
|
||||
- "9200"
|
||||
ulimits:
|
||||
memlock:
|
||||
soft: -1
|
||||
hard: -1
|
||||
nofile:
|
||||
soft: 65536
|
||||
hard: 65536
|
||||
entrypoint: /docker-test-entrypoint.sh
|
||||
healthcheck:
|
||||
start_period: 15s
|
||||
test: ["CMD", "curl", "-f", "-u", "x_pack_rest_user:x-pack-test-password", "-k", "https://localhost:9200"]
|
||||
interval: 10s
|
||||
timeout: 2s
|
||||
retries: 5
|
||||
|
||||
openldap:
|
||||
command: --copy-service --loglevel debug
|
||||
image: "osixia/openldap:1.2.3"
|
||||
image: "osixia/openldap:1.4.0"
|
||||
ports:
|
||||
- "389"
|
||||
- "636"
|
||||
@ -41,11 +154,13 @@ services:
|
||||
- ./idp/shib-jetty-base/start.d/ssl.ini:/opt/shib-jetty-base/start.d/ssl.ini
|
||||
|
||||
oidc-provider:
|
||||
image: "c2id/c2id-server:7.8"
|
||||
image: "c2id/c2id-server:9.5"
|
||||
depends_on:
|
||||
- http-proxy
|
||||
ports:
|
||||
- "8080"
|
||||
expose:
|
||||
- "8080"
|
||||
volumes:
|
||||
- ./oidc/override.properties:/etc/c2id/override.properties
|
||||
|
||||
@ -55,3 +170,5 @@ services:
|
||||
- ./oidc/nginx.conf:/etc/nginx/nginx.conf
|
||||
ports:
|
||||
- "8888"
|
||||
expose:
|
||||
- "8888"
|
||||
|
12
x-pack/test/idp-fixture/docker-test-entrypoint.sh
Executable file
12
x-pack/test/idp-fixture/docker-test-entrypoint.sh
Executable file
@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
cd /usr/share/elasticsearch/bin/
|
||||
./elasticsearch-users useradd x_pack_rest_user -p x-pack-test-password -r superuser || true
|
||||
echo "testnode" >/tmp/password
|
||||
echo "b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2" >/tmp/client_secret
|
||||
cat /tmp/password | ./elasticsearch-keystore add -x -f -v 'xpack.security.http.ssl.keystore.secure_password'
|
||||
cat /tmp/client_secret | ./elasticsearch-keystore add -x -f -v 'xpack.security.authc.realms.oidc.c2id.rp.client_secret'
|
||||
cat /tmp/client_secret | ./elasticsearch-keystore add -x -f -v 'xpack.security.authc.realms.oidc.c2id-implicit.rp.client_secret'
|
||||
cat /tmp/client_secret | ./elasticsearch-keystore add -x -f -v 'xpack.security.authc.realms.oidc.c2id-proxy.rp.client_secret'
|
||||
cat /tmp/client_secret | ./elasticsearch-keystore add -x -f -v 'xpack.security.authc.realms.oidc.c2id-post.rp.client_secret'
|
||||
cat /tmp/client_secret | ./elasticsearch-keystore add -x -f -v 'xpack.security.authc.realms.oidc.c2id-jwt.rp.client_secret'
|
||||
/usr/local/bin/docker-entrypoint.sh | tee >/usr/share/elasticsearch/logs/console.log
|
@ -1,4 +1,4 @@
|
||||
op.issuer=http://localhost:8080
|
||||
op.authz.endpoint=http://localhost:8080/c2id-login/
|
||||
op.issuer=http://oidc-provider:8080/c2id
|
||||
op.authz.endpoint=http://oidc-provider:8080/c2id-login/
|
||||
op.reg.apiAccessTokenSHA256=d1c4fa70d9ee708d13cfa01daa0e060a05a2075a53c5cc1ad79e460e96ab5363
|
||||
jose.jwkSer=RnVsbCBrZXk6CnsKICAia2V5cyI6IFsKICAgIHsKICAgICAgInAiOiAiLXhhN2d2aW5tY3N3QXU3Vm1mV2loZ2o3U3gzUzhmd2dFSTdMZEVveW5FU1RzcElaeUY5aHc0NVhQZmI5VHlpbzZsOHZTS0F5RmU4T2lOalpkNE1Ra0ttYlJzTmxxR1Y5VlBoWF84UG1JSm5mcGVhb3E5YnZfU0k1blZHUl9zYUUzZE9sTEE2VWpaS0lsRVBNb0ZuRlZCMUFaUU9qQlhRRzZPTDg2eDZ2NHMwIiwKICAgICAgImt0eSI6ICJSU0EiLAogICAgICAicSI6ICJ2Q3pDQUlpdHV0MGx1V0djQloyLUFabURLc1RxNkkxcUp0RmlEYkIyZFBNQVlBNldOWTdaWEZoVWxsSjJrT2ZELWdlYjlkYkN2ODBxNEwyajVZSjZoOTBUc1NRWWVHRlljN1lZMGdCMU5VR3l5cXctb29QN0EtYlJmMGI3b3I4ajZJb0hzQTZKa2JranN6c3otbkJ2U2RmUURlZkRNSVc3Ni1ZWjN0c2hsY2MiLAogICAgICAiZCI6ICJtbFBOcm1zVVM5UmJtX1I5SElyeHdmeFYzZnJ2QzlaQktFZzRzc1ZZaThfY09lSjV2U1hyQV9laEtwa2g4QVhYaUdWUGpQbVlyd29xQzFVUksxUkZmLVg0dG10emV2OUVHaU12Z0JCaEF5RkdTSUd0VUNla2x4Q2dhb3BpMXdZSU1Bd0M0STZwMUtaZURxTVNCWVZGeHA5ZWlJZ2pwb05JbV9lR3hXUUs5VHNnYmk5T3lyc1VqaE9KLVczN2JVMEJWUU56UXpxODhCcGxmNzM3VmV1dy1FeDZaMk1iWXR3SWdfZ0JVb0JEZ0NrZkhoOVE4MElYcEZRV0x1RzgwenFrdkVwTHZ0RWxLbDRvQ3BHVnBjcmFUOFNsOGpYc3FDT1k0dnVRT19LRVUzS2VPNUNJbHd4eEhJYXZjQTE5cHFpSWJ5cm1LbThxS0ZEWHluUFJMSGFNZ1EiLAogICAgICAiZSI6ICJBUUFCIiwKICAgICAgImtpZCI6ICJyc2EzODRfMjA0OCIsCiAgICAgICJxaSI6ICJzMldTamVrVDl3S2JPbk9neGNoaDJPY3VubzE2Y20wS281Z3hoUWJTdVMyMldfUjJBR2ZVdkRieGF0cTRLakQ3THo3X1k2TjdTUkwzUVpudVhoZ1djeXgyNGhrUGppQUZLNmlkYVZKQzJqQmgycEZTUDVTNXZxZ0lsME12eWY4NjlwdkN4S0NzaGRKMGdlRWhveE93VkRPYXJqdTl2Zm9IQV90LWJoRlZrUnciLAogICAgICAiZHAiOiAiQlJhQTFqYVRydG9mTHZBSUJBYW1OSEVhSm51RU9zTVJJMFRCZXFuR1BNUm0tY2RjSG1OUVo5WUtqb2JpdXlmbnhGZ0piVDlSeElBRG0ySkpoZEp5RTN4Y1dTSzhmSjBSM1Jick1aT1dwako0QmJTVzFtU1VtRnlKTGxib3puRFhZR2RaZ1hzS0o1UkFrRUNQZFBCY3YwZVlkbk9NYWhfZndfaFZoNjRuZ2tFIiwKICAgICAgImFsZyI6ICJSU0EzODQiLAogICAgICAiZHEiOiAiUFJoVERKVlR3cDNXaDZfWFZrTjIwMUlpTWhxcElrUDN1UTYyUlRlTDNrQ2ZXSkNqMkZPLTRxcVRIQk0tQjZJWUVPLXpoVWZyQnhiMzJ1djNjS2JDWGFZN3BJSFJxQlFEQWQ2WGhHYzlwc0xqNThXd3VGY2RncERJYUFpRjNyc3NUMjJ4UFVvYkJFTVdBalV3bFJrNEtNTjItMnpLQk5FR3lIcDIzOUpKdnpVIiwKICAgICAgIm4iOiAidUpDWDVDbEZpM0JnTXBvOWhRSVZ2SDh0Vi1jLTVFdG5OeUZxVm91R3NlNWwyUG92MWJGb0tsRllsU25YTzNWUE9KRWR3azNDdl9VT0UtQzlqZERYRHpvS3Z4RURaTVM1TDZWMFpIVEJoNndIOV9iN3JHSlBxLV9RdlNkejczSzZxbHpGaUtQamRvdTF6VlFYTmZfblBZbnRnQkdNRUtBc1pRNGp0cWJCdE5lV0h0MF9UM001cEktTV9KNGVlRWpCTW95TkZuU2ExTEZDVmZRNl9YVnpjelp1TlRGMlh6UmdRWkFmcmJGRXZ6eXR1TzVMZTNTTXFrUUFJeDhFQmkwYXVlRUNqNEQ4cDNVNXFVRG92NEF2VnRJbUZlbFJvb1pBMHJtVW1KRHJ4WExrVkhuVUpzaUF6ZW9TLTNBSnV1bHJkMGpuNjJ5VjZHV2dFWklZMVNlZVd3IgogICAgfQogIF0KfQo
|
||||
jose.jwkSer=RnVsbCBrZXk6CnsKICAia2V5cyI6IFsKICAgIHsKICAgICAgInAiOiAiLXhhN2d2aW5tY3N3QXU3Vm1mV2loZ2o3U3gzUzhmd2dFSTdMZEVveW5FU1RzcElaeUY5aHc0NVhQZmI5VHlpbzZsOHZTS0F5RmU4T2lOalpkNE1Ra0ttYlJzTmxxR1Y5VlBoWF84UG1JSm5mcGVhb3E5YnZfU0k1blZHUl9zYUUzZE9sTEE2VWpaS0lsRVBNb0ZuRlZCMUFaUU9qQlhRRzZPTDg2eDZ2NHMwIiwKICAgICAgImt0eSI6ICJSU0EiLAogICAgICAicSI6ICJ2Q3pDQUlpdHV0MGx1V0djQloyLUFabURLc1RxNkkxcUp0RmlEYkIyZFBNQVlBNldOWTdaWEZoVWxsSjJrT2ZELWdlYjlkYkN2ODBxNEwyajVZSjZoOTBUc1NRWWVHRlljN1lZMGdCMU5VR3l5cXctb29QN0EtYlJmMGI3b3I4ajZJb0hzQTZKa2JranN6c3otbkJ2U2RmUURlZkRNSVc3Ni1ZWjN0c2hsY2MiLAogICAgICAiZCI6ICJtbFBOcm1zVVM5UmJtX1I5SElyeHdmeFYzZnJ2QzlaQktFZzRzc1ZZaThfY09lSjV2U1hyQV9laEtwa2g4QVhYaUdWUGpQbVlyd29xQzFVUksxUkZmLVg0dG10emV2OUVHaU12Z0JCaEF5RkdTSUd0VUNla2x4Q2dhb3BpMXdZSU1Bd0M0STZwMUtaZURxTVNCWVZGeHA5ZWlJZ2pwb05JbV9lR3hXUUs5VHNnYmk5T3lyc1VqaE9KLVczN2JVMEJWUU56UXpxODhCcGxmNzM3VmV1dy1FeDZaMk1iWXR3SWdfZ0JVb0JEZ0NrZkhoOVE4MElYcEZRV0x1RzgwenFrdkVwTHZ0RWxLbDRvQ3BHVnBjcmFUOFNsOGpYc3FDT1k0dnVRT19LRVUzS2VPNUNJbHd4eEhJYXZjQTE5cHFpSWJ5cm1LbThxS0ZEWHluUFJMSGFNZ1EiLAogICAgICAiZSI6ICJBUUFCIiwKICAgICAgImtpZCI6ICJyc2EzODRfMjA0OCIsCiAgICAgICJxaSI6ICJzMldTamVrVDl3S2JPbk9neGNoaDJPY3VubzE2Y20wS281Z3hoUWJTdVMyMldfUjJBR2ZVdkRieGF0cTRLakQ3THo3X1k2TjdTUkwzUVpudVhoZ1djeXgyNGhrUGppQUZLNmlkYVZKQzJqQmgycEZTUDVTNXZxZ0lsME12eWY4NjlwdkN4S0NzaGRKMGdlRWhveE93VkRPYXJqdTl2Zm9IQV90LWJoRlZrUnciLAogICAgICAiZHAiOiAiQlJhQTFqYVRydG9mTHZBSUJBYW1OSEVhSm51RU9zTVJJMFRCZXFuR1BNUm0tY2RjSG1OUVo5WUtqb2JpdXlmbnhGZ0piVDlSeElBRG0ySkpoZEp5RTN4Y1dTSzhmSjBSM1Jick1aT1dwako0QmJTVzFtU1VtRnlKTGxib3puRFhZR2RaZ1hzS0o1UkFrRUNQZFBCY3YwZVlkbk9NYWhfZndfaFZoNjRuZ2tFIiwKICAgICAgImFsZyI6ICJSU0EzODQiLAogICAgICAiZHEiOiAiUFJoVERKVlR3cDNXaDZfWFZrTjIwMUlpTWhxcElrUDN1UTYyUlRlTDNrQ2ZXSkNqMkZPLTRxcVRIQk0tQjZJWUVPLXpoVWZyQnhiMzJ1djNjS2JDWGFZN3BJSFJxQlFEQWQ2WGhHYzlwc0xqNThXd3VGY2RncERJYUFpRjNyc3NUMjJ4UFVvYkJFTVdBalV3bFJrNEtNTjItMnpLQk5FR3lIcDIzOUpKdnpVIiwKICAgICAgIm4iOiAidUpDWDVDbEZpM0JnTXBvOWhRSVZ2SDh0Vi1jLTVFdG5OeUZxVm91R3NlNWwyUG92MWJGb0tsRllsU25YTzNWUE9KRWR3azNDdl9VT0UtQzlqZERYRHpvS3Z4RURaTVM1TDZWMFpIVEJoNndIOV9iN3JHSlBxLV9RdlNkejczSzZxbHpGaUtQamRvdTF6VlFYTmZfblBZbnRnQkdNRUtBc1pRNGp0cWJCdE5lV0h0MF9UM001cEktTV9KNGVlRWpCTW95TkZuU2ExTEZDVmZRNl9YVnpjelp1TlRGMlh6UmdRWkFmcmJGRXZ6eXR1TzVMZTNTTXFrUUFJeDhFQmkwYXVlRUNqNEQ4cDNVNXFVRG92NEF2VnRJbUZlbFJvb1pBMHJtVW1KRHJ4WExrVkhuVUpzaUF6ZW9TLTNBSnV1bHJkMGpuNjJ5VjZHV2dFWklZMVNlZVd3IgogICAgfQogIF0KfQo
|
||||
|
Loading…
x
Reference in New Issue
Block a user