Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OIDC realm authentication flows #37787

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6448271
Implement code and implicit flows
jkakavas Jan 23, 2019
92f63ef
fix licenses and SHAs for introduced dependencies
jkakavas Jan 23, 2019
19034ce
Support userinfo requests
jkakavas Jan 23, 2019
aaa5426
Merge remote-tracking branch 'origin/master' into oidc-realm-authenti…
jkakavas Jan 24, 2019
6614057
Add few tests
jkakavas Jan 24, 2019
b70526a
Fix bugs and add unit tests
jkakavas Jan 25, 2019
422319d
Merge remote-tracking branch 'origin/feature-oidc-realm' into oidc-re…
jkakavas Jan 25, 2019
05910d9
Address Feedback
jkakavas Jan 29, 2019
22e8bb7
Merge remote-tracking branch 'origin/feature-oidc-realm' into oidc-re…
jkakavas Jan 29, 2019
b8aa5be
Fix Access Token validation
jkakavas Jan 30, 2019
e3204f5
Completes security tests
jkakavas Jan 30, 2019
ad493a9
Merge remote-tracking branch 'origin/feature-oidc-realm' into oidc-re…
jkakavas Jan 30, 2019
b3cbd8d
Fix checkstyle
jkakavas Jan 30, 2019
0a0ae0e
Make JWKSource reloading async
jkakavas Feb 1, 2019
bc1f552
Merge remote-tracking branch 'origin/feature-oidc-realm' into oidc-re…
jkakavas Feb 1, 2019
baadcdb
fix thirdPartyAudit
jkakavas Feb 1, 2019
09413b5
address feedback
jkakavas Feb 1, 2019
59bc122
cleanup
jkakavas Feb 2, 2019
b368ffc
re-introduce the option for facilitators to pass state and nonce values
jkakavas Feb 3, 2019
81a1770
remove unused import
jkakavas Feb 3, 2019
c9c1cf7
Merge branch 'feature-oidc-realm' into oidc-realm-authentication-flows
jkakavas Feb 3, 2019
3450541
fix tests
jkakavas Feb 3, 2019
9d30bd2
address feedback
jkakavas Feb 5, 2019
82d23a6
Merge branch 'feature-oidc-realm' into oidc-realm-authentication-flows
jkakavas Feb 5, 2019
6098583
Handle deprecation header-AbstractUpgradeTestCase
jkakavas Feb 5, 2019
fa7c024
Revert "Handle deprecation header-AbstractUpgradeTestCase"
jkakavas Feb 5, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.DelegatedAuthorizationSettings;
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
Expand All @@ -24,34 +32,146 @@ private OpenIdConnectRealmSettings() {

public static final String TYPE = "oidc";

public static final Setting.AffixSetting<String> OP_NAME
= RealmSettings.simpleString(TYPE, "op.name", Setting.Property.NodeScope);
public static final Setting.AffixSetting<String> RP_CLIENT_ID
= RealmSettings.simpleString(TYPE, "rp.client_id", Setting.Property.NodeScope);
public static final Setting.AffixSetting<SecureString> RP_CLIENT_SECRET
= RealmSettings.secureString(TYPE, "rp.client_secret");
public static final Setting.AffixSetting<String> RP_REDIRECT_URI
= RealmSettings.simpleString(TYPE, "rp.redirect_uri", Setting.Property.NodeScope);
= Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "rp.redirect_uri",
key -> Setting.simpleString(key, v -> {
try {
new URI(v);
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Invalid value [" + v + "] for [" + key + "]. Not a valid URI.", e);
}
}, Setting.Property.NodeScope));
public static final Setting.AffixSetting<String> RP_RESPONSE_TYPE
= RealmSettings.simpleString(TYPE, "rp.response_type", Setting.Property.NodeScope);
= Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "rp.response_type",
key -> Setting.simpleString(key, v -> {
List<String> responseTypes = Arrays.asList("code", "id_token");
if (responseTypes.contains(v) == false) {
throw new IllegalArgumentException("Invalid value [" + v + "] for [" + key + "]. Allowed values are " + responseTypes + "");
}
}, Setting.Property.NodeScope));
public static final Setting.AffixSetting<String> RP_SIGNATURE_VERIFICATION_ALGORITHM
= Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "rp.signature_verification_algorithm",
key -> new Setting<>(key, "RS256", Function.identity(), v -> {
List<String> sigAlgo = Arrays.asList("HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384",
jkakavas marked this conversation as resolved.
Show resolved Hide resolved
"ES512", "PS256", "PS384", "PS512");
if (sigAlgo.contains(v) == false) {
throw new IllegalArgumentException(
"Invalid value [" + v + "] for [" + key + "]. Allowed values are " + sigAlgo + "}]");
}
}, Setting.Property.NodeScope));
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));
jkakavas marked this conversation as resolved.
Show resolved Hide resolved

public static final Setting.AffixSetting<String> OP_NAME
= RealmSettings.simpleString(TYPE, "op.name", Setting.Property.NodeScope);
public static final Setting.AffixSetting<String> OP_AUTHORIZATION_ENDPOINT
= RealmSettings.simpleString(TYPE, "op.authorization_endpoint", Setting.Property.NodeScope);
= Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "op.authorization_endpoint",
key -> Setting.simpleString(key, v -> {
try {
new URI(v);
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Invalid value [" + v + "] for [" + key + "]. Not a valid URI.", e);
}
}, Setting.Property.NodeScope));
public static final Setting.AffixSetting<String> OP_TOKEN_ENDPOINT
= RealmSettings.simpleString(TYPE, "op.token_endpoint", Setting.Property.NodeScope);
= Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "op.token_endpoint",
key -> Setting.simpleString(key, v -> {
try {
new URI(v);
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Invalid value [" + v + "] for [" + key + "]. Not a valid URI.", e);
}
}, Setting.Property.NodeScope));
public static final Setting.AffixSetting<String> OP_USERINFO_ENDPOINT
= RealmSettings.simpleString(TYPE, "op.userinfo_endpoint", Setting.Property.NodeScope);
= Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "op.token_endpoint",
jkakavas marked this conversation as resolved.
Show resolved Hide resolved
key -> Setting.simpleString(key, v -> {
try {
new URI(v);
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Invalid value [" + v + "] for [" + key + "]. Not a valid URI.", e);
}
}, Setting.Property.NodeScope));
public static final Setting.AffixSetting<String> OP_ISSUER
= RealmSettings.simpleString(TYPE, "op.issuer", Setting.Property.NodeScope);
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> OP_JWKSET_URL
= Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "op.jwkset_url",
key -> Setting.simpleString(key, v -> {
try {
new URL(v);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Invalid value [" + v + "] for [" + key + "]. Not a valid URL.", e);
}
}, Setting.Property.NodeScope));

public static final Setting.AffixSetting<Boolean> POPULATE_USER_METADATA = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "populate_user_metadata",
key -> Setting.boolSetting(key, true, Setting.Property.NodeScope));

public static final ClaimSetting PRINCIPAL_CLAIM = new ClaimSetting("principal");
public static final ClaimSetting GROUPS_CLAIM = new ClaimSetting("groups");
public static final ClaimSetting NAME_CLAIM = new ClaimSetting("name");
public static final ClaimSetting DN_CLAIM = new ClaimSetting("dn");
public static final ClaimSetting MAIL_CLAIM = new ClaimSetting("mail");

public static Set<Setting.AffixSetting<?>> getSettings() {
final Set<Setting.AffixSetting<?>> set = Sets.newHashSet(
OP_NAME, RP_CLIENT_ID, RP_REDIRECT_URI, RP_RESPONSE_TYPE, RP_REQUESTED_SCOPES, RP_CLIENT_SECRET,
OP_AUTHORIZATION_ENDPOINT, OP_TOKEN_ENDPOINT, OP_USERINFO_ENDPOINT, OP_ISSUER);
RP_CLIENT_ID, RP_REDIRECT_URI, RP_RESPONSE_TYPE, RP_REQUESTED_SCOPES, RP_CLIENT_SECRET, RP_SIGNATURE_VERIFICATION_ALGORITHM,
OP_NAME, OP_AUTHORIZATION_ENDPOINT, OP_TOKEN_ENDPOINT, OP_USERINFO_ENDPOINT, OP_ISSUER, OP_JWKSET_URL);
set.addAll(DelegatedAuthorizationSettings.getSettings(TYPE));
set.addAll(RealmSettings.getStandardSettings(TYPE));
set.addAll(SSLConfigurationSettings.getRealmSettings(TYPE));
set.addAll(PRINCIPAL_CLAIM.settings());
set.addAll(GROUPS_CLAIM.settings());
set.addAll(DN_CLAIM.settings());
set.addAll(NAME_CLAIM.settings());
set.addAll(MAIL_CLAIM.settings());
return set;
}


/**
* The OIDC realm offers a number of settings that rely on claim values that are populated by the OP in the ID Token or the User Info
* response.
* Each claim has 2 settings:
* <ul>
* <li>The name of the OpenID Connect claim to use</li>
* <li>An optional java pattern (regex) to apply to that claim value in order to extract the substring that should be used.</li>
* </ul>
* For example, the Elasticsearch User Principal could be configured to come from the OpenID Connect standard claim "email",
* and extract only the local-port of the user's email address (i.e. the name before the '@').
jkakavas marked this conversation as resolved.
Show resolved Hide resolved
* This class encapsulates those 2 settings.
*/
public static final class ClaimSetting {
public static final String CLAIMS_PREFIX = "claims.";
public static final String CLAIM_PATTERNS_PREFIX = "claim_patterns.";

private final Setting.AffixSetting<String> claim;
private final Setting.AffixSetting<String> pattern;

public ClaimSetting(String name) {
claim = RealmSettings.simpleString(TYPE, CLAIMS_PREFIX + name, Setting.Property.NodeScope);
pattern = RealmSettings.simpleString(TYPE, CLAIM_PATTERNS_PREFIX + name, Setting.Property.NodeScope);
}

public Collection<Setting.AffixSetting<?>> settings() {
return Arrays.asList(getClaim(), getPattern());
}

public String name(RealmConfig config) {
return getClaim().getConcreteSettingForNamespace(config.name()).getKey();
}

public Setting.AffixSetting<String> getClaim() {
return claim;
}

public Setting.AffixSetting<String> getPattern() {
return pattern;
}
}
}
24 changes: 23 additions & 1 deletion x-pack/plugin/security/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ dependencies {
compile "org.apache.httpcomponents:httpclient-cache:${versions.httpclient}"
compile 'com.google.guava:guava:19.0'

// Dependencies for oidc
compile "com.nimbusds:oauth2-oidc-sdk:6.5"
compile "com.nimbusds:nimbus-jose-jwt:4.41.2"
compile "com.nimbusds:lang-tag:1.4.4"
compile "com.sun.mail:javax.mail:1.6.2"
compile "net.jcip:jcip-annotations:1.0"
compile "net.minidev:json-smart:2.3"
compile "net.minidev:accessors-smart:1.2"


testCompile 'org.elasticsearch:securemock:1.2'
testCompile "org.elasticsearch:mocksocket:${versions.mocksocket}"
//testCompile "org.yaml:snakeyaml:${versions.snakeyaml}"
Expand Down Expand Up @@ -257,7 +267,19 @@ thirdPartyAudit {
'net.sf.ehcache.Ehcache',
'net.sf.ehcache.Element',
// [missing classes] SLF4j includes an optional class that depends on an extension class (!)
'org.slf4j.ext.EventData'
'org.slf4j.ext.EventData',
'javax.activation.ActivationDataFlavor',
'javax.activation.DataContentHandler',
'javax.activation.DataHandler',
'javax.activation.DataSource',
'javax.activation.FileDataSource',
'javax.activation.FileTypeMap',
'org.cryptomator.siv.SivMode',
'org.objectweb.asm.ClassWriter',
'org.objectweb.asm.Label',
'org.objectweb.asm.MethodVisitor',
'org.objectweb.asm.Type'

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: extra line

)

ignoreViolations (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c592b500269bfde36096641b01238a8350f8aa31
Loading