Include realm type in Security Realm setting keys (#30241)

This moves all Realm settings to an Affix definition.
However, because different realm types define different settings
(potentially conflicting settings) this requires that the realm type
become part of the setting key.

Thus, we now need to define realm settings as:

    xpack.security.authc.realms:
      file.file1:
        order: 0

      native.native1:
        order: 1

- This is a breaking change to realm config
- This is also a breaking change to custom security realms (SecurityExtension)
This commit is contained in:
Tim Vernum 2018-11-06 14:56:50 +11:00 committed by GitHub
parent 00e66bab36
commit 574ec6686e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
136 changed files with 2984 additions and 2311 deletions

View File

@ -66,3 +66,32 @@ used. Therefore, these settings have been renamed from `search.remote.*` to
in the cluster state, or set on dynamic settings updates, we will automatically
upgrade the setting from `search.remote.*` to `cluster.remote.*`. The fallback
settings will be removed in 8.0.0.
[[include-realm-type-in-setting]]
==== Security realms settings
The settings for all security realms must now include the realm type as part
of the setting name, and the explicit `type` setting has been removed.
A realm that was previous configured as:
[source,yaml]
--------------------------------------------------
xpack.security.authc.realms:
ldap1:
type: ldap
order: 1
url: "ldaps://ldap.example.com/"
--------------------------------------------------
Must be migrated to:
[source,yaml]
--------------------------------------------------
xpack.security.authc.realms:
ldap.ldap1:
order: 1
url: "ldaps://ldap.example.com/"
--------------------------------------------------
Any realm specific secure settings that have been stored in the elasticsearch
keystore (such as ldap bind passwords, or passwords for ssl keys) must be updated
in a similar way.

View File

@ -32,12 +32,12 @@ xpack:
authc:
realms:
active_directory:
type: active_directory
order: 0
domain_name: ad.example.com
url: ldaps://ad.example.com:636
ssl:
certificate_authorities: [ "ES_PATH_CONF/cacert.pem" ]
ad_realm:
order: 0
domain_name: ad.example.com
url: ldaps://ad.example.com:636
ssl:
certificate_authorities: [ "ES_PATH_CONF/cacert.pem" ]
--------------------------------------------------
The CA cert must be a PEM encoded certificate.

View File

@ -24,12 +24,12 @@ xpack:
security:
authc:
realms:
ldap1:
type: ldap
order: 0
url: "ldaps://ldap.example.com:636"
ssl:
certificate_authorities: [ "ES_PATH_CONF/cacert.pem" ]
ldap:
ldap1:
order: 0
url: "ldaps://ldap.example.com:636"
ssl:
certificate_authorities: [ "ES_PATH_CONF/cacert.pem" ]
--------------------------------------------------
The CA certificate must be a PEM encoded.
@ -52,4 +52,4 @@ NOTE: By default, when you configure {security} to connect to an LDAP server
configuration do not match, {security} does not allow a connection to the
LDAP server. This is done to protect against man-in-the-middle attacks. If
necessary, you can disable this behavior by setting the
`ssl.verification_mode` property to `certificate`.
`ssl.verification_mode` property to `certificate`.

View File

@ -42,9 +42,10 @@ recommend that you explicitly add this setting to avoid confusion.
A comma-separated list of settings that are omitted from the results of the
<<cluster-nodes-info,cluster nodes info API>>. You can use wildcards to include
multiple settings in the list. For example, the following value hides all the
settings for the ad1 realm: `xpack.security.authc.realms.ad1.*`. The API already
omits all `ssl` settings, `bind_dn`, and `bind_password` due to the
sensitive nature of the information.
settings for the ad1 active_directory realm:
`xpack.security.authc.realms.active_directory.ad1.*`.
The API already omits all `ssl` settings, `bind_dn`, and `bind_password` due to
the sensitive nature of the information.
`xpack.security.fips_mode.enabled`::
Enables fips mode of operation. Set this to `true` if you run this {es} instance in a FIPS 140-2 enabled JVM. For more information, see <<fips-140-compliance>>. Defaults to `false`.
@ -149,18 +150,15 @@ namespace in `elasticsearch.yml`. For example:
----------------------------------------
xpack.security.authc.realms:
realm1:
type: native
native.realm1:
order: 0
...
realm2:
type: ldap
ldap.realm2:
order: 1
...
realm3:
type: active_directory
active_directory.realm3:
order: 2
...
...

View File

@ -11,9 +11,9 @@ For more information about Active Directory realms, see
{xpack-ref}/active-directory-realm.html[Active Directory User Authentication].
. Add a realm configuration of type `active_directory` to `elasticsearch.yml`
under the `xpack.security.authc.realms` namespace. At a minimum, you must set
the realm `type` to `active_directory` and specify the Active Directory
`domain_name`. If you are configuring multiple realms, you should also
under the `xpack.security.authc.realms.active_directory` namespace.
At a minimum, you must specify the Active Directory `domain_name`.
If you are configuring multiple realms, you should also
explicitly set the `order` attribute to control the order in which the realms
are consulted during authentication.
+
@ -35,10 +35,10 @@ xpack:
authc:
realms:
active_directory:
type: active_directory
order: 0 <1>
domain_name: ad.example.com
url: ldaps://ad.example.com:636 <2>
my_ad:
order: 0 <1>
domain_name: ad.example.com
url: ldaps://ad.example.com:636 <2>
------------------------------------------------------------
<1> The realm order controls the order in which the configured realms are checked
when authenticating a user.
@ -71,12 +71,12 @@ xpack:
authc:
realms:
active_directory:
type: active_directory
order: 0
domain_name: example.com <1>
url: ldaps://dc1.ad.example.com:3269, ldaps://dc2.ad.example.com:3269 <2>
load_balance:
type: "round_robin" <3>
my_ad:
order: 0
domain_name: example.com <1>
url: ldaps://dc1.ad.example.com:3269, ldaps://dc2.ad.example.com:3269 <2>
load_balance:
type: "round_robin" <3>
------------------------------------------------------------
<1> The `domain_name` is set to the name of the root domain in the forest.
<2> The `url` value used in this example has URLs for two different Domain Controllers,
@ -135,11 +135,11 @@ xpack:
authc:
realms:
active_directory:
type: active_directory
order: 0
domain_name: ad.example.com
url: ldaps://ad.example.com:636
bind_dn: es_svc_user@ad.example.com <1>
my_ad:
order: 0
domain_name: ad.example.com
url: ldaps://ad.example.com:636
bind_dn: es_svc_user@ad.example.com <1>
------------------------------------------------------------
<1> This is the user that all Active Directory search requests are executed as.
Without a bind user configured, all requests run as the user that is authenticating
@ -152,7 +152,7 @@ the following command adds the password for the example realm above:
[source, shell]
------------------------------------------------------------
bin/elasticsearch-keystore add \
xpack.security.authc.realms.active_directory.secure_bind_password
xpack.security.authc.realms.active_directory.my_ad.secure_bind_password
------------------------------------------------------------
When a bind user is configured, connection pooling is enabled by default.

View File

@ -25,10 +25,9 @@ explicitly configure a `file` realm.
For more information about file realms, see
{xpack-ref}/file-realm.html[File-based user authentication].
. (Optional) Add a realm configuration of type `file` to `elasticsearch.yml`
under the `xpack.security.authc.realms` namespace. At a minimum, you must set
the realm `type` to `file`. If you are configuring multiple realms, you should
also explicitly set the `order` attribute.
. (Optional) Add a realm configuration to `elasticsearch.yml` under the
`xpack.security.authc.realms.file` namespace. At a minimum, you must set
the realm's `order` attribute.
+
--
//See <<ref-users-settings>> for all of the options you can set for a `file` realm.
@ -42,9 +41,9 @@ xpack:
security:
authc:
realms:
file1:
type: file
order: 0
file:
file1:
order: 0
------------------------------------------------------------
--

View File

@ -113,15 +113,14 @@ NOTE: You can configure only one Kerberos realm on {es} nodes.
To configure a Kerberos realm, there are a few mandatory realm settings and
other optional settings that you need to configure in the `elasticsearch.yml`
configuration file. Add a realm of type `kerberos` under the
`xpack.security.authc.realms` namespace.
configuration file. Add a realm configuration under the
`xpack.security.authc.realms.kerberos` namespace.
The most common configuration for a Kerberos realm is as follows:
[source, yaml]
------------------------------------------------------------
xpack.security.authc.realms.kerb1:
type: kerberos
xpack.security.authc.realms.kerberos.kerb1:
order: 3
keytab.path: es.keytab
remove_realm_name: false

View File

@ -27,12 +27,12 @@ However, multiple bind operations might be needed to find the correct user DN.
. To configure an `ldap` realm with user search:
.. Add a realm configuration of type `ldap` to `elasticsearch.yml` under the
`xpack.security.authc.realms` namespace. At a minimum, you must set the realm
`type` to `ldap`, specify the `url` of the LDAP server, and set
`user_search.base_dn` to the container DN where the users are searched for. If
you are configuring multiple realms, you should also explicitly set the `order`
attribute to control the order in which the realms are consulted during
.. Add a realm configuration of to `elasticsearch.yml` under the
`xpack.security.authc.realms.ldap` namespace. At a minimum, you must specify
the `url` of the LDAP server, and set `user_search.base_dn` to the container DN
where the users are searched for.
If you are configuring multiple realms, you should also explicitly set the
`order` attribute to control the order in which the realms are consulted during
authentication. See <<ref-ldap-settings>> for all of the options you can set for
an `ldap` realm.
+
@ -45,19 +45,19 @@ xpack:
security:
authc:
realms:
ldap1:
type: ldap
order: 0
url: "ldaps://ldap.example.com:636"
bind_dn: "cn=ldapuser, ou=users, o=services, dc=example, dc=com"
user_search:
base_dn: "dc=example,dc=com"
attribute: cn
group_search:
base_dn: "dc=example,dc=com"
files:
role_mapping: "ES_PATH_CONF/role_mapping.yml"
unmapped_groups_as_roles: false
ldap:
ldap1:
order: 0
url: "ldaps://ldap.example.com:636"
bind_dn: "cn=ldapuser, ou=users, o=services, dc=example, dc=com"
user_search:
base_dn: "dc=example,dc=com"
attribute: cn
group_search:
base_dn: "dc=example,dc=com"
files:
role_mapping: "ES_PATH_CONF/role_mapping.yml"
unmapped_groups_as_roles: false
------------------------------------------------------------
The password for the `bind_dn` user should be configured by adding the appropriate
@ -67,7 +67,7 @@ For example, the following command adds the password for the example realm above
[source, shell]
------------------------------------------------------------
bin/elasticsearch-keystore add \
xpack.security.authc.realms.ldap1.secure_bind_password
xpack.security.authc.realms.ldap.ldap1.secure_bind_password
------------------------------------------------------------
IMPORTANT: When you configure realms in `elasticsearch.yml`, only the
@ -78,13 +78,13 @@ realms you specify are used for authentication. If you also want to use the
. To configure an `ldap` realm with user DN templates:
.. Add a realm configuration of type `ldap` to `elasticsearch.yml` in the
`xpack.security.authc.realms` namespace. At a minimum, you must set the realm
`type` to `ldap`, specify the `url` of the LDAP server, and specify at least one
template with the `user_dn_templates` option. If you are configuring multiple
realms, you should also explicitly set the `order` attribute to control the
order in which the realms are consulted during authentication. See
<<ref-ldap-settings>> for all of the options you can set for an `ldap` realm.
.. Add a realm configuration to `elasticsearch.yml` in the
`xpack.security.authc.realms.ldap` namespace. At a minimum, you must specify
the `url` of the LDAP server, and specify at least one template with the
`user_dn_templates` option. If you are configuring multiple realms, you should
also explicitly set the `order` attribute to control the order in which the
realms are consulted during authentication.
See <<ref-ldap-settings>> for all of the options you can set for an `ldap` realm.
+
--
For example, the following snippet shows an LDAP realm configured with user DN
@ -96,18 +96,18 @@ xpack:
security:
authc:
realms:
ldap1:
type: ldap
order: 0
url: "ldaps://ldap.example.com:636"
user_dn_templates:
- "cn={0}, ou=users, o=marketing, dc=example, dc=com"
- "cn={0}, ou=users, o=engineering, dc=example, dc=com"
group_search:
base_dn: "dc=example,dc=com"
files:
role_mapping: "/mnt/elasticsearch/group_to_role_mapping.yml"
unmapped_groups_as_roles: false
ldap:
ldap1:
order: 0
url: "ldaps://ldap.example.com:636"
user_dn_templates:
- "cn={0}, ou=users, o=marketing, dc=example, dc=com"
- "cn={0}, ou=users, o=engineering, dc=example, dc=com"
group_search:
base_dn: "dc=example,dc=com"
files:
role_mapping: "/mnt/elasticsearch/group_to_role_mapping.yml"
unmapped_groups_as_roles: false
------------------------------------------------------------
IMPORTANT: The `bind_dn` setting is not used in template mode.
@ -212,8 +212,8 @@ xpack:
security:
authc:
realms:
ldap1:
type: ldap
metadata: cn
ldap:
ldap1:
metadata: cn
--------------------------------------------------
--

View File

@ -9,15 +9,15 @@ The native realm is available by default when no other realms are
configured. If other realm settings have been configured in `elasticsearch.yml`,
you must add the native realm to the realm chain.
You can configure options for the `native` realm in the
`xpack.security.authc.realms` namespace in `elasticsearch.yml`. Explicitly
configuring a native realm enables you to set the order in which it appears in
the realm chain, temporarily disable the realm, and control its cache options.
You can configure a `native` realm in the `xpack.security.authc.realms.native`
namespace in `elasticsearch.yml`.
Explicitly configuring a native realm enables you to set the order in which it
appears in the realm chain, temporarily disable the realm, and control its
cache options.
. Add a realm configuration of type `native` to `elasticsearch.yml` under the
`xpack.security.authc.realms` namespace. At a minimum, you must set the realm
`type` to `native`. If you are configuring multiple realms, you should also
explicitly set the `order` attribute.
. Add a realm configuration to `elasticsearch.yml` under the
`xpack.security.authc.realms.native` namespace. It is recommended that you
explicitly set the `order` attribute for the realm.
+
--
See <<ref-native-settings>> for all of the options you can set for the `native` realm.
@ -30,9 +30,9 @@ xpack:
security:
authc:
realms:
native1:
type: native
order: 0
native:
native1:
order: 0
------------------------------------------------------------
NOTE: To limit exposure to credential theft and mitigate credential compromise,

View File

@ -24,9 +24,9 @@ IMPORTANT: You must enable SSL/TLS and enable client authentication to use PKI.
For more information, see {xpack-ref}/pki-realm.html[PKI User Authentication].
. Add a realm configuration of type `pki` to `elasticsearch.yml` under the
`xpack.security.authc.realms` namespace. At a minimum, you must set the realm
`type` to `pki`. If you are configuring multiple realms, you should also
. Add a realm configuration for a `pki` realm to `elasticsearch.yml` under the
`xpack.security.authc.realms.pki` namespace.
If you are configuring multiple realms, you should
explicitly set the `order` attribute. See <<ref-pki-settings>> for all of the
options you can set for a `pki` realm.
+
@ -39,8 +39,9 @@ xpack:
security:
authc:
realms:
pki1:
type: pki
pki:
pki1:
order: 1
------------------------------------------------------------
With this configuration, any certificate trusted by the SSL/TLS layer is accepted
@ -61,9 +62,9 @@ xpack:
security:
authc:
realms:
pki1:
type: pki
username_pattern: "EMAILADDRESS=(.*?)(?:,|$)"
pki:
pki1:
username_pattern: "EMAILADDRESS=(.*?)(?:,|$)"
------------------------------------------------------------
--
@ -112,11 +113,11 @@ xpack:
security:
authc:
realms:
pki1:
type: pki
truststore:
path: "/path/to/pki_truststore.jks"
password: "x-pack-test-password"
pki:
pki1:
truststore:
path: "/path/to/pki_truststore.jks"
password: "x-pack-test-password"
------------------------------------------------------------
The `certificate_authorities` option can be used as an alternative to the

View File

@ -84,18 +84,19 @@ configuration file) are the most common settings:
[source, yaml]
------------------------------------------------------------
xpack.security.authc.realms.saml1: <1>
type: saml <2>
order: 2 <3>
idp.metadata.path: saml/idp-metadata.xml <4>
idp.entity_id: "https://sso.example.com/" <5>
sp.entity_id: "https://kibana.example.com/" <6>
sp.acs: "https://kibana.example.com/api/security/v1/saml" <7>
sp.logout: "https://kibana.example.com/logout" <8>
xpack.security.authc.realms:
saml: <1>
saml1: <2>
order: 2 <3>
idp.metadata.path: saml/idp-metadata.xml <4>
idp.entity_id: "https://sso.example.com/" <5>
sp.entity_id: "https://kibana.example.com/" <6>
sp.acs: "https://kibana.example.com/api/security/v1/saml" <7>
sp.logout: "https://kibana.example.com/logout" <8>
------------------------------------------------------------
<1> This setting defines a new authentication realm named "saml1". For an
<1> The realm must be within the `xpack.security.authc.realms.saml` namespace.
<2> This setting defines a new authentication realm named "saml1". For an
introduction to realms, see {stack-ov}/realms.html[Realms].
<2> The `type` must be `saml`.
<3> You should define a unique order on each realm in your authentication chain.
It is recommended that the SAML realm be at the bottom of your authentication
chain (that is, it has the _highest_ order).
@ -169,7 +170,7 @@ file:
[source, yaml]
------------------------------------------------------------
xpack.security.authc.realms.saml1:
xpack.security.authc.realms.saml.saml1:
...
attributes.principal: "urn:oid:0.9.2342.19200300.100.1.1"
attributes.groups: "urn:oid:1.3.6.1.4.1.5923.1.5.1."

View File

@ -85,13 +85,15 @@ bin/elasticsearch-plugin install file:///<path>/my-realm-1.0.zip
----------------------------------------
. Add a realm configuration of the appropriate realm type to `elasticsearch.yml`
under the `xpack.security.authc.realms` namespace. The options you can set depend
on the settings exposed by the custom realm. At a minimum, you must set the realm
`type` to the type defined by the extension. If you are configuring multiple
realms, you should also explicitly set the `order` attribute to control the
order in which the realms are consulted during authentication. You should make
sure each configured realm has a distinct `order` setting. In the event that
two or more realms have the same `order`, they will be processed in realm `name` order.
under the `xpack.security.authc.realms` namespace.
You must define your realm within the namespace that matchesto the type defined
by the extension.
The options you can set depend on the settings exposed by the custom realm.
If you are configuring multiple realms, you should also explicitly set the
`order` attribute to control the order in which the realms are consulted during
authentication. You should make sure each configured realm has a distinct
`order` setting. In the event that two or more realms have the same `order`,
they will be processed in realm `name` order.
+
IMPORTANT: When you configure realms in `elasticsearch.yml`, only the
realms you specify are used for authentication. If you also want to use the

View File

@ -120,8 +120,7 @@ configuration file. Each configuration value is explained below.
[source, yaml]
------------------------------------------------------------
xpack.security.authc.realms.saml1:
type: saml
xpack.security.authc.realms.saml.saml1:
order: 2
idp.metadata.path: saml/idp-metadata.xml
idp.entity_id: "https://sso.example.com/"
@ -140,11 +139,10 @@ clients.
The configuration values used in the example above are:
xpack.security.authc.realms.saml::
This defines a new authentication realm named "saml1".
xpack.security.authc.realms.saml.saml1::
This defines a new `saml` authentication realm named "saml1".
See <<realms>> for more explanation of realms.
type:: The `type` must be `saml`
order::
You should define a unique order on each realm in your authentication chain.
It is recommended that the SAML realm be at the bottom of your authentication
@ -281,8 +279,7 @@ and the attribute with the friendlyName "roles" for the user's groups.
[source, yaml]
------------------------------------------------------------
xpack.security.authc.realms.saml1:
type: saml
xpack.security.authc.realms.saml.saml1:
order: 2
idp.metadata.path: saml/idp-metadata.xml
idp.entity_id: "https://sso.example.com/"
@ -327,8 +324,7 @@ realm, as demonstrated in the realm configuration below:
[source, yaml]
------------------------------------------------------------
xpack.security.authc.realms.saml1:
type: saml
xpack.security.authc.realms.saml.saml1:
order: 2
idp.metadata.path: saml/idp-metadata.xml
idp.entity_id: "https://sso.example.com/"
@ -830,8 +826,7 @@ use the same internal IdP, and another which uses a different IdP.
[source, yaml]
------------------------------------------------------------
xpack.security.authc.realms.saml_finance:
type: saml
xpack.security.authc.realms.saml.saml_finance:
order: 2
idp.metadata.path: saml/idp-metadata.xml
idp.entity_id: "https://sso.example.com/"
@ -840,8 +835,7 @@ xpack.security.authc.realms.saml_finance:
sp.logout: "https://kibana.finance.example.com/logout"
attributes.principal: "urn:oid:0.9.2342.19200300.100.1.1"
attributes.groups: "urn:oid:1.3.6.1.4.1.5923.1.5.1."
xpack.security.authc.realms.saml_sales:
type: saml
xpack.security.authc.realms.saml.saml_sales:
order: 3
idp.metadata.path: saml/idp-metadata.xml
idp.entity_id: "https://sso.example.com/"
@ -850,8 +844,7 @@ xpack.security.authc.realms.saml_sales:
sp.logout: "https://kibana.sales.example.com/logout"
attributes.principal: "urn:oid:0.9.2342.19200300.100.1.1"
attributes.groups: "urn:oid:1.3.6.1.4.1.5923.1.5.1."
xpack.security.authc.realms.saml_eng:
type: saml
xpack.security.authc.realms.saml.saml_eng:
order: 4
idp.metadata.path: saml/idp-external.xml
idp.entity_id: "https://engineering.sso.example.net/"

View File

@ -7,12 +7,10 @@ package org.elasticsearch.xpack.core.security;
import org.apache.lucene.util.SPIClassIterator;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.core.security.authc.AuthenticationFailureHandler;
import org.elasticsearch.xpack.core.security.authc.Realm;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.core.security.authz.store.RoleRetrievalResult;
@ -42,16 +40,6 @@ public interface SecurityExtension {
return Collections.emptyMap();
}
/**
* Returns the set of {@link Setting settings} that may be configured for the each type of realm.
*
* Each <em>setting key</em> must be unqualified and is in the same format as will be provided via {@link RealmConfig#settings()}.
* If a given realm-type is not present in the returned map, then it will be treated as if it supported <em>all</em> possible settings.
*
* The life-cycle of an extension dictates that this method will be called before {@link #getRealms(ResourceWatcherService)}
*/
default Map<String, Set<Setting<?>>> getRealmSettings() { return Collections.emptyMap(); }
/**
* Returns a handler for authentication failures, or null to use the default handler.
*

View File

@ -13,26 +13,25 @@ import org.elasticsearch.xpack.core.security.authc.pki.PkiRealmSettings;
import org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.HashSet;
import java.util.Set;
public final class InternalRealmsSettings {
private InternalRealmsSettings() {}
private InternalRealmsSettings() {
}
/**
* Provides the {@link Setting setting configuration} for each <em>internal</em> realm type.
* This excludes the ReservedRealm, as it cannot be configured dynamically.
* @return A map from <em>realm-type</em> to a collection of <code>Setting</code> objects.
*/
public static Map<String, Set<Setting<?>>> getSettings() {
Map<String, Set<Setting<?>>> map = new HashMap<>();
map.put(FileRealmSettings.TYPE, FileRealmSettings.getSettings());
map.put(NativeRealmSettings.TYPE, NativeRealmSettings.getSettings());
map.put(LdapRealmSettings.AD_TYPE, LdapRealmSettings.getSettings(LdapRealmSettings.AD_TYPE));
map.put(LdapRealmSettings.LDAP_TYPE, LdapRealmSettings.getSettings(LdapRealmSettings.LDAP_TYPE));
map.put(PkiRealmSettings.TYPE, PkiRealmSettings.getSettings());
map.put(SamlRealmSettings.TYPE, SamlRealmSettings.getSettings());
return Collections.unmodifiableMap(map);
public static Set<Setting.AffixSetting<?>> getSettings() {
Set<Setting.AffixSetting<?>> set = new HashSet<>();
set.addAll(FileRealmSettings.getSettings());
set.addAll(NativeRealmSettings.getSettings());
set.addAll(LdapRealmSettings.getSettings(LdapRealmSettings.AD_TYPE));
set.addAll(LdapRealmSettings.getSettings(LdapRealmSettings.LDAP_TYPE));
set.addAll(PkiRealmSettings.getSettings());
set.addAll(SamlRealmSettings.getSettings());
return Collections.unmodifiableSet(set);
}
}

View File

@ -27,16 +27,10 @@ import java.util.Map;
public abstract class Realm implements Comparable<Realm> {
protected final Logger logger = LogManager.getLogger(getClass());
protected final String type;
public String getType() {
return type;
}
protected RealmConfig config;
public Realm(String type, RealmConfig config) {
this.type = type;
public Realm(RealmConfig config) {
this.config = config;
}
@ -44,14 +38,14 @@ public abstract class Realm implements Comparable<Realm> {
* @return The type of this realm
*/
public String type() {
return type;
return config.type();
}
/**
* @return The name of this realm.
*/
public String name() {
return config.name;
return config.name();
}
/**
@ -78,7 +72,7 @@ public abstract class Realm implements Comparable<Realm> {
int result = Integer.compare(config.order, other.config.order);
if (result == 0) {
// If same order, compare based on the realm name
result = config.name.compareTo(other.config.name);
result = config.name().compareTo(other.config.name());
}
return result;
}
@ -145,7 +139,7 @@ public abstract class Realm implements Comparable<Realm> {
@Override
public String toString() {
return type + "/" + config.name;
return config.type() + "/" + config.name();
}
/**

View File

@ -5,52 +5,58 @@
*/
package org.elasticsearch.xpack.core.security.authc;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
public class RealmConfig {
final String name;
final RealmIdentifier identifier;
final boolean enabled;
final int order;
private final String type;
final Settings settings;
private final Environment env;
private final Settings globalSettings;
private final ThreadContext threadContext;
public RealmConfig(String name, Settings settings, Settings globalSettings, Environment env,
@Deprecated
public RealmConfig(RealmIdentifier identifier, Settings settings, Settings globalSettings, Environment env,
ThreadContext threadContext) {
this.name = name;
this.settings = settings;
this(identifier, globalSettings, env, threadContext);
}
public RealmConfig(RealmIdentifier identifier, Settings globalSettings, Environment env,
ThreadContext threadContext) {
this.identifier = identifier;
this.globalSettings = globalSettings;
this.env = env;
enabled = RealmSettings.ENABLED_SETTING.get(settings);
order = RealmSettings.ORDER_SETTING.get(settings);
type = RealmSettings.TYPE_SETTING.get(settings);
enabled = getSetting(RealmSettings.ENABLED_SETTING);
order = getSetting(RealmSettings.ORDER_SETTING);
this.threadContext = threadContext;
}
public RealmIdentifier identifier() {
return identifier;
}
public String name() {
return name;
return identifier.name;
}
public boolean enabled() {
return enabled;
}
public int order() {
return order;
}
public String type() {
return type;
}
public Settings settings() {
return settings;
return identifier.type;
}
public Settings globalSettings() {
@ -64,4 +70,148 @@ public class RealmConfig {
public ThreadContext threadContext() {
return threadContext;
}
/**
* Return the {@link Setting.AffixSetting#getConcreteSettingForNamespace concrete setting}
* that is produced by applying this realm's name as the namespace.
* Realm configuration is defined using affix settings in the form {@code xpack.security.authc.realms.type.(name).key},
* where
* <ul>
* <li>{@code type} is a fixed string (known at compile time) that identifies the type of the realm being configured.</li>
* <li>{@code (name)} is a variable string (known only at runtime) that uniquely names the realm.</li>
* <li>{@code key} is a fixed string (known at compile time) that identifies a specific setting within the realm.</li>
* </ul>
* In order to extract an individual value from the runtime {@link Settings} object, it is necessary to convert an
* {@link Setting.AffixSetting} object into a concrete {@link Setting} object that has a fixed key, for a specific name.
*/
public <T> Setting<T> getConcreteSetting(Setting.AffixSetting<T> setting) {
return setting.getConcreteSettingForNamespace(name());
}
/**
* Return the {@link Setting.AffixSetting#getConcreteSettingForNamespace concrete setting} that is produced by applying this realm's
* type as a parameter to the provided function, and the realm's name (as the namespace) to the resulting {@link Setting.AffixSetting}.
* Because some settings (e.g. {@link RealmSettings#ORDER_SETTING "order"}) are defined for multiple "types", but the Settings
* infrastructure treats the type as a fixed part of the setting key, it is common to define such multi-realm settings using a
* {@link Function} of this form.
* @see #getConcreteSetting(Setting.AffixSetting)
*/
public <T> Setting<T> getConcreteSetting(Function<String, Setting.AffixSetting<T>> settingFactory) {
return getConcreteSetting(settingFactory.apply(type()));
}
/**
* Obtain the value of the provided {@code setting} from the node's {@link #globalSettings global settings}.
* The {@link Setting.AffixSetting} is made <em>concrete</em> through {@link #getConcreteSetting(Setting.AffixSetting)}, which is then
* used to {@link Setting#get(Settings) retrieve} the setting value.
*/
public <T> T getSetting(Setting.AffixSetting<T> setting) {
return getConcreteSetting(setting).get(globalSettings);
}
/**
* Obtain the value of the provided {@code setting} from the node's {@link #globalSettings global settings}.
* {@link #getConcreteSetting(Function)} is used to obtain a <em>concrete setting</em> from the provided
* {@link Function}/{@link Setting.AffixSetting}, and this <em>concrete setting</em> is then used to
* {@link Setting#get(Settings) retrieve} the setting value.
*/
public <T> T getSetting(Function<String, Setting.AffixSetting<T>> settingFactory) {
return getSetting(settingFactory.apply(type()));
}
/**
* Obtain the value of the provided {@code setting} from the node's {@link #globalSettings global settings}.
* {@link #getConcreteSetting(Function)} is used to obtain a <em>concrete setting</em> from the provided
* {@link Function}/{@link Setting.AffixSetting}.
* If this <em>concrete setting</em> {@link Setting#exists(Settings) exists} in the global settings, then its value is returned,
* otherwise the {@code onElse} {@link Supplier} is executed and returned.
*/
public <T> T getSetting(Function<String, Setting.AffixSetting<T>> settingFactory, Supplier<T> orElse) {
return getSetting(settingFactory.apply(type()), orElse);
}
/**
* Obtain the value of the provided {@code setting} from the node's {@link #globalSettings global settings}.
* {@link #getConcreteSetting(Setting.AffixSetting)} is used to obtain a <em>concrete setting</em> from the provided
* {@link Setting.AffixSetting}.
* If this <em>concrete setting</em> {@link Setting#exists(Settings) exists} in the global settings, then its value is returned,
* otherwise the {@code onElse} {@link Supplier} is executed and returned.
*/
public <T> T getSetting(Setting.AffixSetting<T> setting, Supplier<T> orElse) {
final Setting<T> concrete = setting.getConcreteSettingForNamespace(name());
if (concrete.exists(globalSettings)) {
return concrete.get(globalSettings);
} else {
return orElse.get();
}
}
/**
* Determines whether the provided {@code setting} has an explicit value in the node's {@link #globalSettings global settings}.
* {@link #getConcreteSetting(Function)} is used to obtain a <em>concrete setting</em> from the provided
* {@link Function}/{@link Setting.AffixSetting}, and this <em>concrete setting</em> is then used to
* {@link Setting#exists(Settings) check} for a value.
*/
public <T> boolean hasSetting(Function<String, Setting.AffixSetting<T>> settingFactory) {
return getConcreteSetting(settingFactory).exists(globalSettings);
}
/**
* Determines whether the provided {@code setting} has an explicit value in the node's {@link #globalSettings global settings}.
* {@link #getConcreteSetting(Setting.AffixSetting)} is used to obtain a <em>concrete setting</em> from the provided
* {@link Setting.AffixSetting}, and this <em>concrete setting</em> is then used to {@link Setting#exists(Settings) check} for a value.
*/
public <T> boolean hasSetting(Setting.AffixSetting<T> setting) {
return getConcreteSetting(setting).exists(globalSettings);
}
/**
* A realm identifier consists of a realm's {@link RealmConfig#type() type} and {@link RealmConfig#name() name}.
* Because realms are configured using a key that contains both of these parts
* (e.g. {@code xpack.security.authc.realms.native.native_realm.order}), it is often necessary to be able to
* pass this pair of variables as a single type (e.g. in method parameters, or return values).
*/
public static class RealmIdentifier {
private final String type;
private final String name;
public RealmIdentifier(String type, String name) {
this.type = Objects.requireNonNull(type, "Realm type cannot be null");
this.name = Objects.requireNonNull(name, "Realm name cannot be null");
}
public String getType() {
return type;
}
public String getName() {
return name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (getClass() != o.getClass()) {
return false;
}
final RealmIdentifier other = (RealmIdentifier) o;
return Objects.equals(this.type, other.type) &&
Objects.equals(this.name, other.name);
}
@Override
public int hashCode() {
return Objects.hash(type, name);
}
@Override
public String toString() {
return type + '/' + name;
}
}
}

View File

@ -5,193 +5,106 @@
*/
package org.elasticsearch.xpack.core.security.authc;
import org.elasticsearch.common.settings.AbstractScopedSettings;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.core.security.SecurityExtension;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.elasticsearch.common.Strings.isNullOrEmpty;
import static org.elasticsearch.xpack.core.security.SecurityField.setting;
/**
* Configures the {@link Setting#groupSetting(String, Consumer, Setting.Property...) group setting} for security
* {@link Realm realms}, with validation according to the realm type.
* <p>
* The allowable settings for a given realm are dependent on the {@link Realm#type() realm type}, so it is not possible
* to simply provide a list of {@link Setting} objects and rely on the global setting vacomlidation (e.g. A custom realm-type might
* define a setting with the same logical key as an internal realm-type, but a different data type).
* </p> <p>
* Instead, realm configuration relies on the <code>validator</code> parameter to
* {@link Setting#groupSetting(String, Consumer, Setting.Property...)} in order to validate each realm in a way that respects the
* declared <code>type</code>.
* Internally, this validation delegates to {@link AbstractScopedSettings#validate(Settings, boolean)} so that validation is reasonably
* aligned
* with the way we validate settings globally.
* </p>
* <p>
* The allowable settings for each realm-type are determined by calls to {@link InternalRealmsSettings#getSettings()} and
* {@link org.elasticsearch.xpack.core.security.SecurityExtension#getRealmSettings()}
* Provides a number of utility methods for interacting with {@link Settings} and {@link Setting} inside a {@link Realm}.
* Settings for realms use an {@link Setting#affixKeySetting(String, String, Function, Setting.AffixSetting[]) affix} style,
* where the <em>type</em> of the realm is part of the prefix, and name of the realm is the variable portion
* (That is to set the order in a file realm named "file1", then full setting key would be
* {@code xpack.security.authc.realms.file.file1.order}.
* This class provides some convenience methods for defining and retrieving such settings.
*/
public class RealmSettings {
public static final String PREFIX = setting("authc.realms.");
public static final String PREFIX = "xpack.security.authc.realms.";
static final Setting<String> TYPE_SETTING = Setting.simpleString("type", Setting.Property.NodeScope);
static final Setting<Boolean> ENABLED_SETTING = Setting.boolSetting("enabled", true, Setting.Property.NodeScope);
static final Setting<Integer> ORDER_SETTING = Setting.intSetting("order", Integer.MAX_VALUE, Setting.Property.NodeScope);
public static final Function<String, Setting.AffixSetting<Boolean>> ENABLED_SETTING = affixSetting("enabled",
key -> Setting.boolSetting(key, true, Setting.Property.NodeScope));
public static final Function<String, Setting.AffixSetting<Integer>> ORDER_SETTING = affixSetting("order",
key -> Setting.intSetting(key, Integer.MAX_VALUE, Setting.Property.NodeScope));
/**
* Add the {@link Setting} configuration for <em>all</em> realms to the provided list.
*/
public static void addSettings(List<Setting<?>> settingsList, List<SecurityExtension> extensions) {
settingsList.add(getGroupSetting(extensions));
public static String realmSettingPrefix(String type) {
return PREFIX + type + ".";
}
public static Collection<String> getSettingsFilter(List<SecurityExtension> extensions) {
return getSettingsByRealm(extensions).values().stream()
.flatMap(Collection::stream)
.filter(Setting::isFiltered)
.map(setting -> PREFIX + "*." + setting.getKey())
.collect(Collectors.toSet());
public static String realmSettingPrefix(RealmConfig.RealmIdentifier identifier) {
return realmSettingPrefix(identifier.getType()) + identifier.getName() + ".";
}
public static String realmSslPrefix(RealmConfig.RealmIdentifier identifier) {
return realmSettingPrefix(identifier) + "ssl.";
}
/**
* Extract the child {@link Settings} for the {@link #PREFIX realms prefix}.
* The top level names in the returned <code>Settings</code> will be the names of the configured realms.
* Create a {@link Setting#simpleString(String, Setting.Property...) simple string} {@link Setting} object for a realm of
* with the provided type and setting suffix.
* @param realmType The type of the realm, used within the setting prefix
* @param suffix The suffix of the setting (everything following the realm name in the affix setting)
* @param properties And properties to apply to the setting
*/
public static Settings get(Settings settings) {
return settings.getByPrefix(RealmSettings.PREFIX);
public static Setting.AffixSetting<String> simpleString(String realmType, String suffix, Setting.Property... properties) {
return Setting.affixKeySetting(realmSettingPrefix(realmType), suffix, key -> Setting.simpleString(key, properties));
}
/**
* Create a {@link Function} that acts as a factory an {@link org.elasticsearch.common.settings.Setting.AffixSetting}.
* The {@code Function} takes the <em>realm-type</em> as an argument.
* @param suffix The suffix of the setting (everything following the realm name in the affix setting)
* @param delegateFactory A factory to produce the concrete setting.
* See {@link Setting#affixKeySetting(Setting.AffixKey, Function, Setting.AffixSetting[])}
*/
public static <T> Function<String, Setting.AffixSetting<T>> affixSetting(String suffix, Function<String, Setting<T>> delegateFactory) {
return realmType -> Setting.affixKeySetting(realmSettingPrefix(realmType), suffix, delegateFactory);
}
/**
* Extracts the realm settings from a global settings object.
* Returns a Map of realm-name to realm-settings.
* Returns a Map of realm-id to realm-settings.
*/
public static Map<String, Settings> getRealmSettings(Settings globalSettings) {
Settings realmsSettings = RealmSettings.get(globalSettings);
return realmsSettings.names().stream()
.collect(Collectors.toMap(Function.identity(), realmsSettings::getAsSettings));
public static Map<RealmConfig.RealmIdentifier, Settings> getRealmSettings(Settings globalSettings) {
Settings settingsByType = globalSettings.getByPrefix(RealmSettings.PREFIX);
return settingsByType.names().stream()
.flatMap(type -> {
final Settings settingsByName = settingsByType.getAsSettings(type);
return settingsByName.names().stream().map(name -> {
final RealmConfig.RealmIdentifier id = new RealmConfig.RealmIdentifier(type, name);
final Settings realmSettings = settingsByName.getAsSettings(name);
return new Tuple<>(id, realmSettings);
});
})
.collect(Collectors.toMap(Tuple::v1, Tuple::v2));
}
/**
* Convert the child {@link Setting} for the provided realm into a fully scoped key for use in an error message.
* @see #PREFIX
*/
public static String getFullSettingKey(RealmConfig realm, Setting<?> setting) {
return getFullSettingKey(realm.name(), setting);
public static String getFullSettingKey(String realmName, Setting.AffixSetting<?> setting) {
return setting.getConcreteSettingForNamespace(realmName).getKey();
}
/**
* @see #getFullSettingKey(RealmConfig, Setting)
*/
public static String getFullSettingKey(RealmConfig realm, String subKey) {
return getFullSettingKey(realm.name(), subKey);
public static String getFullSettingKey(RealmConfig realm, Setting.AffixSetting<?> setting) {
return setting.getConcreteSettingForNamespace(realm.name()).getKey();
}
private static String getFullSettingKey(String name, Setting<?> setting) {
return getFullSettingKey(name, setting.getKey());
public static <T> String getFullSettingKey(RealmConfig.RealmIdentifier realmId, Function<String, Setting.AffixSetting<T>> setting) {
return getFullSettingKey(realmId.getName(), setting.apply(realmId.getType()));
}
private static String getFullSettingKey(String name, String subKey) {
return PREFIX + name + "." + subKey;
public static <T> String getFullSettingKey(RealmConfig realm, Function<String, Setting.AffixSetting<T>> setting) {
return getFullSettingKey(realm.identifier, setting);
}
private static Setting<Settings> getGroupSetting(List<SecurityExtension> extensions) {
return Setting.groupSetting(PREFIX, getSettingsValidator(extensions), Setting.Property.NodeScope);
}
private static Consumer<Settings> getSettingsValidator(List<SecurityExtension> extensions) {
final Map<String, Set<Setting<?>>> childSettings = getSettingsByRealm(extensions);
childSettings.forEach(RealmSettings::verify);
return validator(childSettings);
}
/**
* @return A map from <em>realm-type</em> to a collection of <code>Setting</code> objects.
* @see InternalRealmsSettings#getSettings()
*/
private static Map<String, Set<Setting<?>>> getSettingsByRealm(List<SecurityExtension> extensions) {
final Map<String, Set<Setting<?>>> settingsByRealm = new HashMap<>(InternalRealmsSettings.getSettings());
if (extensions != null) {
extensions.forEach(ext -> {
final Map<String, Set<Setting<?>>> extSettings = ext.getRealmSettings();
extSettings.keySet().stream().filter(settingsByRealm::containsKey).forEach(type -> {
throw new IllegalArgumentException("duplicate realm type " + type);
});
settingsByRealm.putAll(extSettings);
});
}
return settingsByRealm;
}
private static void verify(String type, Set<Setting<?>> settings) {
Set<String> keys = new HashSet<>();
settings.forEach(setting -> {
final String key = setting.getKey();
if (keys.contains(key)) {
throw new IllegalArgumentException("duplicate setting for key " + key + " in realm type " + type);
}
keys.add(key);
if (setting.getProperties().contains(Setting.Property.NodeScope) == false) {
throw new IllegalArgumentException("setting " + key + " in realm type " + type + " does not have NodeScope");
}
});
}
private static Consumer<Settings> validator(Map<String, Set<Setting<?>>> validSettings) {
return (settings) -> settings.names().forEach(n -> validateRealm(n, settings.getAsSettings(n), validSettings));
}
private static void validateRealm(String name, Settings settings, Map<String, Set<Setting<?>>> validSettings) {
final String type = getRealmType(settings);
if (isNullOrEmpty(type)) {
throw new IllegalArgumentException("missing realm type [" + getFullSettingKey(name, TYPE_SETTING) + "] for realm");
}
validateRealm(name, type, settings, validSettings.get(type));
}
public static String getRealmType(Settings settings) {
return TYPE_SETTING.get(settings);
}
private static void validateRealm(String name, String type, Settings settings, Set<Setting<?>> validSettings) {
if (validSettings == null) {
// For backwards compatibility, we assume that is we don't know the valid settings for a realm.type then everything
// is valid. Ideally we would reject these, but XPackExtension doesn't enforce that realm-factories and realm-settings are
// perfectly aligned
return;
}
// Don't validate secure settings because they might have been cleared already
settings = Settings.builder().put(settings, false).build();
validSettings.removeIf(s -> s instanceof SecureSetting);
Set<Setting<?>> settingSet = new HashSet<>(validSettings);
settingSet.add(TYPE_SETTING);
settingSet.add(ENABLED_SETTING);
settingSet.add(ORDER_SETTING);
final AbstractScopedSettings validator =
new AbstractScopedSettings(settings, settingSet, Collections.emptySet(), Setting.Property.NodeScope) { };
try {
validator.validate(settings, false);
} catch (RuntimeException e) {
throw new IllegalArgumentException("incorrect configuration for realm [" + getFullSettingKey(name, "")
+ "] of type " + type, e);
}
public static List<Setting.AffixSetting<?>> getStandardSettings(String realmType) {
return Arrays.asList(ENABLED_SETTING.apply(realmType), ORDER_SETTING.apply(realmType));
}
private RealmSettings() {
}
}

View File

@ -6,8 +6,10 @@
package org.elasticsearch.xpack.core.security.authc.esnative;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.CachingUsernamePasswordRealmSettings;
import java.util.HashSet;
import java.util.Set;
public final class NativeRealmSettings {
@ -18,7 +20,9 @@ public final class NativeRealmSettings {
/**
* @return The {@link Setting setting configuration} for this realm type
*/
public static Set<Setting<?>> getSettings() {
return CachingUsernamePasswordRealmSettings.getSettings();
public static Set<Setting.AffixSetting<?>> getSettings() {
final Set<Setting.AffixSetting<?>> set = new HashSet<>(CachingUsernamePasswordRealmSettings.getSettings(TYPE));
set.addAll(RealmSettings.getStandardSettings(TYPE));
return set;
}
}

View File

@ -6,8 +6,10 @@
package org.elasticsearch.xpack.core.security.authc.file;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.CachingUsernamePasswordRealmSettings;
import java.util.HashSet;
import java.util.Set;
public final class FileRealmSettings {
@ -18,7 +20,9 @@ public final class FileRealmSettings {
/**
* @return The {@link Setting setting configuration} for this realm type
*/
public static Set<Setting<?>> getSettings() {
return CachingUsernamePasswordRealmSettings.getSettings();
public static Set<Setting.AffixSetting<?>> getSettings() {
final Set<Setting.AffixSetting<?>> set = new HashSet<>(CachingUsernamePasswordRealmSettings.getSettings(TYPE));
set.addAll(RealmSettings.getStandardSettings(TYPE));
return set;
}
}

View File

@ -10,6 +10,7 @@ import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.DelegatedAuthorizationSettings;
import java.util.Set;
@ -24,19 +25,23 @@ public final class KerberosRealmSettings {
* Kerberos key tab for Elasticsearch service<br>
* Uses single key tab for multiple service accounts.
*/
public static final Setting<String> HTTP_SERVICE_KEYTAB_PATH =
Setting.simpleString("keytab.path", Property.NodeScope);
public static final Setting<Boolean> SETTING_KRB_DEBUG_ENABLE =
Setting.boolSetting("krb.debug", Boolean.FALSE, Property.NodeScope);
public static final Setting<Boolean> SETTING_REMOVE_REALM_NAME =
Setting.boolSetting("remove_realm_name", Boolean.FALSE, Property.NodeScope);
public static final Setting.AffixSetting<String> HTTP_SERVICE_KEYTAB_PATH = RealmSettings.simpleString(TYPE,
"keytab.path", Property.NodeScope);
public static final Setting.AffixSetting<Boolean> SETTING_KRB_DEBUG_ENABLE = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "krb.debug", key -> Setting.boolSetting(key, Boolean.FALSE, Property.NodeScope));
public static final Setting.AffixSetting<Boolean> SETTING_REMOVE_REALM_NAME = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "remove_realm_name", key -> Setting.boolSetting(key, Boolean.FALSE, Property.NodeScope));
// Cache
private static final TimeValue DEFAULT_TTL = TimeValue.timeValueMinutes(20);
private static final int DEFAULT_MAX_USERS = 100_000; // 100k users
public static final Setting<TimeValue> CACHE_TTL_SETTING = Setting.timeSetting("cache.ttl", DEFAULT_TTL, Setting.Property.NodeScope);
public static final Setting<Integer> CACHE_MAX_USERS_SETTING =
Setting.intSetting("cache.max_users", DEFAULT_MAX_USERS, Property.NodeScope);
public static final Setting.AffixSetting<TimeValue> CACHE_TTL_SETTING = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "cache.ttl", key -> Setting.timeSetting(key, DEFAULT_TTL, Setting.Property.NodeScope));
public static final Setting.AffixSetting<Integer> CACHE_MAX_USERS_SETTING = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "cache.max_users", key -> Setting.intSetting(key, DEFAULT_MAX_USERS, Property.NodeScope));
private KerberosRealmSettings() {
}
@ -44,10 +49,10 @@ public final class KerberosRealmSettings {
/**
* @return the valid set of {@link Setting}s for a {@value #TYPE} realm
*/
public static Set<Setting<?>> getSettings() {
final Set<Setting<?>> settings = Sets.newHashSet(HTTP_SERVICE_KEYTAB_PATH, CACHE_TTL_SETTING, CACHE_MAX_USERS_SETTING,
public static Set<Setting.AffixSetting<?>> getSettings() {
final Set<Setting.AffixSetting<?>> settings = Sets.newHashSet(HTTP_SERVICE_KEYTAB_PATH, CACHE_TTL_SETTING, CACHE_MAX_USERS_SETTING,
SETTING_KRB_DEBUG_ENABLE, SETTING_REMOVE_REALM_NAME);
settings.addAll(DelegatedAuthorizationSettings.getSettings());
settings.addAll(DelegatedAuthorizationSettings.getSettings(TYPE));
return settings;
}
}

View File

@ -6,46 +6,85 @@
package org.elasticsearch.xpack.core.security.authc.ldap;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
import java.util.HashSet;
import java.util.Set;
import static org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings.AD_TYPE;
public final class ActiveDirectorySessionFactorySettings {
public static final String AD_DOMAIN_NAME_SETTING = "domain_name";
private static final String AD_DOMAIN_NAME_SETTING_KEY = "domain_name";
public static final Setting.AffixSetting<String> AD_DOMAIN_NAME_SETTING
= RealmSettings.simpleString(AD_TYPE, AD_DOMAIN_NAME_SETTING_KEY, Setting.Property.NodeScope);
public static final String AD_GROUP_SEARCH_BASEDN_SETTING = "group_search.base_dn";
public static final String AD_GROUP_SEARCH_SCOPE_SETTING = "group_search.scope";
public static final String AD_USER_SEARCH_BASEDN_SETTING = "user_search.base_dn";
public static final String AD_USER_SEARCH_FILTER_SETTING = "user_search.filter";
public static final String AD_UPN_USER_SEARCH_FILTER_SETTING = "user_search.upn_filter";
public static final String AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING = "user_search.down_level_filter";
public static final String AD_USER_SEARCH_SCOPE_SETTING = "user_search.scope";
public static final Setting<Integer> AD_LDAP_PORT_SETTING = Setting.intSetting("port.ldap", 389, Setting.Property.NodeScope);
public static final Setting<Integer> AD_LDAPS_PORT_SETTING = Setting.intSetting("port.ldaps", 636, Setting.Property.NodeScope);
public static final Setting<Integer> AD_GC_LDAP_PORT_SETTING = Setting.intSetting("port.gc_ldap", 3268, Setting.Property.NodeScope);
public static final Setting<Integer> AD_GC_LDAPS_PORT_SETTING = Setting.intSetting("port.gc_ldaps", 3269, Setting.Property.NodeScope);
public static final Setting<Boolean> POOL_ENABLED = Setting.boolSetting("user_search.pool.enabled",
settings -> Boolean.toString(PoolingSessionFactorySettings.BIND_DN.exists(settings)), Setting.Property.NodeScope);
private ActiveDirectorySessionFactorySettings() {}
private static final String AD_USER_SEARCH_BASEDN_SETTING_KEY = "user_search.base_dn";
public static final Setting.AffixSetting<String> AD_USER_SEARCH_BASEDN_SETTING
= RealmSettings.simpleString(AD_TYPE, AD_USER_SEARCH_BASEDN_SETTING_KEY, Setting.Property.NodeScope);
public static Set<Setting<?>> getSettings() {
Set<Setting<?>> settings = new HashSet<>();
settings.addAll(SessionFactorySettings.getSettings());
settings.add(Setting.simpleString(AD_DOMAIN_NAME_SETTING, Setting.Property.NodeScope));
settings.add(Setting.simpleString(AD_GROUP_SEARCH_BASEDN_SETTING, Setting.Property.NodeScope));
settings.add(Setting.simpleString(AD_GROUP_SEARCH_SCOPE_SETTING, Setting.Property.NodeScope));
settings.add(Setting.simpleString(AD_USER_SEARCH_BASEDN_SETTING, Setting.Property.NodeScope));
settings.add(Setting.simpleString(AD_USER_SEARCH_FILTER_SETTING, Setting.Property.NodeScope));
settings.add(Setting.simpleString(AD_UPN_USER_SEARCH_FILTER_SETTING, Setting.Property.NodeScope));
settings.add(Setting.simpleString(AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING, Setting.Property.NodeScope));
settings.add(Setting.simpleString(AD_USER_SEARCH_SCOPE_SETTING, Setting.Property.NodeScope));
private static final String AD_USER_SEARCH_FILTER_SETTING_KEY = "user_search.filter";
public static final Setting.AffixSetting<String> AD_USER_SEARCH_FILTER_SETTING
= RealmSettings.simpleString(AD_TYPE, AD_USER_SEARCH_FILTER_SETTING_KEY, Setting.Property.NodeScope);
private static final String AD_UPN_USER_SEARCH_FILTER_SETTING_KEY = "user_search.upn_filter";
public static final Setting.AffixSetting<String> AD_UPN_USER_SEARCH_FILTER_SETTING
= RealmSettings.simpleString(AD_TYPE, AD_UPN_USER_SEARCH_FILTER_SETTING_KEY, Setting.Property.NodeScope);
private static final String AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING_KEY = "user_search.down_level_filter";
public static final Setting.AffixSetting<String> AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING
= RealmSettings.simpleString(AD_TYPE, AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING_KEY, Setting.Property.NodeScope);
private static final String AD_USER_SEARCH_SCOPE_SETTING_KEY = "user_search.scope";
public static final Setting.AffixSetting<String> AD_USER_SEARCH_SCOPE_SETTING
= RealmSettings.simpleString(AD_TYPE, AD_USER_SEARCH_SCOPE_SETTING_KEY, Setting.Property.NodeScope);
public static final Setting.AffixSetting<Integer> AD_LDAP_PORT_SETTING = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(AD_TYPE), "port.ldap", key -> Setting.intSetting(key, 389, Setting.Property.NodeScope));
public static final Setting.AffixSetting<Integer> AD_LDAPS_PORT_SETTING = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(AD_TYPE), "port.ldaps", key -> Setting.intSetting(key, 636, Setting.Property.NodeScope));
public static final Setting.AffixSetting<Integer> AD_GC_LDAP_PORT_SETTING = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(AD_TYPE), "port.gc_ldap", key -> Setting.intSetting(key, 3268, Setting.Property.NodeScope));
public static final Setting.AffixSetting<Integer> AD_GC_LDAPS_PORT_SETTING = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(AD_TYPE), "port.gc_ldaps", key -> Setting.intSetting(key, 3269, Setting.Property.NodeScope));
public static final String POOL_ENABLED_SUFFIX = "user_search.pool.enabled";
public static final Setting.AffixSetting<Boolean> POOL_ENABLED = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(AD_TYPE), POOL_ENABLED_SUFFIX,
key -> {
if (key.endsWith(POOL_ENABLED_SUFFIX)) {
final String bindDnKey = key.substring(0, key.length() - POOL_ENABLED_SUFFIX.length())
+ PoolingSessionFactorySettings.BIND_DN_SUFFIX;
return Setting.boolSetting(key, settings -> Boolean.toString(settings.keySet().contains(bindDnKey)),
Setting.Property.NodeScope);
} else {
return Setting.boolSetting(key, false, Setting.Property.NodeScope);
}
});
private ActiveDirectorySessionFactorySettings() {
}
public static Set<Setting.AffixSetting<?>> getSettings() {
Set<Setting.AffixSetting<?>> settings = new HashSet<>();
settings.addAll(SessionFactorySettings.getSettings(AD_TYPE));
settings.add(AD_DOMAIN_NAME_SETTING);
settings.add(RealmSettings.simpleString(AD_TYPE, AD_GROUP_SEARCH_BASEDN_SETTING, Setting.Property.NodeScope));
settings.add(RealmSettings.simpleString(AD_TYPE, AD_GROUP_SEARCH_SCOPE_SETTING, Setting.Property.NodeScope));
settings.add(AD_USER_SEARCH_BASEDN_SETTING);
settings.add(AD_USER_SEARCH_FILTER_SETTING);
settings.add(AD_UPN_USER_SEARCH_FILTER_SETTING);
settings.add(AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING);
settings.add(AD_USER_SEARCH_SCOPE_SETTING);
settings.add(AD_LDAP_PORT_SETTING);
settings.add(AD_LDAPS_PORT_SETTING);
settings.add(AD_GC_LDAP_PORT_SETTING);
settings.add(AD_GC_LDAPS_PORT_SETTING);
settings.add(POOL_ENABLED);
settings.addAll(PoolingSessionFactorySettings.getSettings());
settings.addAll(PoolingSessionFactorySettings.getSettings(AD_TYPE));
return settings;
}
}

View File

@ -7,6 +7,7 @@ package org.elasticsearch.xpack.core.security.authc.ldap;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapMetaDataResolverSettings;
import org.elasticsearch.xpack.core.security.authc.support.CachingUsernamePasswordRealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.DelegatedAuthorizationSettings;
@ -14,33 +15,39 @@ import org.elasticsearch.xpack.core.security.authc.support.mapper.CompositeRoleM
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
public final class LdapRealmSettings {
public static final String LDAP_TYPE = "ldap";
public static final String AD_TYPE = "active_directory";
public static final Setting<TimeValue> EXECUTION_TIMEOUT =
Setting.timeSetting("timeout.execution", TimeValue.timeValueSeconds(30L), Setting.Property.NodeScope);
private LdapRealmSettings() {}
public static final String TIMEOUT_EXECUTION_SUFFIX = "timeout.execution";
public static final Function<String, Setting.AffixSetting<TimeValue>> EXECUTION_TIMEOUT = type ->
Setting.affixKeySetting(RealmSettings.realmSettingPrefix(type), TIMEOUT_EXECUTION_SUFFIX,
key -> Setting.timeSetting(key, TimeValue.timeValueSeconds(30L), Setting.Property.NodeScope));
private LdapRealmSettings() {
}
/**
* @param type Either {@link #AD_TYPE} or {@link #LDAP_TYPE}
* @return The {@link Setting setting configuration} for this realm type
*/
public static Set<Setting<?>> getSettings(String type) {
Set<Setting<?>> settings = new HashSet<>();
settings.addAll(CachingUsernamePasswordRealmSettings.getSettings());
settings.addAll(CompositeRoleMapperSettings.getSettings());
settings.add(LdapRealmSettings.EXECUTION_TIMEOUT);
public static Set<Setting.AffixSetting<?>> getSettings(String type) {
Set<Setting.AffixSetting<?>> settings = new HashSet<>();
settings.addAll(CachingUsernamePasswordRealmSettings.getSettings(type));
settings.addAll(CompositeRoleMapperSettings.getSettings(type));
settings.add(LdapRealmSettings.EXECUTION_TIMEOUT.apply(type));
if (AD_TYPE.equals(type)) {
settings.addAll(ActiveDirectorySessionFactorySettings.getSettings());
} else {
assert LDAP_TYPE.equals(type) : "type [" + type + "] is unknown. expected one of [" + AD_TYPE + ", " + LDAP_TYPE + "]";
settings.addAll(LdapSessionFactorySettings.getSettings());
settings.addAll(LdapUserSearchSessionFactorySettings.getSettings());
settings.addAll(DelegatedAuthorizationSettings.getSettings());
settings.addAll(DelegatedAuthorizationSettings.getSettings(type));
}
settings.addAll(LdapMetaDataResolverSettings.getSettings());
settings.addAll(RealmSettings.getStandardSettings(type));
return settings;
}
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.core.security.authc.ldap;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
import java.util.Collections;
@ -14,14 +15,17 @@ import java.util.List;
import java.util.Set;
import java.util.function.Function;
import static org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings.LDAP_TYPE;
public final class LdapSessionFactorySettings {
public static final Setting<List<String>> USER_DN_TEMPLATES_SETTING = Setting.listSetting("user_dn_templates",
Collections.emptyList(), Function.identity(), Setting.Property.NodeScope);
public static final Setting.AffixSetting<List<String>> USER_DN_TEMPLATES_SETTING = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(LDAP_TYPE), "user_dn_templates",
key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(), Setting.Property.NodeScope));
public static Set<Setting<?>> getSettings() {
Set<Setting<?>> settings = new HashSet<>();
settings.addAll(SessionFactorySettings.getSettings());
public static Set<Setting.AffixSetting<?>> getSettings() {
Set<Setting.AffixSetting<?>> settings = new HashSet<>();
settings.addAll(SessionFactorySettings.getSettings(LDAP_TYPE));
settings.add(USER_DN_TEMPLATES_SETTING);
return settings;
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.core.security.authc.ldap;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
@ -13,30 +14,43 @@ import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import static org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings.LDAP_TYPE;
public final class LdapUserSearchSessionFactorySettings {
public static final Setting<String> SEARCH_ATTRIBUTE = new Setting<>("user_search.attribute",
LdapUserSearchSessionFactorySettings.DEFAULT_USERNAME_ATTRIBUTE,
Function.identity(), Setting.Property.NodeScope, Setting.Property.Deprecated);
public static final Setting<String> SEARCH_BASE_DN = Setting.simpleString("user_search.base_dn", Setting.Property.NodeScope);
public static final Setting<String> SEARCH_FILTER = Setting.simpleString("user_search.filter", Setting.Property.NodeScope);
public static final Setting<LdapSearchScope> SEARCH_SCOPE = new Setting<>("user_search.scope", (String) null,
s -> LdapSearchScope.resolve(s, LdapSearchScope.SUB_TREE), Setting.Property.NodeScope);
public static final Setting<Boolean> POOL_ENABLED = Setting.boolSetting("user_search.pool.enabled", true, Setting.Property.NodeScope);
public static final Setting.AffixSetting<String> SEARCH_ATTRIBUTE = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(LDAP_TYPE), "user_search.attribute",
key -> new Setting<>(key, LdapUserSearchSessionFactorySettings.DEFAULT_USERNAME_ATTRIBUTE, Function.identity(),
Setting.Property.NodeScope, Setting.Property.Deprecated));
public static final Setting.AffixSetting<String> SEARCH_BASE_DN
= RealmSettings.simpleString(LDAP_TYPE, "user_search.base_dn", Setting.Property.NodeScope);
public static final Setting.AffixSetting<String> SEARCH_FILTER
= RealmSettings.simpleString(LDAP_TYPE, "user_search.filter", Setting.Property.NodeScope);
public static final Setting.AffixSetting<LdapSearchScope> SEARCH_SCOPE = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(LDAP_TYPE), "user_search.scope",
key -> new Setting<>(key, (String) null, (String s) -> LdapSearchScope.resolve(s, LdapSearchScope.SUB_TREE),
Setting.Property.NodeScope));
public static final Setting.AffixSetting<Boolean> POOL_ENABLED = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(LDAP_TYPE), "user_search.pool.enabled",
key -> Setting.boolSetting(key, true, Setting.Property.NodeScope));
private static final String DEFAULT_USERNAME_ATTRIBUTE = "uid";
private LdapUserSearchSessionFactorySettings() {}
private LdapUserSearchSessionFactorySettings() {
}
public static Set<Setting<?>> getSettings() {
Set<Setting<?>> settings = new HashSet<>();
settings.addAll(SessionFactorySettings.getSettings());
settings.addAll(PoolingSessionFactorySettings.getSettings());
public static Set<Setting.AffixSetting<?>> getSettings() {
Set<Setting.AffixSetting<?>> settings = new HashSet<>();
settings.addAll(SessionFactorySettings.getSettings(LDAP_TYPE));
settings.addAll(PoolingSessionFactorySettings.getSettings(LDAP_TYPE));
settings.add(SEARCH_BASE_DN);
settings.add(SEARCH_SCOPE);
settings.add(SEARCH_ATTRIBUTE);
settings.add(POOL_ENABLED);
settings.add(SEARCH_FILTER);
settings.addAll(SearchGroupsResolverSettings.getSettings());
settings.addAll(SearchGroupsResolverSettings.getSettings(LDAP_TYPE));
settings.addAll(UserAttributeGroupsResolverSettings.getSettings());
return settings;

View File

@ -8,37 +8,62 @@ package org.elasticsearch.xpack.core.security.authc.ldap;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.elasticsearch.common.settings.SecureSetting.secureString;
public final class PoolingSessionFactorySettings {
public static final TimeValue DEFAULT_HEALTH_CHECK_INTERVAL = TimeValue.timeValueSeconds(60L);
public static final Setting<String> BIND_DN = Setting.simpleString("bind_dn", Setting.Property.NodeScope, Setting.Property.Filtered);
public static final Setting<SecureString> LEGACY_BIND_PASSWORD = new Setting<>("bind_password", "", SecureString::new,
Setting.Property.NodeScope, Setting.Property.Filtered, Setting.Property.Deprecated);
public static final Setting<SecureString> SECURE_BIND_PASSWORD = secureString("secure_bind_password", LEGACY_BIND_PASSWORD);
public static final String BIND_DN_SUFFIX = "bind_dn";
public static final Function<String, Setting.AffixSetting<String>> BIND_DN = RealmSettings.affixSetting(BIND_DN_SUFFIX,
key -> Setting.simpleString(key, Setting.Property.NodeScope, Setting.Property.Filtered));
public static final Function<String, Setting.AffixSetting<SecureString>> LEGACY_BIND_PASSWORD = RealmSettings.affixSetting(
"bind_password", key -> new Setting<>(key, "", SecureString::new,
Setting.Property.NodeScope, Setting.Property.Filtered, Setting.Property.Deprecated));
public static final Function<String, Setting.AffixSetting<SecureString>> SECURE_BIND_PASSWORD = realmType ->
Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(realmType), "secure_bind_password",
key -> secureString(key, null)
);
public static final int DEFAULT_CONNECTION_POOL_INITIAL_SIZE = 0;
public static final Setting<Integer> POOL_INITIAL_SIZE = Setting.intSetting("user_search.pool.initial_size",
DEFAULT_CONNECTION_POOL_INITIAL_SIZE, 0, Setting.Property.NodeScope);
public static final Function<String, Setting.AffixSetting<Integer>> POOL_INITIAL_SIZE = RealmSettings.affixSetting(
"user_search.pool.initial_size",
key -> Setting.intSetting(key, DEFAULT_CONNECTION_POOL_INITIAL_SIZE, 0, Setting.Property.NodeScope));
public static final int DEFAULT_CONNECTION_POOL_SIZE = 20;
public static final Setting<Integer> POOL_SIZE = Setting.intSetting("user_search.pool.size",
DEFAULT_CONNECTION_POOL_SIZE, 1, Setting.Property.NodeScope);
public static final Setting<TimeValue> HEALTH_CHECK_INTERVAL = Setting.timeSetting("user_search.pool.health_check.interval",
DEFAULT_HEALTH_CHECK_INTERVAL, Setting.Property.NodeScope);
public static final Setting<Boolean> HEALTH_CHECK_ENABLED = Setting.boolSetting("user_search.pool.health_check.enabled",
true, Setting.Property.NodeScope);
public static final Setting<Optional<String>> HEALTH_CHECK_DN = new Setting<>("user_search.pool.health_check.dn", (String) null,
Optional::ofNullable, Setting.Property.NodeScope);
public static final Function<String, Setting.AffixSetting<Integer>> POOL_SIZE = RealmSettings.affixSetting("user_search.pool.size",
key -> Setting.intSetting(key, DEFAULT_CONNECTION_POOL_SIZE, 1, Setting.Property.NodeScope));
private PoolingSessionFactorySettings() {}
public static final Function<String, Setting.AffixSetting<TimeValue>> HEALTH_CHECK_INTERVAL = RealmSettings.affixSetting(
"user_search.pool.health_check.interval",
key -> Setting.timeSetting(key, DEFAULT_HEALTH_CHECK_INTERVAL, Setting.Property.NodeScope));
public static Set<Setting<?>> getSettings() {
return Sets.newHashSet(POOL_INITIAL_SIZE, POOL_SIZE, HEALTH_CHECK_ENABLED, HEALTH_CHECK_INTERVAL, HEALTH_CHECK_DN, BIND_DN,
SECURE_BIND_PASSWORD, LEGACY_BIND_PASSWORD);
public static final Function<String, Setting.AffixSetting<Boolean>> HEALTH_CHECK_ENABLED = RealmSettings.affixSetting(
"user_search.pool.health_check.enabled",
key -> Setting.boolSetting(key, true, Setting.Property.NodeScope));
public static final Function<String, Setting.AffixSetting<Optional<String>>> HEALTH_CHECK_DN = RealmSettings.affixSetting(
"user_search.pool.health_check.dn",
key -> new Setting<>(key, (String) null,
Optional::ofNullable, Setting.Property.NodeScope));
private PoolingSessionFactorySettings() {
}
public static Set<Setting.AffixSetting<?>> getSettings(String realmType) {
return Stream.of(
POOL_INITIAL_SIZE, POOL_SIZE, HEALTH_CHECK_ENABLED, HEALTH_CHECK_INTERVAL, HEALTH_CHECK_DN, BIND_DN,
LEGACY_BIND_PASSWORD, SECURE_BIND_PASSWORD
).map(f -> f.apply(realmType)).collect(Collectors.toSet());
}
}

View File

@ -6,34 +6,46 @@
package org.elasticsearch.xpack.core.security.authc.ldap;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import static org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings.LDAP_TYPE;
public final class SearchGroupsResolverSettings {
public static final Setting<String> BASE_DN = Setting.simpleString("group_search.base_dn",
public static final Function<String, Setting.AffixSetting<String>> BASE_DN = RealmSettings.affixSetting(
"group_search.base_dn", key -> Setting.simpleString(key, new Setting.Property[]{Setting.Property.NodeScope}));
public static final Function<String, Setting.AffixSetting<LdapSearchScope>> SCOPE = RealmSettings.affixSetting(
"group_search.scope", key -> new Setting<>(key, (String) null,
s -> LdapSearchScope.resolve(s, LdapSearchScope.SUB_TREE), Setting.Property.NodeScope));
public static final Setting.AffixSetting<String> USER_ATTRIBUTE = RealmSettings.simpleString(LDAP_TYPE, "group_search.user_attribute",
Setting.Property.NodeScope);
public static final Setting<LdapSearchScope> SCOPE = new Setting<>("group_search.scope", (String) null,
s -> LdapSearchScope.resolve(s, LdapSearchScope.SUB_TREE), Setting.Property.NodeScope);
public static final Setting<String> USER_ATTRIBUTE = Setting.simpleString(
"group_search.user_attribute", Setting.Property.NodeScope);
private static final String GROUP_SEARCH_DEFAULT_FILTER = "(&" +
"(|(objectclass=groupOfNames)(objectclass=groupOfUniqueNames)" +
"(objectclass=group)(objectclass=posixGroup))" +
"(|(uniqueMember={0})(member={0})(memberUid={0})))";
public static final Setting<String> FILTER = new Setting<>("group_search.filter",
GROUP_SEARCH_DEFAULT_FILTER, Function.identity(), Setting.Property.NodeScope);
public static final Setting.AffixSetting<String> FILTER = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(LDAP_TYPE), "group_search.filter",
key -> new Setting<>(key, GROUP_SEARCH_DEFAULT_FILTER, Function.identity(), Setting.Property.NodeScope));
private SearchGroupsResolverSettings() {}
private SearchGroupsResolverSettings() {
}
public static Set<Setting<?>> getSettings() {
Set<Setting<?>> settings = new HashSet<>();
settings.add(BASE_DN);
settings.add(FILTER);
settings.add(USER_ATTRIBUTE);
settings.add(SCOPE);
public static Set<Setting.AffixSetting<?>> getSettings(String realmType) {
Set<Setting.AffixSetting<?>> settings = new HashSet<>();
settings.add(BASE_DN.apply(realmType));
settings.add(SCOPE.apply(realmType));
if (realmType.equals(LDAP_TYPE)) {
settings.add(FILTER);
settings.add(USER_ATTRIBUTE);
}
return settings;
}
}

View File

@ -6,18 +6,21 @@
package org.elasticsearch.xpack.core.security.authc.ldap;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import java.util.Collections;
import java.util.Set;
import java.util.function.Function;
public final class UserAttributeGroupsResolverSettings {
public static final Setting<String> ATTRIBUTE = new Setting<>("user_group_attribute", "memberOf",
Function.identity(), Setting.Property.NodeScope);
public static final Setting.AffixSetting<String> ATTRIBUTE = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(LdapRealmSettings.LDAP_TYPE), "user_group_attribute",
key -> new Setting<>(key, "memberOf", Function.identity(), Setting.Property.NodeScope));
private UserAttributeGroupsResolverSettings() {}
private UserAttributeGroupsResolverSettings() {
}
public static Set<Setting<?>> getSettings() {
public static Set<Setting.AffixSetting<?>> getSettings() {
return Collections.singleton(ATTRIBUTE);
}
}

View File

@ -6,21 +6,29 @@
package org.elasticsearch.xpack.core.security.authc.ldap.support;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
public final class LdapLoadBalancingSettings {
public static final String LOAD_BALANCE_SETTINGS = "load_balance";
public static final String LOAD_BALANCE_TYPE_SETTING = "type";
public static final String CACHE_TTL_SETTING = "cache_ttl";
private LdapLoadBalancingSettings() {}
public static final Function<String, Setting.AffixSetting<String>> LOAD_BALANCE_TYPE_SETTING = RealmSettings.affixSetting(
"load_balance.type", key -> Setting.simpleString(key, Setting.Property.NodeScope));
public static Set<Setting<?>> getSettings() {
Set<Setting<?>> settings = new HashSet<>();
settings.add(Setting.simpleString(LOAD_BALANCE_SETTINGS + "." + LOAD_BALANCE_TYPE_SETTING, Setting.Property.NodeScope));
settings.add(Setting.simpleString(LOAD_BALANCE_SETTINGS + "." + CACHE_TTL_SETTING, Setting.Property.NodeScope));
private static final TimeValue CACHE_TTL_DEFAULT = TimeValue.timeValueHours(1L);
public static final Function<String, Setting.AffixSetting<TimeValue>> CACHE_TTL_SETTING = RealmSettings.affixSetting(
"load_balance.cache_ttl", key -> Setting.timeSetting(key, CACHE_TTL_DEFAULT, Setting.Property.NodeScope));
private LdapLoadBalancingSettings() {
}
public static Set<Setting.AffixSetting<?>> getSettings(String realmType) {
Set<Setting.AffixSetting<?>> settings = new HashSet<>();
settings.add(LOAD_BALANCE_TYPE_SETTING.apply(realmType));
settings.add(CACHE_TTL_SETTING.apply(realmType));
return settings;
}
}

View File

@ -6,18 +6,21 @@
package org.elasticsearch.xpack.core.security.authc.ldap.support;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
public final class LdapMetaDataResolverSettings {
public static final Setting<List<String>> ADDITIONAL_META_DATA_SETTING = Setting.listSetting(
"metadata", Collections.emptyList(), Function.identity(), Setting.Property.NodeScope);
public static final Setting.AffixSetting<List<String>> ADDITIONAL_META_DATA_SETTING = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(LdapRealmSettings.LDAP_TYPE), "metadata",
key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(), Setting.Property.NodeScope));
private LdapMetaDataResolverSettings() {}
public static List<Setting<?>> getSettings() {
public static List<Setting.AffixSetting<?>> getSettings() {
return Collections.singletonList(ADDITIONAL_META_DATA_SETTING);
}
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.core.security.authc.ldap.support;
import com.unboundid.ldap.sdk.SearchScope;
import org.elasticsearch.common.Strings;
import java.util.Locale;
@ -26,7 +27,7 @@ public enum LdapSearchScope {
}
public static LdapSearchScope resolve(String scope, LdapSearchScope defaultScope) {
if (scope == null) {
if (Strings.isNullOrEmpty(scope)) {
return defaultScope;
}
switch (scope.toLowerCase(Locale.ENGLISH)) {

View File

@ -7,38 +7,53 @@ package org.elasticsearch.xpack.core.security.authc.ldap.support;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
public final class SessionFactorySettings {
public static final String URLS_SETTING = "url";
public static final String TIMEOUT_TCP_CONNECTION_SETTING = "timeout.tcp_connect";
public static final String TIMEOUT_TCP_READ_SETTING = "timeout.tcp_read";
public static final String TIMEOUT_LDAP_SETTING = "timeout.ldap_search";
public static final String HOSTNAME_VERIFICATION_SETTING = "hostname_verification";
public static final String FOLLOW_REFERRALS_SETTING = "follow_referrals";
public static final Setting<Boolean> IGNORE_REFERRAL_ERRORS_SETTING = Setting.boolSetting(
"ignore_referral_errors", true, Setting.Property.NodeScope);
public static final Function<String, Setting.AffixSetting<List<String>>> URLS_SETTING = RealmSettings.affixSetting(
"url", key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(), Setting.Property.NodeScope));
public static final TimeValue TIMEOUT_DEFAULT = TimeValue.timeValueSeconds(5);
public static final Function<String, Setting.AffixSetting<TimeValue>> TIMEOUT_TCP_CONNECTION_SETTING = RealmSettings.affixSetting(
"timeout.tcp_connect", key -> Setting.timeSetting(key, TIMEOUT_DEFAULT, Setting.Property.NodeScope));
private SessionFactorySettings() {}
public static final Function<String, Setting.AffixSetting<TimeValue>> TIMEOUT_TCP_READ_SETTING = RealmSettings.affixSetting(
"timeout.tcp_read", key -> Setting.timeSetting(key, TIMEOUT_DEFAULT, Setting.Property.NodeScope));
public static Set<Setting<?>> getSettings() {
Set<Setting<?>> settings = new HashSet<>();
settings.addAll(LdapLoadBalancingSettings.getSettings());
settings.add(Setting.listSetting(URLS_SETTING, Collections.emptyList(), Function.identity(),
Setting.Property.NodeScope));
settings.add(Setting.timeSetting(TIMEOUT_TCP_CONNECTION_SETTING, TIMEOUT_DEFAULT, Setting.Property.NodeScope));
settings.add(Setting.timeSetting(TIMEOUT_TCP_READ_SETTING, TIMEOUT_DEFAULT, Setting.Property.NodeScope));
settings.add(Setting.timeSetting(TIMEOUT_LDAP_SETTING, TIMEOUT_DEFAULT, Setting.Property.NodeScope));
settings.add(Setting.boolSetting(HOSTNAME_VERIFICATION_SETTING, true, Setting.Property.NodeScope, Setting.Property.Filtered));
settings.add(Setting.boolSetting(FOLLOW_REFERRALS_SETTING, true, Setting.Property.NodeScope));
settings.add(IGNORE_REFERRAL_ERRORS_SETTING);
settings.addAll(SSLConfigurationSettings.withPrefix("ssl.").getAllSettings());
public static final Function<String, Setting.AffixSetting<TimeValue>> TIMEOUT_LDAP_SETTING = RealmSettings.affixSetting(
"timeout.ldap_search", key -> Setting.timeSetting(key, TIMEOUT_DEFAULT, Setting.Property.NodeScope));
public static final Function<String, Setting.AffixSetting<Boolean>> HOSTNAME_VERIFICATION_SETTING = RealmSettings.affixSetting(
"hostname_verification", key -> Setting.boolSetting(key, true, Setting.Property.NodeScope, Setting.Property.Filtered));
public static final Function<String, Setting.AffixSetting<Boolean>> FOLLOW_REFERRALS_SETTING = RealmSettings.affixSetting(
"follow_referrals", key -> Setting.boolSetting(key, true, Setting.Property.NodeScope));
public static final Function<String, Setting.AffixSetting<Boolean>> IGNORE_REFERRAL_ERRORS_SETTING = RealmSettings.affixSetting(
"ignore_referral_errors", key -> Setting.boolSetting(key, true, Setting.Property.NodeScope));
private SessionFactorySettings() {
}
public static Set<Setting.AffixSetting<?>> getSettings(String realmType) {
Set<Setting.AffixSetting<?>> settings = new HashSet<>();
settings.addAll(LdapLoadBalancingSettings.getSettings(realmType));
settings.add(URLS_SETTING.apply(realmType));
settings.add(TIMEOUT_TCP_CONNECTION_SETTING.apply(realmType));
settings.add(TIMEOUT_TCP_READ_SETTING.apply(realmType));
settings.add(TIMEOUT_LDAP_SETTING.apply(realmType));
settings.add(HOSTNAME_VERIFICATION_SETTING.apply(realmType));
settings.add(FOLLOW_REFERRALS_SETTING.apply(realmType));
settings.add(IGNORE_REFERRAL_ERRORS_SETTING.apply(realmType));
settings.addAll(SSLConfigurationSettings.getRealmSettings(realmType));
return settings;
}
}

View File

@ -5,48 +5,84 @@
*/
package org.elasticsearch.xpack.core.security.authc.pki;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.DelegatedAuthorizationSettings;
import org.elasticsearch.xpack.core.security.authc.support.mapper.CompositeRoleMapperSettings;
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
public final class PkiRealmSettings {
public static final String TYPE = "pki";
public static final String DEFAULT_USERNAME_PATTERN = "CN=(.*?)(?:,|$)";
public static final Setting<Pattern> USERNAME_PATTERN_SETTING = new Setting<>("username_pattern", DEFAULT_USERNAME_PATTERN,
s -> Pattern.compile(s, Pattern.CASE_INSENSITIVE), Setting.Property.NodeScope);
private static final TimeValue DEFAULT_TTL = TimeValue.timeValueMinutes(20);
public static final Setting<TimeValue> CACHE_TTL_SETTING = Setting.timeSetting("cache.ttl", DEFAULT_TTL, Setting.Property.NodeScope);
private static final int DEFAULT_MAX_USERS = 100_000; //100k users
public static final Setting<Integer> CACHE_MAX_USERS_SETTING = Setting.intSetting("cache.max_users", DEFAULT_MAX_USERS,
Setting.Property.NodeScope);
public static final SSLConfigurationSettings SSL_SETTINGS = SSLConfigurationSettings.withoutPrefix();
public static final Setting.AffixSetting<Pattern> USERNAME_PATTERN_SETTING = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "username_pattern",
key -> new Setting<>(key, DEFAULT_USERNAME_PATTERN, s -> Pattern.compile(s, Pattern.CASE_INSENSITIVE),
Setting.Property.NodeScope));
private PkiRealmSettings() {}
private static final TimeValue DEFAULT_TTL = TimeValue.timeValueMinutes(20);
public static final Setting.AffixSetting<TimeValue> CACHE_TTL_SETTING = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "cache.ttl",
key -> Setting.timeSetting(key, DEFAULT_TTL, Setting.Property.NodeScope));
private static final int DEFAULT_MAX_USERS = 100_000; //100k users
public static final Setting.AffixSetting<Integer> CACHE_MAX_USERS_SETTING = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "cache.max_users",
key -> Setting.intSetting(key, DEFAULT_MAX_USERS, Setting.Property.NodeScope));
public static final Setting.AffixSetting<Optional<String>> TRUST_STORE_PATH;
public static final Setting.AffixSetting<Optional<String>> TRUST_STORE_TYPE;
public static final Setting.AffixSetting<SecureString> TRUST_STORE_PASSWORD;
public static final Setting.AffixSetting<SecureString> LEGACY_TRUST_STORE_PASSWORD;
public static final Setting.AffixSetting<String> TRUST_STORE_ALGORITHM;
public static final Setting.AffixSetting<List<String>> CAPATH_SETTING;
static {
final String prefix = "xpack.security.authc.realms." + TYPE + ".";
final SSLConfigurationSettings ssl = SSLConfigurationSettings.withoutPrefix();
TRUST_STORE_PATH = Setting.affixKeySetting(prefix, ssl.truststorePath.getKey(),
SSLConfigurationSettings.TRUST_STORE_PATH_TEMPLATE);
TRUST_STORE_TYPE = Setting.affixKeySetting(prefix, ssl.truststoreType.getKey(),
SSLConfigurationSettings.TRUST_STORE_TYPE_TEMPLATE);
TRUST_STORE_PASSWORD = Setting.affixKeySetting(prefix, ssl.truststorePassword.getKey(),
SSLConfigurationSettings.TRUSTSTORE_PASSWORD_TEMPLATE);
LEGACY_TRUST_STORE_PASSWORD = Setting.affixKeySetting(prefix, ssl.legacyTruststorePassword.getKey(),
SSLConfigurationSettings.LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE);
TRUST_STORE_ALGORITHM = Setting.affixKeySetting(prefix, ssl.truststoreAlgorithm.getKey(),
SSLConfigurationSettings.TRUST_STORE_ALGORITHM_TEMPLATE);
CAPATH_SETTING = Setting.affixKeySetting(prefix, ssl.caPaths.getKey(),
SSLConfigurationSettings.CAPATH_SETTING_TEMPLATE);
}
private PkiRealmSettings() {
}
/**
* @return The {@link Setting setting configuration} for this realm type
*/
public static Set<Setting<?>> getSettings() {
Set<Setting<?>> settings = new HashSet<>();
public static Set<Setting.AffixSetting<?>> getSettings() {
Set<Setting.AffixSetting<?>> settings = new HashSet<>();
settings.add(USERNAME_PATTERN_SETTING);
settings.add(CACHE_TTL_SETTING);
settings.add(CACHE_MAX_USERS_SETTING);
settings.add(SSL_SETTINGS.truststorePath);
settings.add(SSL_SETTINGS.truststorePassword);
settings.add(SSL_SETTINGS.legacyTruststorePassword);
settings.add(SSL_SETTINGS.truststoreAlgorithm);
settings.add(SSL_SETTINGS.caPaths);
settings.add(TRUST_STORE_PATH);
settings.add(TRUST_STORE_PASSWORD);
settings.add(LEGACY_TRUST_STORE_PASSWORD);
settings.add(TRUST_STORE_ALGORITHM);
settings.add(CAPATH_SETTING);
settings.addAll(DelegatedAuthorizationSettings.getSettings());
settings.addAll(CompositeRoleMapperSettings.getSettings());
settings.addAll(DelegatedAuthorizationSettings.getSettings(TYPE));
settings.addAll(CompositeRoleMapperSettings.getSettings(TYPE));
settings.addAll(RealmSettings.getStandardSettings(TYPE));
return settings;
}
}

View File

@ -8,6 +8,8 @@ package org.elasticsearch.xpack.core.security.authc.saml;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.unit.TimeValue;
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 org.elasticsearch.xpack.core.ssl.X509KeyPairSettings;
@ -27,26 +29,43 @@ public class SamlRealmSettings {
// these settings will be used under the prefix xpack.security.authc.realms.REALM_NAME.
private static final String IDP_METADATA_SETTING_PREFIX = "idp.metadata.";
public static final Setting<String> IDP_ENTITY_ID = Setting.simpleString("idp.entity_id", Setting.Property.NodeScope);
public static final Setting<String> IDP_METADATA_PATH
= Setting.simpleString(IDP_METADATA_SETTING_PREFIX + "path", Setting.Property.NodeScope);
public static final Setting<TimeValue> IDP_METADATA_HTTP_REFRESH
= Setting.timeSetting(IDP_METADATA_SETTING_PREFIX + "http.refresh", TimeValue.timeValueHours(1), Setting.Property.NodeScope);
public static final Setting<Boolean> IDP_SINGLE_LOGOUT = Setting.boolSetting("idp.use_single_logout", true, Setting.Property.NodeScope);
public static final Setting.AffixSetting<String> IDP_ENTITY_ID
= RealmSettings.simpleString(TYPE, "idp.entity_id", Setting.Property.NodeScope);
public static final Setting<String> SP_ENTITY_ID = Setting.simpleString("sp.entity_id", Setting.Property.NodeScope);
public static final Setting<String> SP_ACS = Setting.simpleString("sp.acs", Setting.Property.NodeScope);
public static final Setting<String> SP_LOGOUT = Setting.simpleString("sp.logout", Setting.Property.NodeScope);
public static final Setting.AffixSetting<String> IDP_METADATA_PATH
= RealmSettings.simpleString(TYPE, IDP_METADATA_SETTING_PREFIX + "path", Setting.Property.NodeScope);
public static final Setting<String> NAMEID_FORMAT = new Setting<>("nameid_format", s -> TRANSIENT_NAMEID_FORMAT, Function.identity(),
Setting.Property.NodeScope);
public static final Setting<Boolean> NAMEID_ALLOW_CREATE = Setting.boolSetting("nameid.allow_create", false,
Setting.Property.NodeScope);
public static final Setting<String> NAMEID_SP_QUALIFIER = Setting.simpleString("nameid.sp_qualifier", Setting.Property.NodeScope);
public static final Setting.AffixSetting<TimeValue> IDP_METADATA_HTTP_REFRESH = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), IDP_METADATA_SETTING_PREFIX + "http.refresh",
key -> Setting.timeSetting(key, TimeValue.timeValueHours(1), Setting.Property.NodeScope));
public static final Setting<Boolean> FORCE_AUTHN = Setting.boolSetting("force_authn", false, Setting.Property.NodeScope);
public static final Setting<Boolean> POPULATE_USER_METADATA = Setting.boolSetting("populate_user_metadata", true,
Setting.Property.NodeScope);
public static final Setting.AffixSetting<Boolean> IDP_SINGLE_LOGOUT = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "idp.use_single_logout",
key -> Setting.boolSetting(key, true, Setting.Property.NodeScope));
public static final Setting.AffixSetting<String> SP_ENTITY_ID
= RealmSettings.simpleString(TYPE, "sp.entity_id", Setting.Property.NodeScope);
public static final Setting.AffixSetting<String> SP_ACS = RealmSettings.simpleString(TYPE, "sp.acs", Setting.Property.NodeScope);
public static final Setting.AffixSetting<String> SP_LOGOUT = RealmSettings.simpleString(TYPE, "sp.logout", Setting.Property.NodeScope);
public static final Setting.AffixSetting<String> NAMEID_FORMAT = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "nameid_format",
key -> new Setting<>(key, s -> TRANSIENT_NAMEID_FORMAT, Function.identity(), Setting.Property.NodeScope));
public static final Setting.AffixSetting<Boolean> NAMEID_ALLOW_CREATE = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "nameid.allow_create",
key -> Setting.boolSetting(key, false, Setting.Property.NodeScope));
public static final Setting.AffixSetting<String> NAMEID_SP_QUALIFIER
= RealmSettings.simpleString(TYPE, "nameid.sp_qualifier", Setting.Property.NodeScope);
public static final Setting.AffixSetting<Boolean> FORCE_AUTHN = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "force_authn",
key -> Setting.boolSetting(key, false, 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 AttributeSetting PRINCIPAL_ATTRIBUTE = new AttributeSetting("principal");
public static final AttributeSetting GROUPS_ATTRIBUTE = new AttributeSetting("groups");
@ -54,19 +73,25 @@ public class SamlRealmSettings {
public static final AttributeSetting NAME_ATTRIBUTE = new AttributeSetting("name");
public static final AttributeSetting MAIL_ATTRIBUTE = new AttributeSetting("mail");
public static final X509KeyPairSettings ENCRYPTION_SETTINGS = new X509KeyPairSettings("encryption.", false);
public static final Setting<String> ENCRYPTION_KEY_ALIAS =
Setting.simpleString("encryption.keystore.alias", Setting.Property.NodeScope);
public static final String ENCRYPTION_SETTING_KEY = "encryption.";
public static final Setting.AffixSetting<String> ENCRYPTION_KEY_ALIAS = RealmSettings.simpleString(
TYPE, ENCRYPTION_SETTING_KEY + "keystore.alias", Setting.Property.NodeScope);
public static final X509KeyPairSettings SIGNING_SETTINGS = new X509KeyPairSettings("signing.", false);
public static final Setting<String> SIGNING_KEY_ALIAS =
Setting.simpleString("signing.keystore.alias", Setting.Property.NodeScope);
public static final Setting<List<String>> SIGNING_MESSAGE_TYPES = Setting.listSetting("signing.saml_messages",
Collections.singletonList("*"), Function.identity(), Setting.Property.NodeScope);
public static final Setting<List<String>> REQUESTED_AUTHN_CONTEXT_CLASS_REF = Setting.listSetting("req_authn_context_class_ref",
Collections.emptyList(), Function.identity(),Setting.Property.NodeScope);
public static final Setting<TimeValue> CLOCK_SKEW = Setting.positiveTimeSetting("allowed_clock_skew", TimeValue.timeValueMinutes(3),
Setting.Property.NodeScope);
public static final String SIGNING_SETTING_KEY = "signing.";
public static final Setting.AffixSetting<String> SIGNING_KEY_ALIAS = RealmSettings.simpleString(
TYPE, SIGNING_SETTING_KEY + "keystore.alias", Setting.Property.NodeScope);
public static final Setting.AffixSetting<List<String>> SIGNING_MESSAGE_TYPES = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "signing.saml_messages",
key -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(), Setting.Property.NodeScope));
public static final Setting.AffixSetting<List<String>> REQUESTED_AUTHN_CONTEXT_CLASS_REF = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "req_authn_context_class_ref",
key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(),Setting.Property.NodeScope));
public static final Setting.AffixSetting<TimeValue> CLOCK_SKEW = Setting.affixKeySetting(
RealmSettings.realmSettingPrefix(TYPE), "allowed_clock_skew",
key -> Setting.positiveTimeSetting(key, TimeValue.timeValueMinutes(3), Setting.Property.NodeScope));
public static final String SSL_PREFIX = "ssl.";
@ -76,21 +101,24 @@ public class SamlRealmSettings {
/**
* @return The {@link Setting setting configuration} for this realm type
*/
public static Set<Setting<?>> getSettings() {
final Set<Setting<?>> set = Sets.newHashSet(IDP_ENTITY_ID, IDP_METADATA_PATH, IDP_SINGLE_LOGOUT,
public static Set<Setting.AffixSetting<?>> getSettings() {
final Set<Setting.AffixSetting<?>> set = Sets.newHashSet(
IDP_ENTITY_ID, IDP_METADATA_PATH, IDP_SINGLE_LOGOUT,
SP_ENTITY_ID, SP_ACS, SP_LOGOUT,
NAMEID_FORMAT, NAMEID_ALLOW_CREATE, NAMEID_SP_QUALIFIER, FORCE_AUTHN,
POPULATE_USER_METADATA, CLOCK_SKEW,
ENCRYPTION_KEY_ALIAS, SIGNING_KEY_ALIAS, SIGNING_MESSAGE_TYPES, REQUESTED_AUTHN_CONTEXT_CLASS_REF);
set.addAll(ENCRYPTION_SETTINGS.getAllSettings());
set.addAll(SIGNING_SETTINGS.getAllSettings());
set.addAll(SSLConfigurationSettings.withPrefix(SSL_PREFIX).getAllSettings());
ENCRYPTION_KEY_ALIAS, SIGNING_KEY_ALIAS, SIGNING_MESSAGE_TYPES, REQUESTED_AUTHN_CONTEXT_CLASS_REF);
set.addAll(X509KeyPairSettings.affix(RealmSettings.realmSettingPrefix(TYPE), ENCRYPTION_SETTING_KEY, false));
set.addAll(X509KeyPairSettings.affix(RealmSettings.realmSettingPrefix(TYPE), SIGNING_SETTING_KEY, false));
set.addAll(SSLConfigurationSettings.getRealmSettings(TYPE));
set.addAll(PRINCIPAL_ATTRIBUTE.settings());
set.addAll(GROUPS_ATTRIBUTE.settings());
set.addAll(DN_ATTRIBUTE.settings());
set.addAll(NAME_ATTRIBUTE.settings());
set.addAll(MAIL_ATTRIBUTE.settings());
set.addAll(DelegatedAuthorizationSettings.getSettings());
set.addAll(DelegatedAuthorizationSettings.getSettings(TYPE));
set.addAll(RealmSettings.getStandardSettings(TYPE));
return set;
}
@ -109,27 +137,27 @@ public class SamlRealmSettings {
public static final String ATTRIBUTES_PREFIX = "attributes.";
public static final String ATTRIBUTE_PATTERNS_PREFIX = "attribute_patterns.";
private final Setting<String> attribute;
private final Setting<String> pattern;
private final Setting.AffixSetting<String> attribute;
private final Setting.AffixSetting<String> pattern;
public AttributeSetting(String name) {
attribute = Setting.simpleString(ATTRIBUTES_PREFIX + name, Setting.Property.NodeScope);
pattern = Setting.simpleString(ATTRIBUTE_PATTERNS_PREFIX + name, Setting.Property.NodeScope);
attribute = RealmSettings.simpleString(TYPE, ATTRIBUTES_PREFIX + name, Setting.Property.NodeScope);
pattern = RealmSettings.simpleString(TYPE, ATTRIBUTE_PATTERNS_PREFIX + name, Setting.Property.NodeScope);
}
public Collection<Setting<?>> settings() {
public Collection<Setting.AffixSetting<?>> settings() {
return Arrays.asList(getAttribute(), getPattern());
}
public String name() {
return getAttribute().getKey();
public String name(RealmConfig config) {
return getAttribute().getConcreteSettingForNamespace(config.name()).getKey();
}
public Setting<String> getAttribute() {
public Setting.AffixSetting<String> getAttribute() {
return attribute;
}
public Setting<String> getPattern() {
public Setting.AffixSetting<String> getPattern() {
return pattern;
}
}

View File

@ -7,29 +7,44 @@ package org.elasticsearch.xpack.core.security.authc.support;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
public final class CachingUsernamePasswordRealmSettings {
public static final Setting<String> CACHE_HASH_ALGO_SETTING = Setting.simpleString("cache.hash_algo", "ssha256",
Setting.Property.NodeScope);
private static final String CACHE_HASH_ALGO_SUFFIX = "cache.hash_algo";
public static final Function<String, Setting.AffixSetting<String>> CACHE_HASH_ALGO_SETTING = RealmSettings.affixSetting(
CACHE_HASH_ALGO_SUFFIX, key -> Setting.simpleString(key, "ssha256", Setting.Property.NodeScope));
private static final TimeValue DEFAULT_TTL = TimeValue.timeValueMinutes(20);
public static final Setting<TimeValue> CACHE_TTL_SETTING = Setting.timeSetting("cache.ttl", DEFAULT_TTL, Setting.Property.NodeScope);
private static final String CACHE_TTL_SUFFIX = "cache.ttl";
public static final Function<String, Setting.AffixSetting<TimeValue>> CACHE_TTL_SETTING = RealmSettings.affixSetting(
CACHE_TTL_SUFFIX, key -> Setting.timeSetting(key, DEFAULT_TTL, Setting.Property.NodeScope));
private static final int DEFAULT_MAX_USERS = 100_000; //100k users
public static final Setting<Integer> CACHE_MAX_USERS_SETTING = Setting.intSetting("cache.max_users", DEFAULT_MAX_USERS,
Setting.Property.NodeScope);
private static final String CACHE_MAX_USERS_SUFFIX = "cache.max_users";
public static final Function<String, Setting.AffixSetting<Integer>> CACHE_MAX_USERS_SETTING = RealmSettings.affixSetting(
CACHE_MAX_USERS_SUFFIX, key -> Setting.intSetting(key, DEFAULT_MAX_USERS, Setting.Property.NodeScope));
public static final Setting<Boolean> AUTHC_ENABLED_SETTING = Setting.boolSetting("authentication.enabled", true,
Setting.Property.NodeScope);
public static final Function<String, Setting.AffixSetting<Boolean>> AUTHC_ENABLED_SETTING = RealmSettings.affixSetting(
"authentication.enabled", key -> Setting.boolSetting(key, true, Setting.Property.NodeScope));
private CachingUsernamePasswordRealmSettings() {}
private CachingUsernamePasswordRealmSettings() {
}
/**
* Returns the {@link Setting setting configuration} that is common for all caching realms
*/
public static Set<Setting<?>> getSettings() {
return new HashSet<>(Arrays.asList(CACHE_HASH_ALGO_SETTING, CACHE_TTL_SETTING, CACHE_MAX_USERS_SETTING, AUTHC_ENABLED_SETTING));
public static Set<Setting.AffixSetting<?>> getSettings(String type) {
return new HashSet<>(Arrays.asList(
CACHE_HASH_ALGO_SETTING.apply(type),
CACHE_TTL_SETTING.apply(type),
CACHE_MAX_USERS_SETTING.apply(type),
AUTHC_ENABLED_SETTING.apply(type)
));
}
}

View File

@ -7,6 +7,7 @@
package org.elasticsearch.xpack.core.security.authc.support;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import java.util.Collection;
import java.util.Collections;
@ -18,10 +19,11 @@ import java.util.function.Function;
*/
public class DelegatedAuthorizationSettings {
public static final Setting<List<String>> AUTHZ_REALMS = Setting.listSetting("authorization_realms",
Collections.emptyList(), Function.identity(), Setting.Property.NodeScope);
public static final String AUTHZ_REALMS_SUFFIX = "authorization_realms";
public static final Function<String, Setting.AffixSetting<List<String>>> AUTHZ_REALMS = RealmSettings.affixSetting(
AUTHZ_REALMS_SUFFIX, key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(), Setting.Property.NodeScope));
public static Collection<Setting<?>> getSettings() {
return Collections.singleton(AUTHZ_REALMS);
public static Collection<Setting.AffixSetting<?>> getSettings(String realmType) {
return Collections.singleton(AUTHZ_REALMS.apply(realmType));
}
}

View File

@ -6,20 +6,26 @@
package org.elasticsearch.xpack.core.security.authc.support;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import java.util.Arrays;
import java.util.List;
import java.util.Collection;
import java.util.function.Function;
public final class DnRoleMapperSettings {
private static final String DEFAULT_FILE_NAME = "role_mapping.yml";
public static final Setting<String> ROLE_MAPPING_FILE_SETTING = new Setting<>("files.role_mapping", DEFAULT_FILE_NAME,
Function.identity(), Setting.Property.NodeScope);
public static final Setting<Boolean> USE_UNMAPPED_GROUPS_AS_ROLES_SETTING =
Setting.boolSetting("unmapped_groups_as_roles", false, Setting.Property.NodeScope);
public static final String FILES_ROLE_MAPPING_SUFFIX = "files.role_mapping";
public static final Function<String, Setting.AffixSetting<String>> ROLE_MAPPING_FILE_SETTING = type ->
Setting.affixKeySetting(RealmSettings.realmSettingPrefix(type), FILES_ROLE_MAPPING_SUFFIX,
key -> new Setting<>(key, DEFAULT_FILE_NAME, Function.identity(), Setting.Property.NodeScope));
public static List<Setting<?>> getSettings() {
return Arrays.asList(USE_UNMAPPED_GROUPS_AS_ROLES_SETTING, ROLE_MAPPING_FILE_SETTING);
public static final String UNMAPPED_GROUPS_AS_ROLES_SUFFIX = "unmapped_groups_as_roles";
public static final Function<String, Setting.AffixSetting<Boolean>> USE_UNMAPPED_GROUPS_AS_ROLES_SETTING = type ->
Setting.affixKeySetting(RealmSettings.realmSettingPrefix(type), UNMAPPED_GROUPS_AS_ROLES_SUFFIX,
key -> Setting.boolSetting(key, false, Setting.Property.NodeScope));
public static Collection<? extends Setting.AffixSetting<?>> getSettings(String realmType) {
return Arrays.asList(USE_UNMAPPED_GROUPS_AS_ROLES_SETTING.apply(realmType), ROLE_MAPPING_FILE_SETTING.apply(realmType));
}
}

View File

@ -13,7 +13,7 @@ import java.util.Collection;
public final class CompositeRoleMapperSettings {
private CompositeRoleMapperSettings() {}
public static Collection<? extends Setting<?>> getSettings() {
return DnRoleMapperSettings.getSettings();
public static Collection<? extends Setting.AffixSetting<?>> getSettings(String type) {
return DnRoleMapperSettings.getSettings(type);
}
}

View File

@ -13,7 +13,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.CollectionUtils;
import javax.net.ssl.TrustManagerFactory;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.Collection;
@ -58,107 +57,169 @@ public class SSLConfigurationSettings {
private static final Function<String, Setting<List<String>>> CIPHERS_SETTING_TEMPLATE = key -> Setting.listSetting(key, Collections
.emptyList(), Function.identity(), Property.NodeScope, Property.Filtered);
public static final Setting<List<String>> CIPHERS_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.",
public static final Setting<List<String>> CIPHERS_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.cipher_suites", CIPHERS_SETTING_TEMPLATE);
public static final Function<String, Setting.AffixSetting<List<String>>> CIPHERS_SETTING_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.cipher_suites", CIPHERS_SETTING_TEMPLATE);
private static final Function<String,Setting<List<String>>> SUPPORTED_PROTOCOLS_TEMPLATE = key -> Setting.listSetting(key,
private static final Function<String, Setting<List<String>>> SUPPORTED_PROTOCOLS_TEMPLATE = key -> Setting.listSetting(key,
Collections.emptyList(), Function.identity(), Property.NodeScope, Property.Filtered);
public static final Setting<List<String>> SUPPORTED_PROTOCOLS_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.supported_protocols", SUPPORTED_PROTOCOLS_TEMPLATE) ;
"xpack.security.ssl.supported_protocols", SUPPORTED_PROTOCOLS_TEMPLATE);
public static final Function<String, Setting.AffixSetting<List<String>>> SUPPORTED_PROTOCOLS_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.supported_protocols",
SUPPORTED_PROTOCOLS_TEMPLATE);
public static final Setting<Optional<String>> KEYSTORE_PATH_PROFILES = Setting.affixKeySetting("transport.profiles.",
static final Setting<Optional<String>> KEYSTORE_PATH_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.keystore.path", X509KeyPairSettings.KEYSTORE_PATH_TEMPLATE);
static final Function<String, Setting.AffixSetting<Optional<String>>> KEYSTORE_PATH_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.path",
X509KeyPairSettings.KEYSTORE_PATH_TEMPLATE);
public static final Setting<SecureString> LEGACY_KEYSTORE_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.keystore.password", X509KeyPairSettings.LEGACY_KEYSTORE_PASSWORD_TEMPLATE);
public static final Function<String, Setting.AffixSetting<SecureString>> LEGACY_KEYSTORE_PASSWORD_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.password",
X509KeyPairSettings.LEGACY_KEYSTORE_PASSWORD_TEMPLATE);
public static final Setting<SecureString> KEYSTORE_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.keystore.secure_password", X509KeyPairSettings.KEYSTORE_PASSWORD_TEMPLATE);
public static final Function<String, Setting.AffixSetting<SecureString>> KEYSTORE_PASSWORD_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.secure_password",
X509KeyPairSettings.KEYSTORE_PASSWORD_TEMPLATE);
public static final Setting<SecureString> LEGACY_KEYSTORE_KEY_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.keystore.key_password", X509KeyPairSettings.LEGACY_KEYSTORE_KEY_PASSWORD_TEMPLATE);
public static final Function<String, Setting.AffixSetting<SecureString>> LEGACY_KEYSTORE_KEY_PASSWORD_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.key_password",
X509KeyPairSettings.LEGACY_KEYSTORE_KEY_PASSWORD_TEMPLATE);
public static final Setting<SecureString> KEYSTORE_KEY_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.keystore.secure_key_password", X509KeyPairSettings.KEYSTORE_KEY_PASSWORD_TEMPLATE);
public static final Function<String, Setting.AffixSetting<SecureString>> KEYSTORE_KEY_PASSWORD_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.secure_key_password",
X509KeyPairSettings.KEYSTORE_KEY_PASSWORD_TEMPLATE);
private static final Function<String, Setting<Optional<String>>> TRUST_STORE_PATH_TEMPLATE = key -> new Setting<>(key, s -> null,
public static final Function<String, Setting<Optional<String>>> TRUST_STORE_PATH_TEMPLATE = key -> new Setting<>(key, s -> null,
Optional::ofNullable, Property.NodeScope, Property.Filtered);
public static final Setting<Optional<String>> TRUST_STORE_PATH_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.truststore.path", TRUST_STORE_PATH_TEMPLATE);
public static final Function<String, Setting.AffixSetting<Optional<String>>> TRUST_STORE_PATH_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.truststore.path", TRUST_STORE_PATH_TEMPLATE);
public static final Setting<Optional<String>> KEY_PATH_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.key", X509KeyPairSettings.KEY_PATH_TEMPLATE);
public static final Function<String, Setting.AffixSetting<Optional<String>>> KEY_PATH_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.key", X509KeyPairSettings.KEY_PATH_TEMPLATE);
private static final Function<String, Setting<SecureString>> LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE = key ->
public static final Function<String, Setting<SecureString>> LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE = key ->
new Setting<>(key, "", SecureString::new, Property.Deprecated, Property.Filtered, Property.NodeScope);
public static final Setting<SecureString> LEGACY_TRUSTSTORE_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.truststore.password", LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE);
public static final Function<String, Setting.AffixSetting<SecureString>> LEGACY_TRUST_STORE_PASSWORD_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "truststore.password",
LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE);
private static final Function<String, Setting<SecureString>> TRUSTSTORE_PASSWORD_TEMPLATE = key ->
public static final Function<String, Setting<SecureString>> TRUSTSTORE_PASSWORD_TEMPLATE = key ->
SecureSetting.secureString(key, LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE.apply(key.replace("truststore.secure_password",
"truststore.password")));
public static final Setting<SecureString> TRUSTSTORE_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.truststore.secure_password", TRUSTSTORE_PASSWORD_TEMPLATE);
public static final Function<String, Setting.AffixSetting<SecureString>> TRUST_STORE_PASSWORD_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.truststore.secure_password",
TRUSTSTORE_PASSWORD_TEMPLATE);
public static final Setting<String> KEY_STORE_ALGORITHM_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.keystore.algorithm", X509KeyPairSettings.KEY_STORE_ALGORITHM_TEMPLATE);
public static final Function<String, Setting.AffixSetting<String>> KEY_STORE_ALGORITHM_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.algorithm",
X509KeyPairSettings.KEY_STORE_ALGORITHM_TEMPLATE);
private static final Function<String, Setting<String>> TRUST_STORE_ALGORITHM_TEMPLATE = key ->
public static final Function<String, Setting<String>> TRUST_STORE_ALGORITHM_TEMPLATE = key ->
new Setting<>(key, s -> TrustManagerFactory.getDefaultAlgorithm(),
Function.identity(), Property.NodeScope, Property.Filtered);
public static final Setting<String> TRUST_STORE_ALGORITHM_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.truststore.algorithm", TRUST_STORE_ALGORITHM_TEMPLATE);
public static final Function<String, Setting.AffixSetting<String>> TRUST_STORE_ALGORITHM_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.truststore.algorithm",
TRUST_STORE_ALGORITHM_TEMPLATE);
public static final Setting<Optional<String>> KEY_STORE_TYPE_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.keystore.type", X509KeyPairSettings.KEY_STORE_TYPE_TEMPLATE);
public static final Function<String, Setting.AffixSetting<Optional<String>>> KEY_STORE_TYPE_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.type",
X509KeyPairSettings.KEY_STORE_TYPE_TEMPLATE);
private static final Function<String, Setting<Optional<String>>> TRUST_STORE_TYPE_TEMPLATE =
public static final Function<String, Setting<Optional<String>>> TRUST_STORE_TYPE_TEMPLATE =
X509KeyPairSettings.KEY_STORE_TYPE_TEMPLATE;
public static final Setting<Optional<String>> TRUST_STORE_TYPE_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.truststore.type", TRUST_STORE_TYPE_TEMPLATE);
public static final Function<String, Setting.AffixSetting<Optional<String>>> TRUST_STORE_TYPE_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.truststore.type", TRUST_STORE_TYPE_TEMPLATE);
private static final Function<String, Setting<Optional<String>>> TRUST_RESTRICTIONS_TEMPLATE = key -> new Setting<>(key, s -> null,
Optional::ofNullable, Property.NodeScope, Property.Filtered);
public static final Setting<Optional<String>> TRUST_RESTRICTIONS_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.trust_restrictions", TRUST_RESTRICTIONS_TEMPLATE);
public static final Function<String, Setting.AffixSetting<Optional<String>>> TRUST_RESTRICTIONS_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.trust_restrictions",
TRUST_RESTRICTIONS_TEMPLATE);
public static final Setting<SecureString> LEGACY_KEY_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.key_passphrase", X509KeyPairSettings.LEGACY_KEY_PASSWORD_TEMPLATE);
public static final Function<String, Setting.AffixSetting<SecureString>> LEGACY_KEY_PASSWORD_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.key_passphrase",
X509KeyPairSettings.LEGACY_KEY_PASSWORD_TEMPLATE);
public static final Setting<SecureString> KEY_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.secure_key_passphrase", X509KeyPairSettings.KEY_PASSWORD_TEMPLATE);
public static final Function<String, Setting.AffixSetting<SecureString>> KEY_PASSWORD_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.secure_key_passphrase",
X509KeyPairSettings.KEY_PASSWORD_TEMPLATE);
public static final Setting<Optional<String>> CERT_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.certificate", X509KeyPairSettings.CERT_TEMPLATE);
public static final Function<String, Setting.AffixSetting<Optional<String>>> CERT_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.certificate",
X509KeyPairSettings.CERT_TEMPLATE);
private static final Function<String, Setting<List<String>>> CAPATH_SETTING_TEMPLATE = key -> Setting.listSetting(key, Collections
public static final Function<String, Setting<List<String>>> CAPATH_SETTING_TEMPLATE = key -> Setting.listSetting(key, Collections
.emptyList(), Function.identity(), Property.NodeScope, Property.Filtered);
public static final Setting<List<String>> CAPATH_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.",
public static final Setting<List<String>> CAPATH_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.certificate_authorities", CAPATH_SETTING_TEMPLATE);
public static final Function<String, Setting.AffixSetting<List<String>>> CAPATH_SETTING_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.certificate_authorities",
CAPATH_SETTING_TEMPLATE);
private static final Function<String, Setting<Optional<SSLClientAuth>>> CLIENT_AUTH_SETTING_TEMPLATE =
key -> new Setting<>(key, (String) null, s -> s == null ? Optional.empty() : Optional.of(SSLClientAuth.parse(s)),
Property.NodeScope, Property.Filtered);
public static final Setting<Optional<SSLClientAuth>> CLIENT_AUTH_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.",
public static final Setting<Optional<SSLClientAuth>> CLIENT_AUTH_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.client_authentication", CLIENT_AUTH_SETTING_TEMPLATE);
public static final Function<String, Setting.AffixSetting<Optional<SSLClientAuth>>> CLIENT_AUTH_SETTING_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.client_authentication",
CLIENT_AUTH_SETTING_TEMPLATE);
private static final Function<String, Setting<Optional<VerificationMode>>> VERIFICATION_MODE_SETTING_TEMPLATE =
key -> new Setting<>(key, (String) null, s -> s == null ? Optional.empty() : Optional.of(VerificationMode.parse(s)),
Property.NodeScope, Property.Filtered);
public static final Setting<Optional<VerificationMode>> VERIFICATION_MODE_SETTING_PROFILES = Setting.affixKeySetting(
"transport.profiles.", "xpack.security.ssl.verification_mode", VERIFICATION_MODE_SETTING_TEMPLATE);
public static final Function<String, Setting.AffixSetting<Optional<VerificationMode>>> VERIFICATION_MODE_SETTING_REALM = realmType ->
Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.verification_mode",
VERIFICATION_MODE_SETTING_TEMPLATE);
/**
* @see #withoutPrefix
* @see #withPrefix
* @param prefix The prefix under which each setting should be defined. Must be either the empty string (<code>""</code>) or a string
* ending in <code>"."</code>
* @see #withoutPrefix
* @see #withPrefix
*/
private SSLConfigurationSettings(String prefix) {
assert prefix != null : "Prefix cannot be null (but can be blank)";
x509KeyPair = new X509KeyPairSettings(prefix, true);
ciphers = CIPHERS_SETTING_TEMPLATE.apply(prefix + "cipher_suites");
x509KeyPair = X509KeyPairSettings.withPrefix(prefix, true);
ciphers = CIPHERS_SETTING_TEMPLATE.apply(prefix + "cipher_suites");
supportedProtocols = SUPPORTED_PROTOCOLS_TEMPLATE.apply(prefix + "supported_protocols");
truststorePath = TRUST_STORE_PATH_TEMPLATE.apply(prefix + "truststore.path");
legacyTruststorePassword = LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE.apply(prefix + "truststore.password");
@ -205,6 +266,7 @@ public class SSLConfigurationSettings {
/**
* Construct settings that have a prefixed. That is, they can be used to read from a {@link Settings} object where the configuration
* keys are prefixed-children of the <code>Settings</code>.
*
* @param prefix A string that must end in <code>"ssl."</code>
*/
public static SSLConfigurationSettings withPrefix(String prefix) {
@ -212,17 +274,27 @@ public class SSLConfigurationSettings {
return new SSLConfigurationSettings(prefix);
}
public static Collection<Setting<?>> getProfileSettings() {
return Arrays.asList(CIPHERS_SETTING_PROFILES, SUPPORTED_PROTOCOLS_PROFILES, KEYSTORE_PATH_PROFILES,
LEGACY_KEYSTORE_PASSWORD_PROFILES, KEYSTORE_PASSWORD_PROFILES, LEGACY_KEYSTORE_KEY_PASSWORD_PROFILES,
KEYSTORE_KEY_PASSWORD_PROFILES, TRUST_STORE_PATH_PROFILES, LEGACY_TRUSTSTORE_PASSWORD_PROFILES,
TRUSTSTORE_PASSWORD_PROFILES, KEY_STORE_ALGORITHM_PROFILES, TRUST_STORE_ALGORITHM_PROFILES,
KEY_STORE_TYPE_PROFILES, TRUST_STORE_TYPE_PROFILES, TRUST_RESTRICTIONS_PROFILES,
KEY_PATH_PROFILES, LEGACY_KEY_PASSWORD_PROFILES, KEY_PASSWORD_PROFILES,CERT_PROFILES,CAPATH_SETTING_PROFILES,
KEY_PATH_PROFILES, LEGACY_KEY_PASSWORD_PROFILES, KEY_PASSWORD_PROFILES, CERT_PROFILES, CAPATH_SETTING_PROFILES,
CLIENT_AUTH_SETTING_PROFILES, VERIFICATION_MODE_SETTING_PROFILES);
}
public static Collection<Setting.AffixSetting<?>> getRealmSettings(String realmType) {
return Stream.of(CIPHERS_SETTING_REALM, SUPPORTED_PROTOCOLS_REALM, KEYSTORE_PATH_REALM,
LEGACY_KEYSTORE_PASSWORD_REALM, KEYSTORE_PASSWORD_REALM, LEGACY_KEYSTORE_KEY_PASSWORD_REALM,
KEYSTORE_KEY_PASSWORD_REALM, TRUST_STORE_PATH_REALM, LEGACY_TRUST_STORE_PASSWORD_REALM,
TRUST_STORE_PASSWORD_REALM, KEY_STORE_ALGORITHM_REALM, TRUST_STORE_ALGORITHM_REALM,
KEY_STORE_TYPE_REALM, TRUST_STORE_TYPE_REALM, TRUST_RESTRICTIONS_REALM,
KEY_PATH_REALM, LEGACY_KEY_PASSWORD_REALM, KEY_PASSWORD_REALM, CERT_REALM, CAPATH_SETTING_REALM,
CLIENT_AUTH_SETTING_REALM, VERIFICATION_MODE_SETTING_REALM)
.map(f -> f.apply(realmType)).collect(Collectors.toList());
}
public List<Setting<SecureString>> getSecureSettingsInUse(Settings settings) {
return Stream.of(this.truststorePassword, this.x509KeyPair.keystorePassword,
this.x509KeyPair.keystoreKeyPassword, this.x509KeyPair.keyPassword)

View File

@ -17,7 +17,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.common.socket.SocketAccess;
import org.elasticsearch.xpack.core.security.SecurityField;
import org.elasticsearch.xpack.core.ssl.cert.CertificateInfo;
import javax.net.ssl.HostnameVerifier;
@ -186,9 +185,9 @@ public class SSLService {
* not expose any of the parameters that you give it.
*
* @param sslContext SSL Context used to handle SSL / TCP requests
* @param protocols Supported protocols
* @param ciphers Supported ciphers
* @param verifier Hostname verifier
* @param protocols Supported protocols
* @param ciphers Supported ciphers
* @param verifier Hostname verifier
* @return Never {@code null}.
*/
SSLIOSessionStrategy sslIOSessionStrategy(SSLContext sslContext, String[] protocols, String[] ciphers, HostnameVerifier verifier) {
@ -211,10 +210,11 @@ public class SSLService {
* Creates an {@link SSLEngine} based on the provided configuration. This SSLEngine can be used for a connection that requires
* hostname verification assuming the provided
* host and port are correct. The SSLEngine created by this method is most useful for clients with hostname verification enabled
*
* @param configuration the ssl configuration
* @param host the host of the remote endpoint. If using hostname verification, this should match what is in the remote endpoint's
* certificate
* @param port the port of the remote endpoint
* @param host the host of the remote endpoint. If using hostname verification, this should match what is in the remote
* endpoint's certificate
* @param port the port of the remote endpoint
* @return {@link SSLEngine}
* @see #getSSLConfiguration(String)
*/
@ -243,6 +243,7 @@ public class SSLService {
/**
* Returns whether the provided settings results in a valid configuration that can be used for server connections
*
* @param sslConfiguration the configuration to check
*/
public boolean isConfigurationValidForServerUsage(SSLConfiguration sslConfiguration) {
@ -274,6 +275,7 @@ public class SSLService {
/**
* Returns the existing {@link SSLContextHolder} for the configuration
*
* @throws IllegalArgumentException if not found
*/
SSLContextHolder sslContextHolder(SSLConfiguration sslConfiguration) {
@ -287,6 +289,7 @@ public class SSLService {
/**
* Returns the existing {@link SSLConfiguration} for the given settings
*
* @param settings the settings for the ssl configuration
* @return the ssl configuration for the provided settings. If the settings are empty, the global configuration is returned
*/
@ -314,6 +317,7 @@ public class SSLService {
/**
* Returns the intersection of the supported ciphers with the requested ciphers. This method will also optionally log if unsupported
* ciphers were requested.
*
* @throws IllegalArgumentException if no supported ciphers are in the requested ciphers
*/
String[] supportedCiphers(String[] supportedCiphers, List<String> requestedCiphers, boolean log) {
@ -351,6 +355,7 @@ public class SSLService {
/**
* Creates an {@link SSLContext} based on the provided configuration
*
* @param sslConfiguration the configuration to use for context creation
* @return the created SSLContext
*/
@ -365,9 +370,10 @@ public class SSLService {
/**
* Creates an {@link SSLContext} based on the provided configuration and trust/key managers
*
* @param sslConfiguration the configuration to use for context creation
* @param keyManager the key manager to use
* @param trustManager the trust manager to use
* @param keyManager the key manager to use
* @param trustManager the trust manager to use
* @return the created SSLContext
*/
private SSLContextHolder createSslContext(X509ExtendedKeyManager keyManager, X509ExtendedTrustManager trustManager,
@ -375,7 +381,7 @@ public class SSLService {
// Initialize sslContext
try {
SSLContext sslContext = SSLContext.getInstance(sslContextAlgorithm(sslConfiguration.supportedProtocols()));
sslContext.init(new X509ExtendedKeyManager[] { keyManager }, new X509ExtendedTrustManager[] { trustManager }, null);
sslContext.init(new X509ExtendedKeyManager[]{keyManager}, new X509ExtendedTrustManager[]{trustManager}, null);
// check the supported ciphers and log them here to prevent spamming logs on every call
supportedCiphers(sslContext.getSupportedSSLParameters().getCipherSuites(), sslConfiguration.cipherSuites(), true);
@ -439,6 +445,7 @@ public class SSLService {
* certificates that are provided by the JRE.
* Due to the nature of KeyStores, this may include certificates that are available, but never used
* such as a CA certificate that is no longer in use, or a server certificate for an unrelated host.
*
* @see TrustConfig#certificates(Environment)
*/
public Set<CertificateInfo> getLoadedCertificates() throws GeneralSecurityException, IOException {
@ -499,14 +506,14 @@ public class SSLService {
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
SSLSocket sslSocket = createWithPermissions(() -> delegate.createSocket(host, port, localHost, localPort));
SSLSocket sslSocket = createWithPermissions(() -> delegate.createSocket(host, port, localHost, localPort));
configureSSLSocket(sslSocket);
return sslSocket;
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
SSLSocket sslSocket = createWithPermissions(() -> delegate.createSocket(host, port));
SSLSocket sslSocket = createWithPermissions(() -> delegate.createSocket(host, port));
configureSSLSocket(sslSocket);
return sslSocket;
}
@ -609,14 +616,16 @@ public class SSLService {
* @return A map of Settings prefix to Settings object
*/
private static Map<String, Settings> getRealmsSSLSettings(Settings settings) {
Map<String, Settings> sslSettings = new HashMap<>();
final String prefix = SecurityField.setting("authc.realms.");
Settings realmsSettings = settings.getByPrefix(prefix);
for (String name : realmsSettings.names()) {
Settings realmSSLSettings = realmsSettings.getAsSettings(name).getByPrefix("ssl.");
// Put this even if empty, so that the name will be mapped to the global SSL configuration
sslSettings.put(prefix + name + ".ssl", realmSSLSettings);
}
final Map<String, Settings> sslSettings = new HashMap<>();
final String prefix = "xpack.security.authc.realms.";
final Map<String, Settings> settingsByRealmType = settings.getGroups(prefix);
settingsByRealmType.forEach((realmType, typeSettings) ->
typeSettings.getAsGroups().forEach((realmName, realmSettings) -> {
Settings realmSSLSettings = realmSettings.getByPrefix("ssl.");
// Put this even if empty, so that the name will be mapped to the global SSL configuration
sslSettings.put(prefix + realmType + "." + realmName + ".ssl", realmSSLSettings);
})
);
return sslSettings;
}

View File

@ -11,13 +11,13 @@ import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.util.CollectionUtils;
import javax.net.ssl.KeyManagerFactory;
import java.security.KeyStore;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* An encapsulation of the configuration options for X.509 Key Pair support in X-Pack security.
@ -61,8 +61,6 @@ public class X509KeyPairSettings {
"key_passphrase")));
private final String prefix;
// Specify private cert/key pair via keystore
final Setting<Optional<String>> keystorePath;
final Setting<SecureString> keystorePassword;
@ -83,21 +81,24 @@ public class X509KeyPairSettings {
private final List<Setting<?>> allSettings;
public X509KeyPairSettings(String prefix, boolean acceptNonSecurePasswords) {
keystorePath = KEYSTORE_PATH_TEMPLATE.apply(prefix + "keystore.path");
keystorePassword = KEYSTORE_PASSWORD_TEMPLATE.apply(prefix + "keystore.secure_password");
keystoreAlgorithm = KEY_STORE_ALGORITHM_TEMPLATE.apply(prefix + "keystore.algorithm");
keystoreType = KEY_STORE_TYPE_TEMPLATE.apply(prefix + "keystore.type");
keystoreKeyPassword = KEYSTORE_KEY_PASSWORD_TEMPLATE.apply(prefix + "keystore.secure_key_password");
private interface SettingFactory {
<T> Setting<T> apply(String keyPart, Function<String, Setting<T>> template);
}
keyPath = KEY_PATH_TEMPLATE.apply(prefix + "key");
keyPassword = KEY_PASSWORD_TEMPLATE.apply(prefix + "secure_key_passphrase");
certificatePath = CERT_TEMPLATE.apply(prefix + "certificate");
private X509KeyPairSettings(boolean acceptNonSecurePasswords, SettingFactory factory) {
keystorePath = factory.apply("keystore.path", KEYSTORE_PATH_TEMPLATE);
keystorePassword = factory.apply("keystore.secure_password", KEYSTORE_PASSWORD_TEMPLATE);
keystoreAlgorithm = factory.apply("keystore.algorithm", KEY_STORE_ALGORITHM_TEMPLATE);
keystoreType = factory.apply("keystore.type", KEY_STORE_TYPE_TEMPLATE);
keystoreKeyPassword = factory.apply("keystore.secure_key_password", KEYSTORE_KEY_PASSWORD_TEMPLATE);
legacyKeystorePassword = LEGACY_KEYSTORE_PASSWORD_TEMPLATE.apply(prefix + "keystore.password");
legacyKeystoreKeyPassword = LEGACY_KEYSTORE_KEY_PASSWORD_TEMPLATE.apply(prefix + "keystore.key_password");
legacyKeyPassword = LEGACY_KEY_PASSWORD_TEMPLATE.apply(prefix + "key_passphrase");
this.prefix = prefix;
keyPath = factory.apply("key", KEY_PATH_TEMPLATE);
keyPassword = factory.apply("secure_key_passphrase", KEY_PASSWORD_TEMPLATE);
certificatePath = factory.apply("certificate", CERT_TEMPLATE);
legacyKeystorePassword = factory.apply("keystore.password", LEGACY_KEYSTORE_PASSWORD_TEMPLATE);
legacyKeystoreKeyPassword = factory.apply("keystore.key_password", LEGACY_KEYSTORE_KEY_PASSWORD_TEMPLATE);
legacyKeyPassword = factory.apply("key_passphrase", LEGACY_KEY_PASSWORD_TEMPLATE);
final List<Setting<?>> settings = CollectionUtils.arrayAsArrayList(
keystorePath, keystorePassword, keystoreAlgorithm, keystoreType, keystoreKeyPassword,
@ -110,12 +111,26 @@ public class X509KeyPairSettings {
allSettings = Collections.unmodifiableList(settings);
}
public static X509KeyPairSettings withPrefix(String prefix, boolean acceptNonSecurePasswords) {
return new X509KeyPairSettings(acceptNonSecurePasswords, new SettingFactory() {
@Override
public <T> Setting<T> apply(String key, Function<String, Setting<T>> template) {
return template.apply(prefix + key);
}
});
}
public Collection<? extends Setting<?>> getAllSettings() {
public static Collection<Setting.AffixSetting<?>> affix(String prefix, String suffixPart, boolean acceptNonSecurePasswords) {
final X509KeyPairSettings settings = new X509KeyPairSettings(acceptNonSecurePasswords, new SettingFactory() {
@Override
public <T> Setting<T> apply(String keyPart, Function<String, Setting<T>> template) {
return Setting.affixKeySetting(prefix, suffixPart + keyPart, template);
}
});
return settings.getAllSettings().stream().map(s -> (Setting.AffixSetting<?>) s).collect(Collectors.toList());
}
public Collection<Setting<?>> getAllSettings() {
return allSettings;
}
public String getPrefix() {
return prefix;
}
}

View File

@ -496,8 +496,8 @@ public class SSLServiceTests extends ESTestCase {
"transport.profiles.prof1.xpack.security.ssl",
"transport.profiles.prof2.xpack.security.ssl",
"transport.profiles.prof3.xpack.security.ssl",
"xpack.security.authc.realms.realm1.ssl",
"xpack.security.authc.realms.realm2.ssl",
"xpack.security.authc.realms.ldap.realm1.ssl",
"xpack.security.authc.realms.saml.realm2.ssl",
"xpack.monitoring.exporters.mon1.ssl",
"xpack.monitoring.exporters.mon2.ssl"
};
@ -518,7 +518,7 @@ public class SSLServiceTests extends ESTestCase {
final Settings settings = builder
// Add a realm without SSL settings. This context name should be mapped to the global configuration
.put("xpack.security.authc.realms.realm3.type", "file")
.put("xpack.security.authc.realms.file.realm3.order", 4)
// Add an exporter without SSL settings. This context name should be mapped to the global configuration
.put("xpack.monitoring.exporters.mon3.type", "http")
.setSecureSettings(secureSettings)
@ -538,7 +538,7 @@ public class SSLServiceTests extends ESTestCase {
// These contexts have no SSL settings, but for convenience we want those components to be able to access their context
// by name, and get back the global configuration
final SSLConfiguration realm3Config = sslService.getSSLConfiguration("xpack.security.authc.realms.realm3.ssl");
final SSLConfiguration realm3Config = sslService.getSSLConfiguration("xpack.security.authc.realms.file.realm3.ssl");
final SSLConfiguration mon3Config = sslService.getSSLConfiguration("xpack.monitoring.exporters.mon3.ssl.");
final SSLConfiguration global = globalConfiguration(sslService);
assertThat(realm3Config, sameInstance(global));
@ -560,8 +560,7 @@ public class SSLServiceTests extends ESTestCase {
.put("xpack.ssl.keystore.path", jksPath)
.put("xpack.ssl.truststore.path", jksPath)
.put("xpack.http.ssl.keystore.path", p12Path)
.put("xpack.security.authc.realms.ad.type", "ad")
.put("xpack.security.authc.realms.ad.ssl.certificate_authorities", pemPath)
.put("xpack.security.authc.realms.active_directory.ad.ssl.certificate_authorities", pemPath)
.setSecureSettings(secureSettings)
.build();

View File

@ -9,6 +9,7 @@ import org.elasticsearch.bootstrap.BootstrapCheck;
import org.elasticsearch.bootstrap.BootstrapContext;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.pki.PkiRealmSettings;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
@ -16,6 +17,7 @@ import org.elasticsearch.xpack.core.ssl.SSLService;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.xpack.core.XPackSettings.HTTP_SSL_ENABLED;
import static org.elasticsearch.xpack.core.security.SecurityField.setting;
@ -35,8 +37,10 @@ class PkiRealmBootstrapCheck implements BootstrapCheck {
@Override
public BootstrapCheckResult check(BootstrapContext context) {
final Settings settings = context.settings;
final boolean pkiRealmEnabled = settings.getGroups(RealmSettings.PREFIX).values().stream()
.filter(s -> PkiRealmSettings.TYPE.equals(s.get("type")))
final Map<RealmConfig.RealmIdentifier, Settings> realms = RealmSettings.getRealmSettings(settings);
final boolean pkiRealmEnabled = realms.entrySet().stream()
.filter(e -> PkiRealmSettings.TYPE.equals(e.getKey().getType()))
.map(Map.Entry::getValue)
.anyMatch(s -> s.getAsBoolean("enabled", true));
if (pkiRealmEnabled) {
for (String contextName : getSslContextNames(settings)) {

View File

@ -113,8 +113,8 @@ import org.elasticsearch.xpack.core.security.action.user.SetEnabledAction;
import org.elasticsearch.xpack.core.security.authc.AuthenticationFailureHandler;
import org.elasticsearch.xpack.core.security.authc.AuthenticationServiceField;
import org.elasticsearch.xpack.core.security.authc.DefaultAuthenticationFailureHandler;
import org.elasticsearch.xpack.core.security.authc.InternalRealmsSettings;
import org.elasticsearch.xpack.core.security.authc.Realm;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.authz.AuthorizationServiceField;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
@ -607,7 +607,7 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
// authentication and authorization settings
AnonymousUser.addSettings(settingsList);
RealmSettings.addSettings(settingsList, securityExtensions);
settingsList.addAll(InternalRealmsSettings.getSettings());
NativeRolesStore.addSettings(settingsList);
ReservedRealm.addSettings(settingsList);
AuthenticationService.addSettings(settingsList);
@ -644,7 +644,6 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
public List<String> getSettingsFilter() {
List<String> asArray = settings.getAsList(SecurityField.setting("hide_settings"));
ArrayList<String> settingsFilter = new ArrayList<>(asArray);
settingsFilter.addAll(RealmSettings.getSettingsFilter(securityExtensions));
// hide settings where we don't define them - they are part of a group...
settingsFilter.add("transport.profiles.*." + SecurityField.setting("*"));
return settingsFilter;

View File

@ -33,12 +33,13 @@ import org.elasticsearch.xpack.security.authc.support.RoleMappingFileBootstrapCh
import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Provides a single entry point into dealing with all standard XPack security {@link Realm realms}.
@ -98,9 +99,9 @@ public final class InternalRealms {
securityIndex.addIndexStateListener(nativeRealm::onSecurityIndexStateChange);
return nativeRealm;
});
map.put(LdapRealmSettings.AD_TYPE, config -> new LdapRealm(LdapRealmSettings.AD_TYPE, config, sslService,
map.put(LdapRealmSettings.AD_TYPE, config -> new LdapRealm(config, sslService,
resourceWatcherService, nativeRoleMappingStore, threadPool));
map.put(LdapRealmSettings.LDAP_TYPE, config -> new LdapRealm(LdapRealmSettings.LDAP_TYPE, config,
map.put(LdapRealmSettings.LDAP_TYPE, config -> new LdapRealm(config,
sslService, resourceWatcherService, nativeRoleMappingStore, threadPool));
map.put(PkiRealmSettings.TYPE, config -> new PkiRealm(config, resourceWatcherService, nativeRoleMappingStore));
map.put(SamlRealmSettings.TYPE, config -> SamlRealm.create(config, sslService, resourceWatcherService, nativeRoleMappingStore));
@ -112,20 +113,14 @@ public final class InternalRealms {
}
public static List<BootstrapCheck> getBootstrapChecks(final Settings globalSettings, final Environment env) {
final List<BootstrapCheck> checks = new ArrayList<>();
final Map<String, Settings> settingsByRealm = RealmSettings.getRealmSettings(globalSettings);
settingsByRealm.forEach((name, settings) -> {
final RealmConfig realmConfig = new RealmConfig(name, settings, globalSettings, env, null);
switch (realmConfig.type()) {
case LdapRealmSettings.AD_TYPE:
case LdapRealmSettings.LDAP_TYPE:
case PkiRealmSettings.TYPE:
final BootstrapCheck check = RoleMappingFileBootstrapCheck.create(realmConfig);
if (check != null) {
checks.add(check);
}
}
});
final Set<String> realmTypes = Sets.newHashSet(LdapRealmSettings.AD_TYPE, LdapRealmSettings.LDAP_TYPE, PkiRealmSettings.TYPE);
final List<BootstrapCheck> checks = RealmSettings.getRealmSettings(globalSettings)
.keySet().stream()
.filter(id -> realmTypes.contains(id.getType()))
.map(id -> new RealmConfig(id, globalSettings, env, null))
.map(RoleMappingFileBootstrapCheck::create)
.filter(Objects::nonNull)
.collect(Collectors.toList());
return checks;
}
}

View File

@ -22,6 +22,7 @@ import java.util.stream.StreamSupport;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.settings.Settings;
@ -34,10 +35,9 @@ import org.elasticsearch.xpack.core.security.authc.Realm;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.esnative.NativeRealmSettings;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.core.security.authc.file.FileRealmSettings;
import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
/**
* Serves as a realms registry (also responsible for ordering the realms appropriately)
@ -155,41 +155,37 @@ public class Realms implements Iterable<Realm> {
}
protected List<Realm> initRealms() throws Exception {
Settings realmsSettings = RealmSettings.get(settings);
Map<RealmConfig.RealmIdentifier, Settings> realmsSettings = RealmSettings.getRealmSettings(settings);
Set<String> internalTypes = new HashSet<>();
List<Realm> realms = new ArrayList<>();
List<String> kerberosRealmNames = new ArrayList<>();
for (String name : realmsSettings.names()) {
Settings realmSettings = realmsSettings.getAsSettings(name);
String type = realmSettings.get("type");
if (type == null) {
throw new IllegalArgumentException("missing realm type for [" + name + "] realm");
}
Realm.Factory factory = factories.get(type);
for (RealmConfig.RealmIdentifier identifier: realmsSettings.keySet()) {
Realm.Factory factory = factories.get(identifier.getType());
if (factory == null) {
throw new IllegalArgumentException("unknown realm type [" + type + "] set for realm [" + name + "]");
throw new IllegalArgumentException("unknown realm type [" + identifier.getType() + "] for realm [" + identifier + "]");
}
RealmConfig config = new RealmConfig(name, realmSettings, settings, env, threadContext);
RealmConfig config = new RealmConfig(identifier, settings, env, threadContext);
if (!config.enabled()) {
if (logger.isDebugEnabled()) {
logger.debug("realm [{}/{}] is disabled", type, name);
logger.debug("realm [{}] is disabled", identifier);
}
continue;
}
if (FileRealmSettings.TYPE.equals(type) || NativeRealmSettings.TYPE.equals(type)) {
if (FileRealmSettings.TYPE.equals(identifier.getType()) || NativeRealmSettings.TYPE.equals(identifier.getType())) {
// this is an internal realm factory, let's make sure we didn't already registered one
// (there can only be one instance of an internal realm)
if (internalTypes.contains(type)) {
throw new IllegalArgumentException("multiple [" + type + "] realms are configured. [" + type +
"] is an internal realm and therefore there can only be one such realm configured");
if (internalTypes.contains(identifier.getType())) {
throw new IllegalArgumentException("multiple [" + identifier.getType() + "] realms are configured. ["
+ identifier.getType() + "] is an internal realm and therefore there can only be one such realm configured");
}
internalTypes.add(type);
internalTypes.add(identifier.getType());
}
if (KerberosRealmSettings.TYPE.equals(type)) {
kerberosRealmNames.add(name);
if (KerberosRealmSettings.TYPE.equals(identifier.getType())) {
kerberosRealmNames.add(identifier.getName());
if (kerberosRealmNames.size() > 1) {
throw new IllegalArgumentException("multiple realms " + kerberosRealmNames.toString() + " configured of type [" + type
+ "], [" + type + "] can only have one such realm configured");
throw new IllegalArgumentException("multiple realms " + kerberosRealmNames.toString() + " configured of type ["
+ identifier.getType() + "], [" + identifier.getType() + "] can only have one such realm " +
"configured");
}
}
realms.add(factory.create(config));
@ -272,13 +268,14 @@ public class Realms implements Iterable<Realm> {
private void addNativeRealms(List<Realm> realms) throws Exception {
Realm.Factory fileRealm = factories.get(FileRealmSettings.TYPE);
if (fileRealm != null) {
realms.add(fileRealm.create(new RealmConfig("default_" + FileRealmSettings.TYPE, Settings.EMPTY,
realms.add(fileRealm.create(new RealmConfig(
new RealmConfig.RealmIdentifier(FileRealmSettings.TYPE, "default_" + FileRealmSettings.TYPE),
settings, env, threadContext)));
}
Realm.Factory indexRealmFactory = factories.get(NativeRealmSettings.TYPE);
if (indexRealmFactory != null) {
realms.add(indexRealmFactory.create(new RealmConfig("default_" + NativeRealmSettings.TYPE, Settings.EMPTY,
realms.add(indexRealmFactory.create(new RealmConfig(
new RealmConfig.RealmIdentifier(NativeRealmSettings.TYPE, "default_" + NativeRealmSettings.TYPE),
settings, env, threadContext)));
}
}

View File

@ -9,7 +9,6 @@ import org.elasticsearch.action.ActionListener;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.esnative.NativeRealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
@ -28,7 +27,7 @@ public class NativeRealm extends CachingUsernamePasswordRealm {
private final NativeUsersStore userStore;
public NativeRealm(RealmConfig config, NativeUsersStore usersStore, ThreadPool threadPool) {
super(NativeRealmSettings.TYPE, config, threadPool);
super(config, threadPool);
this.userStore = usersStore;
}

View File

@ -68,7 +68,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
public ReservedRealm(Environment env, Settings settings, NativeUsersStore nativeUsersStore, AnonymousUser anonymousUser,
SecurityIndexManager securityIndex, ThreadPool threadPool) {
super(TYPE, new RealmConfig(TYPE, Settings.EMPTY, settings, env, threadPool.getThreadContext()), threadPool);
super(new RealmConfig(new RealmConfig.RealmIdentifier(TYPE, TYPE), settings, env, threadPool.getThreadContext()), threadPool);
this.nativeUsersStore = nativeUsersStore;
this.realmEnabled = XPackSettings.RESERVED_REALM_ENABLED_SETTING.get(settings);
this.anonymousUser = anonymousUser;

View File

@ -10,7 +10,6 @@ import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.file.FileRealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
@ -28,7 +27,7 @@ public class FileRealm extends CachingUsernamePasswordRealm {
// pkg private for testing
FileRealm(RealmConfig config, FileUserPasswdStore userPasswdStore, FileUserRolesStore userRolesStore, ThreadPool threadPool) {
super(FileRealmSettings.TYPE, config, threadPool);
super(config, threadPool);
this.userPasswdStore = userPasswdStore;
userPasswdStore.addListener(this::expireAll);
this.userRolesStore = userRolesStore;

View File

@ -79,22 +79,22 @@ public final class KerberosRealm extends Realm implements CachingRealm {
KerberosRealm(final RealmConfig config, final NativeRoleMappingStore nativeRoleMappingStore,
final KerberosTicketValidator kerberosTicketValidator, final ThreadPool threadPool,
final Cache<String, User> userPrincipalNameToUserCache) {
super(KerberosRealmSettings.TYPE, config);
super(config);
this.userRoleMapper = nativeRoleMappingStore;
this.userRoleMapper.refreshRealmOnChange(this);
final TimeValue ttl = KerberosRealmSettings.CACHE_TTL_SETTING.get(config.settings());
final TimeValue ttl = config.getSetting(KerberosRealmSettings.CACHE_TTL_SETTING);
if (ttl.getNanos() > 0) {
this.userPrincipalNameToUserCache = (userPrincipalNameToUserCache == null)
? CacheBuilder.<String, User>builder()
.setExpireAfterWrite(KerberosRealmSettings.CACHE_TTL_SETTING.get(config.settings()))
.setMaximumWeight(KerberosRealmSettings.CACHE_MAX_USERS_SETTING.get(config.settings())).build()
.setExpireAfterWrite(config.getSetting(KerberosRealmSettings.CACHE_TTL_SETTING))
.setMaximumWeight(config.getSetting(KerberosRealmSettings.CACHE_MAX_USERS_SETTING)).build()
: userPrincipalNameToUserCache;
} else {
this.userPrincipalNameToUserCache = null;
}
this.kerberosTicketValidator = kerberosTicketValidator;
this.threadPool = threadPool;
this.keytabPath = config.env().configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(config.settings()));
this.keytabPath = config.env().configFile().resolve(config.getSetting(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH));
if (Files.exists(keytabPath) == false) {
throw new IllegalArgumentException("configured service key tab file [" + keytabPath + "] does not exist");
@ -105,8 +105,9 @@ public final class KerberosRealm extends Realm implements CachingRealm {
if (Files.isReadable(keytabPath) == false) {
throw new IllegalArgumentException("configured service key tab file [" + keytabPath + "] must have read permission");
}
this.enableKerberosDebug = KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.get(config.settings());
this.removeRealmName = KerberosRealmSettings.SETTING_REMOVE_REALM_NAME.get(config.settings());
this.enableKerberosDebug = config.getSetting(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE);
this.removeRealmName = config.getSetting(KerberosRealmSettings.SETTING_REMOVE_REALM_NAME);
this.delegatedRealms = null;
}

View File

@ -13,8 +13,10 @@ import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SearchScope;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.ldap.ActiveDirectorySessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.SearchGroupsResolverSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver;
@ -24,13 +26,12 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import static org.elasticsearch.xpack.core.security.authc.ldap.ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING;
import static org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySIDUtil.convertToString;
import static org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactory.buildDnFromDomain;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.OBJECT_CLASS_PRESENCE_FILTER;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.search;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.searchForEntry;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING;
import static org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySIDUtil.convertToString;
class ActiveDirectoryGroupsResolver implements GroupsResolver {
@ -39,10 +40,11 @@ class ActiveDirectoryGroupsResolver implements GroupsResolver {
private final LdapSearchScope scope;
private final boolean ignoreReferralErrors;
ActiveDirectoryGroupsResolver(Settings settings) {
this.baseDn = settings.get("group_search.base_dn", buildDnFromDomain(settings.get(AD_DOMAIN_NAME_SETTING)));
this.scope = LdapSearchScope.resolve(settings.get("group_search.scope"), LdapSearchScope.SUB_TREE);
this.ignoreReferralErrors = IGNORE_REFERRAL_ERRORS_SETTING.get(settings);
ActiveDirectoryGroupsResolver(RealmConfig config) {
this.baseDn = config.getSetting(SearchGroupsResolverSettings.BASE_DN,
() -> buildDnFromDomain(config.getSetting(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING)));
this.scope = config.getSetting(SearchGroupsResolverSettings.SCOPE);
this.ignoreReferralErrors = config.getSetting(IGNORE_REFERRAL_ERRORS_SETTING);
}
@Override

View File

@ -22,7 +22,7 @@ import org.elasticsearch.common.cache.Cache;
import org.elasticsearch.common.cache.CacheBuilder;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.core.internal.io.IOUtils;
@ -64,30 +64,30 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
final UpnADAuthenticator upnADAuthenticator;
ActiveDirectorySessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) throws LDAPException {
super(config, sslService, new ActiveDirectoryGroupsResolver(config.settings()),
super(config, sslService, new ActiveDirectoryGroupsResolver(config),
ActiveDirectorySessionFactorySettings.POOL_ENABLED,
PoolingSessionFactorySettings.BIND_DN.exists(config.settings())? getBindDN(config.settings()) : null,
config.hasSetting(PoolingSessionFactorySettings.BIND_DN) ? getBindDN(config) : null,
() -> {
if (PoolingSessionFactorySettings.BIND_DN.exists(config.settings())) {
final String healthCheckDn = PoolingSessionFactorySettings.BIND_DN.get(config.settings());
if (config.hasSetting(PoolingSessionFactorySettings.BIND_DN)) {
final String healthCheckDn = config.getSetting(PoolingSessionFactorySettings.BIND_DN);
if (healthCheckDn.isEmpty() && healthCheckDn.indexOf('=') > 0) {
return healthCheckDn;
}
}
return config.settings().get(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_BASEDN_SETTING,
config.settings().get(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING));
return config.getSetting(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_BASEDN_SETTING,
() -> config.getSetting(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING));
}, threadPool);
Settings settings = config.settings();
String domainName = settings.get(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING);
String domainName = config.getSetting(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING);
if (domainName == null) {
throw new IllegalArgumentException("missing [" + ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING
throw new IllegalArgumentException("missing [" +
RealmSettings.getFullSettingKey(config, ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING)
+ "] setting for active directory");
}
String domainDN = buildDnFromDomain(domainName);
final int ldapPort = ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING.get(settings);
final int ldapsPort = ActiveDirectorySessionFactorySettings.AD_LDAPS_PORT_SETTING.get(settings);
final int gcLdapPort = ActiveDirectorySessionFactorySettings.AD_GC_LDAP_PORT_SETTING.get(settings);
final int gcLdapsPort = ActiveDirectorySessionFactorySettings.AD_GC_LDAPS_PORT_SETTING.get(settings);
final int ldapPort = config.getSetting(ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING);
final int ldapsPort = config.getSetting(ActiveDirectorySessionFactorySettings.AD_LDAPS_PORT_SETTING);
final int gcLdapPort = config.getSetting(ActiveDirectorySessionFactorySettings.AD_GC_LDAP_PORT_SETTING);
final int gcLdapsPort = config.getSetting(ActiveDirectorySessionFactorySettings.AD_GC_LDAPS_PORT_SETTING);
defaultADAuthenticator = new DefaultADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver,
metaDataResolver, domainDN, threadPool);
@ -99,9 +99,9 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
}
@Override
protected List<String> getDefaultLdapUrls(Settings settings) {
return Collections.singletonList("ldap://" + settings.get(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING) +
":" + ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING.get(settings));
protected List<String> getDefaultLdapUrls(RealmConfig config) {
return Collections.singletonList("ldap://" + config.getSetting(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING) +
":" + config.getSetting(ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING));
}
@Override
@ -143,7 +143,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
@Override
void getUnauthenticatedSessionWithoutPool(String user, ActionListener<LdapSession> listener) {
if (PoolingSessionFactorySettings.BIND_DN.exists(config.settings()) == false) {
if (config.hasSetting(PoolingSessionFactorySettings.BIND_DN) == false) {
listener.onResponse(null);
return;
}
@ -188,10 +188,10 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
return "DC=" + domain.replace(".", ",DC=");
}
static String getBindDN(Settings settings) {
String bindDN = PoolingSessionFactorySettings.BIND_DN.get(settings);
static String getBindDN(RealmConfig config) {
String bindDN = config.getSetting(PoolingSessionFactorySettings.BIND_DN);
if (bindDN.isEmpty() == false && bindDN.indexOf('\\') < 0 && bindDN.indexOf('@') < 0 && bindDN.indexOf('=') < 0) {
bindDN = bindDN + "@" + settings.get(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING);
bindDN = bindDN + "@" + config.getSetting(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING);
}
return bindDN;
}
@ -226,22 +226,22 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
final ThreadPool threadPool;
ADAuthenticator(RealmConfig realm, TimeValue timeout, boolean ignoreReferralErrors, Logger logger, GroupsResolver groupsResolver,
LdapMetaDataResolver metaDataResolver, String domainDN, String userSearchFilterSetting, String defaultUserSearchFilter,
ThreadPool threadPool) {
LdapMetaDataResolver metaDataResolver, String domainDN, Setting.AffixSetting<String> userSearchFilterSetting,
String defaultUserSearchFilter, ThreadPool threadPool) {
this.realm = realm;
this.timeout = timeout;
this.ignoreReferralErrors = ignoreReferralErrors;
this.logger = logger;
this.groupsResolver = groupsResolver;
this.metaDataResolver = metaDataResolver;
final Settings settings = realm.settings();
this.bindDN = getBindDN(settings);
this.bindPassword = PoolingSessionFactorySettings.SECURE_BIND_PASSWORD.get(settings);
this.bindDN = getBindDN(realm);
this.bindPassword = realm.getSetting(PoolingSessionFactorySettings.SECURE_BIND_PASSWORD,
() -> realm.getSetting(PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD));
this.threadPool = threadPool;
userSearchDN = settings.get(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_BASEDN_SETTING, domainDN);
userSearchScope = LdapSearchScope.resolve(settings.get(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_SCOPE_SETTING),
userSearchDN = realm.getSetting(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_BASEDN_SETTING, () -> domainDN);
userSearchScope = LdapSearchScope.resolve(realm.getSetting(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_SCOPE_SETTING),
LdapSearchScope.SUB_TREE);
userSearchFilter = settings.get(userSearchFilterSetting, defaultUserSearchFilter);
userSearchFilter = realm.getSetting(userSearchFilterSetting, () -> defaultUserSearchFilter);
}
final void authenticate(LDAPConnection connection, String username, SecureString password, ActionListener<LdapSession> listener) {
@ -324,7 +324,8 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
final String domainName;
DefaultADAuthenticator(RealmConfig realm, TimeValue timeout, boolean ignoreReferralErrors, Logger logger,
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN, ThreadPool threadPool) {
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN,
ThreadPool threadPool) {
super(realm, timeout, ignoreReferralErrors, logger, groupsResolver, metaDataResolver, domainDN,
ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_FILTER_SETTING,
"(&(objectClass=user)(|(sAMAccountName={0})(userPrincipalName={0}@" + domainName(realm) + ")))", threadPool);
@ -332,7 +333,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
}
private static String domainName(RealmConfig realm) {
return realm.settings().get(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING);
return realm.getSetting(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING);
}
@Override
@ -363,7 +364,6 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
Cache<String, String> domainNameCache = CacheBuilder.<String, String>builder().setMaximumWeight(100).build();
final String domainDN;
final Settings settings;
final SSLService sslService;
final RealmConfig config;
private final int ldapPort;
@ -372,12 +372,12 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
private final int gcLdapsPort;
DownLevelADAuthenticator(RealmConfig config, TimeValue timeout, boolean ignoreReferralErrors, Logger logger,
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN, SSLService sslService,
ThreadPool threadPool, int ldapPort, int ldapsPort, int gcLdapPort, int gcLdapsPort) {
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN,
SSLService sslService, ThreadPool threadPool,
int ldapPort, int ldapsPort, int gcLdapPort, int gcLdapsPort) {
super(config, timeout, ignoreReferralErrors, logger, groupsResolver, metaDataResolver, domainDN,
ActiveDirectorySessionFactorySettings.AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING, DOWN_LEVEL_FILTER, threadPool);
this.domainDN = domainDN;
this.settings = config.settings();
this.sslService = sslService;
this.config = config;
this.ldapPort = ldapPort;
@ -457,7 +457,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
public void onFailure(Exception e) {
IOUtils.closeWhileHandlingException(searchConnection);
listener.onFailure(e);
};
}
});
}
} catch (LDAPException e) {
@ -519,7 +519,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
static final String UPN_USER_FILTER = "(&(objectClass=user)(userPrincipalName={1}))";
UpnADAuthenticator(RealmConfig config, TimeValue timeout, boolean ignoreReferralErrors, Logger logger,
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN, ThreadPool threadPool) {
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN, ThreadPool threadPool) {
super(config, timeout, ignoreReferralErrors, logger, groupsResolver, metaDataResolver, domainDN,
ActiveDirectorySessionFactorySettings.AD_UPN_USER_SEARCH_FILTER_SETTING, UPN_USER_FILTER, threadPool);
if (userSearchFilter.contains("{0}")) {

View File

@ -26,6 +26,7 @@ import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapSessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapUserSearchSessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.ssl.SSLService;
@ -56,43 +57,44 @@ public final class LdapRealm extends CachingUsernamePasswordRealm {
private final UserRoleMapper roleMapper;
private final ThreadPool threadPool;
private final TimeValue executionTimeout;
private DelegatedAuthorizationSupport delegatedRealms;
public LdapRealm(String type, RealmConfig config, SSLService sslService,
public LdapRealm(RealmConfig config, SSLService sslService,
ResourceWatcherService watcherService,
NativeRoleMappingStore nativeRoleMappingStore, ThreadPool threadPool)
throws LDAPException {
this(type, config, sessionFactory(config, sslService, threadPool, type),
new CompositeRoleMapper(type, config, watcherService, nativeRoleMappingStore),
this(config, sessionFactory(config, sslService, threadPool),
new CompositeRoleMapper(config, watcherService, nativeRoleMappingStore),
threadPool);
}
// pkg private for testing
LdapRealm(String type, RealmConfig config, SessionFactory sessionFactory,
LdapRealm(RealmConfig config, SessionFactory sessionFactory,
UserRoleMapper roleMapper, ThreadPool threadPool) {
super(type, config, threadPool);
super(config, threadPool);
this.sessionFactory = sessionFactory;
this.roleMapper = roleMapper;
this.threadPool = threadPool;
this.executionTimeout = LdapRealmSettings.EXECUTION_TIMEOUT.get(config.settings());
this.executionTimeout = config.getSetting(LdapRealmSettings.EXECUTION_TIMEOUT);
roleMapper.refreshRealmOnChange(this);
}
static SessionFactory sessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool, String type)
static SessionFactory sessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool)
throws LDAPException {
final SessionFactory sessionFactory;
if (LdapRealmSettings.AD_TYPE.equals(type)) {
if (LdapRealmSettings.AD_TYPE.equals(config.type())) {
sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
} else {
assert LdapRealmSettings.LDAP_TYPE.equals(type) : "type [" + type + "] is unknown. expected one of ["
assert LdapRealmSettings.LDAP_TYPE.equals(config.type()) : "type [" + config.type() + "] is unknown. expected one of ["
+ LdapRealmSettings.AD_TYPE + ", " + LdapRealmSettings.LDAP_TYPE + "]";
final boolean hasSearchSettings = LdapUserSearchSessionFactory.hasUserSearchSettings(config);
final boolean hasTemplates = LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING.exists(config.settings());
final boolean hasTemplates = config.hasSetting(LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING);
if (hasSearchSettings == false) {
if (hasTemplates == false) {
throw new IllegalArgumentException("settings were not found for either user search [" +
RealmSettings.getFullSettingKey(config, LdapUserSearchSessionFactory.SEARCH_PREFIX) +
RealmSettings.getFullSettingKey(config, LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN) +
"] or user template [" +
RealmSettings.getFullSettingKey(config, LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING) +
"] modes of operation. " +
@ -102,7 +104,7 @@ public final class LdapRealm extends CachingUsernamePasswordRealm {
sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
} else if (hasTemplates) {
throw new IllegalArgumentException("settings were found for both user search [" +
RealmSettings.getFullSettingKey(config, LdapUserSearchSessionFactory.SEARCH_PREFIX) +
RealmSettings.getFullSettingKey(config, LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN) +
"] and user template [" +
RealmSettings.getFullSettingKey(config, LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING) +
"] modes of operation. " +
@ -175,7 +177,7 @@ public final class LdapRealm extends CachingUsernamePasswordRealm {
public void usageStats(ActionListener<Map<String, Object>> listener) {
super.usageStats(ActionListener.wrap(usage -> {
usage.put("size", getCacheSize());
usage.put("load_balance_type", LdapLoadBalancing.resolve(config.settings()).toString());
usage.put("load_balance_type", LdapLoadBalancing.resolve(config).toString());
usage.put("ssl", sessionFactory.isSslUsed());
usage.put("user_search", LdapUserSearchSessionFactory.hasUserSearchSettings(config));
listener.onResponse(usage);

View File

@ -8,12 +8,11 @@ package org.elasticsearch.xpack.security.authc.ldap;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.SimpleBindRequest;
import org.elasticsearch.core.internal.io.IOUtils;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.core.internal.io.IOUtils;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
@ -46,15 +45,14 @@ public class LdapSessionFactory extends SessionFactory {
public LdapSessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) {
super(config, sslService, threadPool);
Settings settings = config.settings();
userDnTemplates = LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING.get(settings).toArray(Strings.EMPTY_ARRAY);
userDnTemplates = config.getSetting(LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING).toArray(Strings.EMPTY_ARRAY);
if (userDnTemplates.length == 0) {
throw new IllegalArgumentException("missing required LDAP setting ["
+ RealmSettings.getFullSettingKey(config, LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING) + "]");
}
logger.info("Realm [{}] is in user-dn-template mode: [{}]", config.name(), userDnTemplates);
groupResolver = groupResolver(settings);
metaDataResolver = new LdapMetaDataResolver(settings, ignoreReferralErrors);
groupResolver = groupResolver(config);
metaDataResolver = new LdapMetaDataResolver(config, ignoreReferralErrors);
}
/**
@ -123,11 +121,11 @@ public class LdapSessionFactory extends SessionFactory {
return new MessageFormat(template, Locale.ROOT).format(new Object[] { escapedUsername }, new StringBuffer(), null).toString();
}
static GroupsResolver groupResolver(Settings settings) {
if (SearchGroupsResolverSettings.BASE_DN.exists(settings)) {
return new SearchGroupsResolver(settings);
static GroupsResolver groupResolver(RealmConfig realmConfig) {
if (realmConfig.hasSetting(SearchGroupsResolverSettings.BASE_DN)) {
return new SearchGroupsResolver(realmConfig);
}
return new UserAttributeGroupsResolver(settings);
return new UserAttributeGroupsResolver(realmConfig);
}
}

View File

@ -15,7 +15,6 @@ import com.unboundid.ldap.sdk.SimpleBindRequest;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRunnable;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.core.internal.io.IOUtils;
import org.elasticsearch.threadpool.ThreadPool;
@ -30,6 +29,8 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils;
import java.util.stream.Stream;
import static org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings.BIND_DN;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.attributesToSearchFor;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.createFilter;
@ -44,30 +45,30 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
private final String searchFilter;
LdapUserSearchSessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) throws LDAPException {
super(config, sslService, groupResolver(config.settings()), LdapUserSearchSessionFactorySettings.POOL_ENABLED,
BIND_DN.exists(config.settings()) ? BIND_DN.get(config.settings()) : null,
super(config, sslService, groupResolver(config), LdapUserSearchSessionFactorySettings.POOL_ENABLED,
config.getSetting(BIND_DN, () -> null),
() -> config.getSetting(BIND_DN, () -> config.getSetting(LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN)),
threadPool);
userSearchBaseDn = config.getSetting(LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN,
() -> {
if (BIND_DN.exists(config.settings())) {
return BIND_DN.get(config.settings());
} else {
return LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN.get(config.settings());
}
}, threadPool);
Settings settings = config.settings();
if (LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN.exists(settings)) {
userSearchBaseDn = LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN.get(settings);
} else {
throw new IllegalArgumentException("[" + RealmSettings.getFullSettingKey(config,
LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN) + "] must be specified");
}
scope = LdapUserSearchSessionFactorySettings.SEARCH_SCOPE.get(settings);
throw new IllegalArgumentException("[" + RealmSettings.getFullSettingKey(config,
LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN) + "] must be specified");
}
);
scope = config.getSetting(LdapUserSearchSessionFactorySettings.SEARCH_SCOPE);
searchFilter = getSearchFilter(config);
logger.info("Realm [{}] is in user-search mode - base_dn=[{}], search filter=[{}]",
config.name(), userSearchBaseDn, searchFilter);
}
static boolean hasUserSearchSettings(RealmConfig config) {
return config.settings().getByPrefix("user_search.").isEmpty() == false;
return Stream.of(
LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN,
LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE,
LdapUserSearchSessionFactorySettings.SEARCH_SCOPE,
LdapUserSearchSessionFactorySettings.SEARCH_FILTER,
LdapUserSearchSessionFactorySettings.POOL_ENABLED
).anyMatch(config::hasSetting);
}
/**
@ -96,13 +97,13 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
/**
* Sets up a LDAPSession using the following process:
* <ol>
* <li>Opening a new connection to the LDAP server</li>
* <li>Executes a bind request using the bind user</li>
* <li>Executes a search to find the DN of the user</li>
* <li>Closes the opened connection</li>
* <li>Opens a new connection to the LDAP server</li>
* <li>Executes a bind request using the found DN and provided password</li>
* <li>Creates a new LDAPSession with the bound connection</li>
* <li>Opening a new connection to the LDAP server</li>
* <li>Executes a bind request using the bind user</li>
* <li>Executes a search to find the DN of the user</li>
* <li>Closes the opened connection</li>
* <li>Opens a new connection to the LDAP server</li>
* <li>Executes a bind request using the found DN and provided password</li>
* <li>Creates a new LDAPSession with the bound connection</li>
* </ol>
*/
@Override
@ -151,6 +152,7 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
listener.onFailure(e);
}));
}
@Override
public void onFailure(Exception e) {
IOUtils.closeWhileHandlingException(connection);
@ -227,17 +229,16 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
attributesToSearchFor(groupResolver.attributes(), metaDataResolver.attributeNames()));
}
private static GroupsResolver groupResolver(Settings settings) {
if (SearchGroupsResolverSettings.BASE_DN.exists(settings)) {
return new SearchGroupsResolver(settings);
private static GroupsResolver groupResolver(RealmConfig realmConfig) {
if (realmConfig.hasSetting(SearchGroupsResolverSettings.BASE_DN)) {
return new SearchGroupsResolver(realmConfig);
}
return new UserAttributeGroupsResolver(settings);
return new UserAttributeGroupsResolver(realmConfig);
}
static String getSearchFilter(RealmConfig config) {
final Settings settings = config.settings();
final boolean hasAttribute = LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE.exists(settings);
final boolean hasFilter = LdapUserSearchSessionFactorySettings.SEARCH_FILTER.exists(settings);
final boolean hasAttribute = config.hasSetting(LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE);
final boolean hasFilter = config.hasSetting(LdapUserSearchSessionFactorySettings.SEARCH_FILTER);
if (hasAttribute && hasFilter) {
throw new IllegalArgumentException("search attribute setting [" +
RealmSettings.getFullSettingKey(config, LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE)
@ -245,9 +246,9 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
RealmSettings.getFullSettingKey(config, LdapUserSearchSessionFactorySettings.SEARCH_FILTER)
+ "] cannot be combined!");
} else if (hasFilter) {
return LdapUserSearchSessionFactorySettings.SEARCH_FILTER.get(settings);
return config.getSetting(LdapUserSearchSessionFactorySettings.SEARCH_FILTER);
} else if (hasAttribute) {
return "(" + LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE.get(settings) + "={0})";
return "(" + config.getSetting(LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE) + "={0})";
} else {
return "(uid={0})";
}

View File

@ -19,7 +19,6 @@ import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.lease.Releasable;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
@ -60,23 +59,23 @@ abstract class PoolingSessionFactory extends SessionFactory implements Releasabl
* @param threadPool a thread pool used for async queries execution
*/
PoolingSessionFactory(RealmConfig config, SSLService sslService, LdapSession.GroupsResolver groupResolver,
Setting<Boolean> poolingEnabled, @Nullable String bindDn, Supplier<String> healthCheckDNSupplier,
Setting.AffixSetting<Boolean> poolingEnabled, @Nullable String bindDn, Supplier<String> healthCheckDNSupplier,
ThreadPool threadPool) throws LDAPException {
super(config, sslService, threadPool);
this.groupResolver = groupResolver;
this.metaDataResolver = new LdapMetaDataResolver(config.settings(), ignoreReferralErrors);
this.metaDataResolver = new LdapMetaDataResolver(config, ignoreReferralErrors);
final byte[] bindPassword;
if (LEGACY_BIND_PASSWORD.exists(config.settings())) {
if (SECURE_BIND_PASSWORD.exists(config.settings())) {
if (config.hasSetting(LEGACY_BIND_PASSWORD)) {
if (config.hasSetting(SECURE_BIND_PASSWORD)) {
throw new IllegalArgumentException("You cannot specify both ["
+ RealmSettings.getFullSettingKey(config, LEGACY_BIND_PASSWORD) + "] and ["
+ RealmSettings.getFullSettingKey(config, SECURE_BIND_PASSWORD) + "]");
} else {
bindPassword = CharArrays.toUtf8Bytes(LEGACY_BIND_PASSWORD.get(config.settings()).getChars());
bindPassword = CharArrays.toUtf8Bytes(config.getSetting(LEGACY_BIND_PASSWORD).getChars());
}
} else if (SECURE_BIND_PASSWORD.exists(config.settings())) {
bindPassword = CharArrays.toUtf8Bytes(SECURE_BIND_PASSWORD.get(config.settings()).getChars());
} else if (config.hasSetting(SECURE_BIND_PASSWORD)) {
bindPassword = CharArrays.toUtf8Bytes(config.getSetting(SECURE_BIND_PASSWORD).getChars());
} else {
bindPassword = null;
}
@ -87,7 +86,7 @@ abstract class PoolingSessionFactory extends SessionFactory implements Releasabl
bindCredentials = new SimpleBindRequest(bindDn, bindPassword);
}
this.useConnectionPool = poolingEnabled.get(config.settings());
this.useConnectionPool = config.getSetting(poolingEnabled);
if (useConnectionPool) {
this.connectionPool = createConnectionPool(config, serverSet, timeout, logger, bindCredentials, healthCheckDNSupplier);
} else {
@ -142,17 +141,16 @@ abstract class PoolingSessionFactory extends SessionFactory implements Releasabl
static LDAPConnectionPool createConnectionPool(RealmConfig config, ServerSet serverSet, TimeValue timeout, Logger logger,
BindRequest bindRequest,
Supplier<String> healthCheckDnSupplier) throws LDAPException {
Settings settings = config.settings();
final int initialSize = PoolingSessionFactorySettings.POOL_INITIAL_SIZE.get(settings);
final int size = PoolingSessionFactorySettings.POOL_SIZE.get(settings);
final int initialSize = config.getSetting(PoolingSessionFactorySettings.POOL_INITIAL_SIZE);
final int size = config.getSetting(PoolingSessionFactorySettings.POOL_SIZE);
LDAPConnectionPool pool = null;
boolean success = false;
try {
pool = LdapUtils.privilegedConnect(() -> new LDAPConnectionPool(serverSet, bindRequest, initialSize, size));
pool.setRetryFailedOperationsDueToInvalidConnections(true);
if (PoolingSessionFactorySettings.HEALTH_CHECK_ENABLED.get(settings)) {
String entryDn = PoolingSessionFactorySettings.HEALTH_CHECK_DN.get(settings).orElseGet(healthCheckDnSupplier);
final long healthCheckInterval = PoolingSessionFactorySettings.HEALTH_CHECK_INTERVAL.get(settings).millis();
if (config.getSetting(PoolingSessionFactorySettings.HEALTH_CHECK_ENABLED)) {
String entryDn = config.getSetting(PoolingSessionFactorySettings.HEALTH_CHECK_DN).orElseGet(healthCheckDnSupplier);
final long healthCheckInterval = config.getSetting(PoolingSessionFactorySettings.HEALTH_CHECK_INTERVAL).millis();
if (entryDn != null) {
// Checks the status of the LDAP connection at a specified interval in the background. We do not check on
// create as the LDAP server may require authentication to get an entry and a bind request has not been executed

View File

@ -14,8 +14,8 @@ import com.unboundid.ldap.sdk.SearchScope;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.ldap.SearchGroupsResolverSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver;
@ -26,11 +26,11 @@ import java.util.List;
import java.util.stream.Collectors;
import static org.elasticsearch.common.Strings.isNullOrEmpty;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.OBJECT_CLASS_PRESENCE_FILTER;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.createFilter;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.search;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.searchForEntry;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING;
/**
* Resolves the groups for a user by executing a search with a filter usually that contains a group
@ -44,16 +44,14 @@ class SearchGroupsResolver implements GroupsResolver {
private final LdapSearchScope scope;
private final boolean ignoreReferralErrors;
SearchGroupsResolver(Settings settings) {
if (SearchGroupsResolverSettings.BASE_DN.exists(settings)) {
baseDn = SearchGroupsResolverSettings.BASE_DN.get(settings);
} else {
SearchGroupsResolver(RealmConfig config) {
baseDn = config.getSetting(SearchGroupsResolverSettings.BASE_DN, () -> {
throw new IllegalArgumentException("base_dn must be specified");
}
filter = SearchGroupsResolverSettings.FILTER.get(settings);
userAttribute = SearchGroupsResolverSettings.USER_ATTRIBUTE.get(settings);
scope = SearchGroupsResolverSettings.SCOPE.get(settings);
this.ignoreReferralErrors = IGNORE_REFERRAL_ERRORS_SETTING.get(settings);
});
filter = config.getSetting(SearchGroupsResolverSettings.FILTER);
userAttribute = config.getSetting(SearchGroupsResolverSettings.USER_ATTRIBUTE);
scope = config.getSetting(SearchGroupsResolverSettings.SCOPE);
ignoreReferralErrors = config.getSetting(IGNORE_REFERRAL_ERRORS_SETTING);
}
@Override

View File

@ -10,8 +10,8 @@ import com.unboundid.ldap.sdk.LDAPInterface;
import com.unboundid.ldap.sdk.SearchScope;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.ldap.UserAttributeGroupsResolverSettings;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver;
@ -22,9 +22,9 @@ import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.OBJECT_CLASS_PRESENCE_FILTER;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.searchForEntry;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING;
/**
* Resolves the groups of a user based on the value of a attribute of the user's ldap entry
@ -34,8 +34,8 @@ class UserAttributeGroupsResolver implements GroupsResolver {
private final String attribute;
private final boolean ignoreReferralErrors;
UserAttributeGroupsResolver(Settings settings) {
this(UserAttributeGroupsResolverSettings.ATTRIBUTE.get(settings), IGNORE_REFERRAL_ERRORS_SETTING.get(settings));
UserAttributeGroupsResolver(RealmConfig realmConfig) {
this(realmConfig.getSetting(UserAttributeGroupsResolverSettings.ATTRIBUTE), realmConfig.getSetting(IGNORE_REFERRAL_ERRORS_SETTING));
}
private UserAttributeGroupsResolver(String attribute, boolean ignoreReferralErrors) {

View File

@ -11,9 +11,11 @@ import com.unboundid.ldap.sdk.RoundRobinDNSServerSet;
import com.unboundid.ldap.sdk.RoundRobinServerSet;
import com.unboundid.ldap.sdk.ServerSet;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapLoadBalancingSettings;
import javax.net.SocketFactory;
@ -26,7 +28,7 @@ public enum LdapLoadBalancing {
FAILOVER() {
@Override
ServerSet buildServerSet(String[] addresses, int[] ports, Settings settings, @Nullable SocketFactory socketFactory,
ServerSet buildServerSet(String[] addresses, int[] ports, RealmConfig realmConfig, @Nullable SocketFactory socketFactory,
@Nullable LDAPConnectionOptions options) {
FailoverServerSet serverSet = new FailoverServerSet(addresses, ports, socketFactory, options);
serverSet.setReOrderOnFailover(true);
@ -36,7 +38,7 @@ public enum LdapLoadBalancing {
ROUND_ROBIN() {
@Override
ServerSet buildServerSet(String[] addresses, int[] ports, Settings settings, @Nullable SocketFactory socketFactory,
ServerSet buildServerSet(String[] addresses, int[] ports, RealmConfig realmConfig, @Nullable SocketFactory socketFactory,
@Nullable LDAPConnectionOptions options) {
return new RoundRobinServerSet(addresses, ports, socketFactory, options);
}
@ -44,7 +46,7 @@ public enum LdapLoadBalancing {
DNS_ROUND_ROBIN() {
@Override
ServerSet buildServerSet(String[] addresses, int[] ports, Settings settings, @Nullable SocketFactory socketFactory,
ServerSet buildServerSet(String[] addresses, int[] ports, RealmConfig realmConfig, @Nullable SocketFactory socketFactory,
@Nullable LDAPConnectionOptions options) {
if (addresses.length != 1) {
throw new IllegalArgumentException(toString() + " can only be used with a single url");
@ -52,7 +54,7 @@ public enum LdapLoadBalancing {
if (InetAddresses.isInetAddress(addresses[0])) {
throw new IllegalArgumentException(toString() + " can only be used with a DNS name");
}
TimeValue dnsTtl = settings.getAsTime(LdapLoadBalancingSettings.CACHE_TTL_SETTING, CACHE_TTL_DEFAULT);
TimeValue dnsTtl = realmConfig.getSetting(LdapLoadBalancingSettings.CACHE_TTL_SETTING);
return new RoundRobinDNSServerSet(addresses[0], ports[0],
RoundRobinDNSServerSet.AddressSelectionMode.ROUND_ROBIN, dnsTtl.millis(), null, socketFactory, options);
}
@ -60,7 +62,7 @@ public enum LdapLoadBalancing {
DNS_FAILOVER() {
@Override
ServerSet buildServerSet(String[] addresses, int[] ports, Settings settings, @Nullable SocketFactory socketFactory,
ServerSet buildServerSet(String[] addresses, int[] ports, RealmConfig realmConfig, @Nullable SocketFactory socketFactory,
@Nullable LDAPConnectionOptions options) {
if (addresses.length != 1) {
throw new IllegalArgumentException(toString() + " can only be used with a single url");
@ -68,16 +70,15 @@ public enum LdapLoadBalancing {
if (InetAddresses.isInetAddress(addresses[0])) {
throw new IllegalArgumentException(toString() + " can only be used with a DNS name");
}
TimeValue dnsTtl = settings.getAsTime(LdapLoadBalancingSettings.CACHE_TTL_SETTING, CACHE_TTL_DEFAULT);
TimeValue dnsTtl = realmConfig.getSetting(LdapLoadBalancingSettings.CACHE_TTL_SETTING);
return new RoundRobinDNSServerSet(addresses[0], ports[0],
RoundRobinDNSServerSet.AddressSelectionMode.FAILOVER, dnsTtl.millis(), null, socketFactory, options);
}
};
public static final String LOAD_BALANCE_TYPE_DEFAULT = LdapLoadBalancing.FAILOVER.toString();
public static final TimeValue CACHE_TTL_DEFAULT = TimeValue.timeValueHours(1L);
public static final LdapLoadBalancing LOAD_BALANCE_TYPE_DEFAULT = LdapLoadBalancing.FAILOVER;
abstract ServerSet buildServerSet(String[] addresses, int[] ports, Settings settings, @Nullable SocketFactory socketFactory,
abstract ServerSet buildServerSet(String[] addresses, int[] ports, RealmConfig realmConfig, @Nullable SocketFactory socketFactory,
@Nullable LDAPConnectionOptions options);
@Override
@ -85,21 +86,24 @@ public enum LdapLoadBalancing {
return name().toLowerCase(Locale.ROOT);
}
public static LdapLoadBalancing resolve(Settings settings) {
Settings loadBalanceSettings = settings.getAsSettings(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS);
String type = loadBalanceSettings.get(LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING, LOAD_BALANCE_TYPE_DEFAULT);
public static LdapLoadBalancing resolve(RealmConfig realmConfig) {
String type = realmConfig.getSetting(LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING);
if (Strings.isNullOrEmpty(type)) {
return LOAD_BALANCE_TYPE_DEFAULT;
}
try {
return valueOf(type.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException ilae) {
throw new IllegalArgumentException("unknown load balance type [" + type + "]", ilae);
throw new IllegalArgumentException("unknown load balance type [" + type + "] in setting [" +
RealmSettings.getFullSettingKey(realmConfig, LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING) +
"]", ilae);
}
}
public static ServerSet serverSet(String[] addresses, int[] ports, Settings settings, @Nullable SocketFactory socketFactory,
public static ServerSet serverSet(String[] addresses, int[] ports, RealmConfig realmConfig, @Nullable SocketFactory socketFactory,
@Nullable LDAPConnectionOptions options) {
LdapLoadBalancing loadBalancing = resolve(settings);
Settings loadBalanceSettings = settings.getAsSettings(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS);
return loadBalancing.buildServerSet(addresses, ports, loadBalanceSettings, socketFactory, options);
LdapLoadBalancing loadBalancing = resolve(realmConfig);
return loadBalancing.buildServerSet(addresses, ports, realmConfig, socketFactory, options);
}
}

View File

@ -5,6 +5,16 @@
*/
package org.elasticsearch.xpack.security.authc.ldap.support;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.LDAPInterface;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SearchScope;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapMetaDataResolverSettings;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@ -13,16 +23,6 @@ import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.LDAPInterface;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SearchScope;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapMetaDataResolverSettings;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.OBJECT_CLASS_PRESENCE_FILTER;
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.searchForEntry;
@ -31,8 +31,8 @@ public class LdapMetaDataResolver {
private final String[] attributeNames;
private final boolean ignoreReferralErrors;
public LdapMetaDataResolver(Settings settings, boolean ignoreReferralErrors) {
this(LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING.get(settings), ignoreReferralErrors);
public LdapMetaDataResolver(RealmConfig realmConfig, boolean ignoreReferralErrors) {
this(realmConfig.getSetting(LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING), ignoreReferralErrors);
}
LdapMetaDataResolver(Collection<String> attributeNames, boolean ignoreReferralErrors) {

View File

@ -26,7 +26,6 @@ import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.util.Supplier;
import org.elasticsearch.core.internal.io.IOUtils;
import org.apache.lucene.util.SetOnce;
import org.elasticsearch.SpecialPermission;
import org.elasticsearch.action.ActionListener;
@ -35,11 +34,11 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.common.util.concurrent.CountDown;
import org.elasticsearch.core.internal.io.IOUtils;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.support.Exceptions;
import javax.naming.ldap.Rdn;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;

View File

@ -16,7 +16,6 @@ import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
@ -64,8 +63,8 @@ public abstract class SessionFactory {
protected SessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) {
this.config = config;
this.logger = LogManager.getLogger(getClass());
final Settings settings = config.settings();
TimeValue searchTimeout = settings.getAsTime(SessionFactorySettings.TIMEOUT_LDAP_SETTING, SessionFactorySettings.TIMEOUT_DEFAULT);
TimeValue searchTimeout = config.getSetting(SessionFactorySettings.TIMEOUT_LDAP_SETTING,
() -> SessionFactorySettings.TIMEOUT_DEFAULT);
if (searchTimeout.millis() < 1000L) {
logger.warn("ldap_search timeout [{}] is less than the minimum supported search " +
"timeout of 1s. using 1s",
@ -75,10 +74,10 @@ public abstract class SessionFactory {
this.timeout = searchTimeout;
this.sslService = sslService;
this.threadPool = threadPool;
LDAPServers ldapServers = ldapServers(settings);
LDAPServers ldapServers = ldapServers(config);
this.serverSet = serverSet(config, sslService, ldapServers);
this.sslUsed = ldapServers.ssl;
this.ignoreReferralErrors = SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING.get(settings);
this.ignoreReferralErrors = config.getSetting(SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING);
}
/**
@ -116,32 +115,22 @@ public abstract class SessionFactory {
protected static LDAPConnectionOptions connectionOptions(RealmConfig config,
SSLService sslService, Logger logger) {
Settings realmSettings = config.settings();
LDAPConnectionOptions options = new LDAPConnectionOptions();
options.setConnectTimeoutMillis(Math.toIntExact(
realmSettings.getAsTime(SessionFactorySettings.TIMEOUT_TCP_CONNECTION_SETTING,
SessionFactorySettings.TIMEOUT_DEFAULT).millis()
));
options.setFollowReferrals(realmSettings.getAsBoolean(SessionFactorySettings.FOLLOW_REFERRALS_SETTING, true));
options.setResponseTimeoutMillis(
realmSettings.getAsTime(SessionFactorySettings.TIMEOUT_TCP_READ_SETTING, SessionFactorySettings.TIMEOUT_DEFAULT).millis()
);
options.setConnectTimeoutMillis(Math.toIntExact(config.getSetting(SessionFactorySettings.TIMEOUT_TCP_CONNECTION_SETTING).millis()));
options.setFollowReferrals(config.getSetting(SessionFactorySettings.FOLLOW_REFERRALS_SETTING));
options.setResponseTimeoutMillis(config.getSetting(SessionFactorySettings.TIMEOUT_TCP_READ_SETTING).millis());
options.setAllowConcurrentSocketFactoryUse(true);
final SSLConfigurationSettings sslConfigurationSettings =
SSLConfigurationSettings.withoutPrefix();
final Settings realmSSLSettings = realmSettings.getByPrefix("ssl.");
final boolean verificationModeExists =
sslConfigurationSettings.verificationMode.exists(realmSSLSettings);
final boolean hostnameVerificationExists =
realmSettings.get(SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING, null) != null;
final boolean verificationModeExists = config.hasSetting(SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM);
final boolean hostnameVerificationExists = config.hasSetting(SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING);
if (verificationModeExists && hostnameVerificationExists) {
throw new IllegalArgumentException("[" + SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING + "] and [" +
sslConfigurationSettings.verificationMode.getKey() +
throw new IllegalArgumentException("[" +
RealmSettings.getFullSettingKey(config, SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING) + "] and [" +
RealmSettings.getFullSettingKey(config, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM) +
"] may not be used at the same time");
} else if (verificationModeExists) {
final String sslKey = RealmSettings.getFullSettingKey(config, "ssl");
final String sslKey = RealmSettings.realmSslPrefix(config.identifier());
final SSLConfiguration sslConfiguration = sslService.getSSLConfiguration(sslKey);
if (sslConfiguration == null) {
throw new IllegalStateException("cannot find SSL configuration for " + sslKey);
@ -153,9 +142,8 @@ public abstract class SessionFactory {
new DeprecationLogger(logger).deprecated("the setting [{}] has been deprecated and " +
"will be removed in a future version. use [{}] instead",
RealmSettings.getFullSettingKey(config, SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING),
RealmSettings.getFullSettingKey(config, "ssl." +
sslConfigurationSettings.verificationMode.getKey()));
if (realmSettings.getAsBoolean(SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING, true)) {
RealmSettings.getFullSettingKey(config, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM));
if (config.getSetting(SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING)) {
options.setSSLSocketVerifier(new HostNameSSLSocketVerifier(true));
}
} else {
@ -164,34 +152,34 @@ public abstract class SessionFactory {
return options;
}
private LDAPServers ldapServers(Settings settings) {
private LDAPServers ldapServers(RealmConfig config) {
// Parse LDAP urls
List<String> ldapUrls = settings.getAsList(SessionFactorySettings.URLS_SETTING, getDefaultLdapUrls(settings));
List<String> ldapUrls = config.getSetting(SessionFactorySettings.URLS_SETTING, () -> getDefaultLdapUrls(config));
if (ldapUrls == null || ldapUrls.isEmpty()) {
throw new IllegalArgumentException("missing required LDAP setting [" + SessionFactorySettings.URLS_SETTING +
"]");
throw new IllegalArgumentException("missing required LDAP setting ["
+ RealmSettings.getFullSettingKey(config, SessionFactorySettings.URLS_SETTING) + "]");
}
return new LDAPServers(ldapUrls.toArray(new String[ldapUrls.size()]));
}
protected List<String> getDefaultLdapUrls(Settings settings) {
protected List<String> getDefaultLdapUrls(RealmConfig config) {
return null;
}
private ServerSet serverSet(RealmConfig realmConfig, SSLService clientSSLService,
LDAPServers ldapServers) {
Settings settings = realmConfig.settings();
SocketFactory socketFactory = null;
if (ldapServers.ssl()) {
SSLConfiguration ssl = clientSSLService.getSSLConfiguration(RealmSettings.getFullSettingKey(realmConfig, "ssl"));
final String sslKey = RealmSettings.realmSslPrefix(config.identifier());
final SSLConfiguration ssl = clientSSLService.getSSLConfiguration(sslKey);
socketFactory = clientSSLService.sslSocketFactory(ssl);
if (settings.getAsBoolean(SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING, true)) {
if (ssl.verificationMode().isHostnameVerificationEnabled()) {
logger.debug("using encryption for LDAP connections with hostname verification");
} else {
logger.debug("using encryption for LDAP connections without hostname verification");
}
}
return LdapLoadBalancing.serverSet(ldapServers.addresses(), ldapServers.ports(), settings,
return LdapLoadBalancing.serverSet(ldapServers.addresses(), ldapServers.ports(), realmConfig,
socketFactory, connectionOptions(realmConfig, sslService, logger));
}
@ -255,7 +243,7 @@ public abstract class SessionFactory {
//No mixing is allowed because we use the same socketfactory
throw new IllegalArgumentException(
"configured LDAP protocols are not all equal (ldaps://.. and ldap://..): ["
+ Strings.arrayToCommaDelimitedString(ldapUrls) + "]");
+ Strings.arrayToCommaDelimitedString(ldapUrls) + "]");
}
return allSecure;

View File

@ -15,7 +15,6 @@ import org.elasticsearch.common.cache.Cache;
import org.elasticsearch.common.cache.CacheBuilder;
import org.elasticsearch.common.hash.MessageDigests;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ReleasableLock;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
@ -79,19 +78,19 @@ public class PkiRealm extends Realm implements CachingRealm {
private DelegatedAuthorizationSupport delegatedRealms;
public PkiRealm(RealmConfig config, ResourceWatcherService watcherService, NativeRoleMappingStore nativeRoleMappingStore) {
this(config, new CompositeRoleMapper(PkiRealmSettings.TYPE, config, watcherService, nativeRoleMappingStore));
this(config, new CompositeRoleMapper(config, watcherService, nativeRoleMappingStore));
}
// pkg private for testing
PkiRealm(RealmConfig config, UserRoleMapper roleMapper) {
super(PkiRealmSettings.TYPE, config);
super(config);
this.trustManager = trustManagers(config);
this.principalPattern = PkiRealmSettings.USERNAME_PATTERN_SETTING.get(config.settings());
this.principalPattern = config.getSetting(PkiRealmSettings.USERNAME_PATTERN_SETTING);
this.roleMapper = roleMapper;
this.roleMapper.refreshRealmOnChange(this);
this.cache = CacheBuilder.<BytesKey, User>builder()
.setExpireAfterWrite(PkiRealmSettings.CACHE_TTL_SETTING.get(config.settings()))
.setMaximumWeight(PkiRealmSettings.CACHE_MAX_USERS_SETTING.get(config.settings()))
.setExpireAfterWrite(config.getSetting(PkiRealmSettings.CACHE_TTL_SETTING))
.setMaximumWeight(config.getSetting(PkiRealmSettings.CACHE_MAX_USERS_SETTING))
.build();
this.delegatedRealms = null;
}
@ -117,7 +116,7 @@ public class PkiRealm extends Realm implements CachingRealm {
@Override
public void authenticate(AuthenticationToken authToken, ActionListener<AuthenticationResult> listener) {
assert delegatedRealms != null : "Realm has not been initialized correctly";
X509AuthenticationToken token = (X509AuthenticationToken)authToken;
X509AuthenticationToken token = (X509AuthenticationToken) authToken;
try {
final BytesKey fingerprint = computeFingerprint(token.credentials()[0]);
User user = cache.get(fingerprint);
@ -215,36 +214,43 @@ public class PkiRealm extends Realm implements CachingRealm {
return true;
}
static X509TrustManager trustManagers(RealmConfig realmConfig) {
final Settings settings = realmConfig.settings();
final Environment env = realmConfig.env();
List<String> certificateAuthorities = settings.getAsList(PkiRealmSettings.SSL_SETTINGS.caPaths.getKey(), null);
String truststorePath = PkiRealmSettings.SSL_SETTINGS.truststorePath.get(settings).orElse(null);
X509TrustManager trustManagers(RealmConfig realmConfig) {
final List<String> certificateAuthorities = realmConfig.hasSetting(PkiRealmSettings.CAPATH_SETTING) ?
realmConfig.getSetting(PkiRealmSettings.CAPATH_SETTING) : null;
String truststorePath = realmConfig.getSetting(PkiRealmSettings.TRUST_STORE_PATH).orElse(null);
if (truststorePath == null && certificateAuthorities == null) {
return null;
} else if (truststorePath != null && certificateAuthorities != null) {
final String pathKey = RealmSettings.getFullSettingKey(realmConfig, PkiRealmSettings.SSL_SETTINGS.truststorePath);
final String caKey = RealmSettings.getFullSettingKey(realmConfig, PkiRealmSettings.SSL_SETTINGS.caPaths);
final String pathKey = RealmSettings.getFullSettingKey(realmConfig, PkiRealmSettings.TRUST_STORE_PATH);
final String caKey = RealmSettings.getFullSettingKey(realmConfig, PkiRealmSettings.CAPATH_SETTING);
throw new IllegalArgumentException("[" + pathKey + "] and [" + caKey + "] cannot be used at the same time");
} else if (truststorePath != null) {
return trustManagersFromTruststore(truststorePath, realmConfig);
final X509TrustManager trustManager = trustManagersFromTruststore(truststorePath, realmConfig);
if (trustManager.getAcceptedIssuers().length == 0) {
logger.warn("PKI Realm {} uses truststore {} which has no accepted certificate issuers", this, truststorePath);
}
return trustManager;
}
return trustManagersFromCAs(settings, env);
final X509TrustManager trustManager = trustManagersFromCAs(certificateAuthorities, realmConfig.env());
if (trustManager.getAcceptedIssuers().length == 0) {
logger.warn("PKI Realm {} uses CAs {} with no accepted certificate issuers", this, certificateAuthorities);
}
return trustManager;
}
private static X509TrustManager trustManagersFromTruststore(String truststorePath, RealmConfig realmConfig) {
final Settings settings = realmConfig.settings();
if (PkiRealmSettings.SSL_SETTINGS.truststorePassword.exists(settings) == false
&& PkiRealmSettings.SSL_SETTINGS.legacyTruststorePassword.exists(settings) == false) {
if (realmConfig.hasSetting(PkiRealmSettings.TRUST_STORE_PASSWORD) == false
&& realmConfig.hasSetting(PkiRealmSettings.LEGACY_TRUST_STORE_PASSWORD) == false) {
throw new IllegalArgumentException("Neither [" +
RealmSettings.getFullSettingKey(realmConfig, PkiRealmSettings.SSL_SETTINGS.truststorePassword) + "] or [" +
RealmSettings.getFullSettingKey(realmConfig, PkiRealmSettings.SSL_SETTINGS.legacyTruststorePassword) + "] is configured"
);
RealmSettings.getFullSettingKey(realmConfig, PkiRealmSettings.TRUST_STORE_PASSWORD) + "] or [" +
RealmSettings.getFullSettingKey(realmConfig, PkiRealmSettings.LEGACY_TRUST_STORE_PASSWORD)
+ "] is configured");
}
try (SecureString password = PkiRealmSettings.SSL_SETTINGS.truststorePassword.get(settings)) {
String trustStoreAlgorithm = PkiRealmSettings.SSL_SETTINGS.truststoreAlgorithm.get(settings);
String trustStoreType = SSLConfigurationSettings.getKeyStoreType(PkiRealmSettings.SSL_SETTINGS.truststoreType,
settings, truststorePath);
try (SecureString password = realmConfig.getSetting(PkiRealmSettings.TRUST_STORE_PASSWORD)) {
String trustStoreAlgorithm = realmConfig.getSetting(PkiRealmSettings.TRUST_STORE_ALGORITHM);
String trustStoreType = SSLConfigurationSettings.getKeyStoreType(
realmConfig.getConcreteSetting(PkiRealmSettings.TRUST_STORE_TYPE), realmConfig.globalSettings(),
truststorePath);
try {
return CertParsingUtils.trustManager(truststorePath, trustStoreType, password.getChars(), trustStoreAlgorithm, realmConfig
.env());
@ -254,8 +260,7 @@ public class PkiRealm extends Realm implements CachingRealm {
}
}
private static X509TrustManager trustManagersFromCAs(Settings settings, Environment env) {
List<String> certificateAuthorities = settings.getAsList(PkiRealmSettings.SSL_SETTINGS.caPaths.getKey(), null);
private static X509TrustManager trustManagersFromCAs(List<String> certificateAuthorities, Environment env) {
assert certificateAuthorities != null;
try {
Certificate[] certificates = CertParsingUtils.readCertificates(certificateAuthorities, env);

View File

@ -66,8 +66,6 @@ import org.opensaml.xmlsec.signature.support.Signer;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getRealmType;
/**
* CLI tool to generate SAML Metadata for a Service Provider (realm)
*/
@ -160,8 +158,9 @@ public class SamlMetadataCommand extends EnvironmentAwareCommand {
final boolean batch = options.has(batchSpec);
final RealmConfig realm = findRealm(terminal, options, env);
final Settings realmSettings = realm.globalSettings().getByPrefix(RealmSettings.realmSettingPrefix(realm.identifier()));
terminal.println(Terminal.Verbosity.VERBOSE,
"Using realm configuration\n=====\n" + realm.settings().toDelimitedString('\n') + "=====");
"Using realm configuration\n=====\n" + realmSettings.toDelimitedString('\n') + "=====");
final Locale locale = findLocale(options);
terminal.println(Terminal.Verbosity.VERBOSE, "Using locale: " + locale.toLanguageTag());
@ -172,7 +171,7 @@ public class SamlMetadataCommand extends EnvironmentAwareCommand {
.encryptionCredentials(spConfig.getEncryptionCredentials())
.signingCredential(spConfig.getSigningConfiguration().getCredential())
.authnRequestsSigned(spConfig.getSigningConfiguration().shouldSign(AuthnRequest.DEFAULT_ELEMENT_LOCAL_NAME))
.nameIdFormat(SamlRealmSettings.NAMEID_FORMAT.get(realm.settings()))
.nameIdFormat(realm.getSetting(SamlRealmSettings.NAMEID_FORMAT))
.serviceName(option(serviceNameSpec, options, env.settings().get("cluster.name")));
Map<String, String> attributes = getAttributeNames(options, realm);
@ -399,7 +398,8 @@ public class SamlMetadataCommand extends EnvironmentAwareCommand {
for (String a : attributeSpec.values(options)) {
attributes.put(a, null);
}
final Settings attributeSettings = realm.settings().getByPrefix(SamlRealmSettings.AttributeSetting.ATTRIBUTES_PREFIX);
final String prefix = RealmSettings.realmSettingPrefix(realm.identifier()) + SamlRealmSettings.AttributeSetting.ATTRIBUTES_PREFIX;
final Settings attributeSettings = realm.globalSettings().getByPrefix(prefix);
for (String key : sorted(attributeSettings.keySet())) {
final String attr = attributeSettings.get(key);
attributes.put(attr, key);
@ -412,6 +412,9 @@ public class SamlMetadataCommand extends EnvironmentAwareCommand {
return new TreeSet<>(strings);
}
/**
* @TODO REALM-SETTINGS[TIM] This can be redone a lot now the realm settings are keyed by type
*/
private RealmConfig findRealm(Terminal terminal, OptionSet options, Environment env) throws UserException, IOException, Exception {
keyStoreWrapper = keyStoreFunction.apply(env);
@ -430,36 +433,37 @@ public class SamlMetadataCommand extends EnvironmentAwareCommand {
settings = env.settings();
}
final Map<String, Settings> realms = RealmSettings.getRealmSettings(settings);
final Map<RealmConfig.RealmIdentifier, Settings> realms = RealmSettings.getRealmSettings(settings);
if (options.has(realmSpec)) {
final String name = realmSpec.value(options);
final Settings realmSettings = realms.get(name);
final RealmConfig.RealmIdentifier identifier = new RealmConfig.RealmIdentifier(SamlRealmSettings.TYPE, name);
final Settings realmSettings = realms.get(identifier);
if (realmSettings == null) {
throw new UserException(ExitCodes.CONFIG, "No such realm '" + name + "' defined in " + env.configFile());
}
final String realmType = getRealmType(realmSettings);
if (isSamlRealm(realmType)) {
return buildRealm(name, realmSettings, env);
if (isSamlRealm(identifier)) {
return buildRealm(identifier, env, settings);
} else {
throw new UserException(ExitCodes.CONFIG, "Realm '" + name + "' is not a SAML realm (is '" + realmType + "')");
throw new UserException(ExitCodes.CONFIG, "Realm '" + name + "' is not a SAML realm (is '" + identifier.getType() + "')");
}
} else {
final List<Map.Entry<String, Settings>> saml = realms.entrySet().stream()
.filter(entry -> isSamlRealm(getRealmType(entry.getValue())))
final List<Map.Entry<RealmConfig.RealmIdentifier, Settings>> saml = realms.entrySet().stream()
.filter(entry -> isSamlRealm(entry.getKey()))
.collect(Collectors.toList());
if (saml.isEmpty()) {
throw new UserException(ExitCodes.CONFIG, "There is no SAML realm configured in " + env.configFile());
}
if (saml.size() > 1) {
terminal.println("Using configuration in " + env.configFile());
terminal.println("Found multiple SAML realms: " + saml.stream().map(Map.Entry::getKey).collect(Collectors.joining(", ")));
terminal.println("Found multiple SAML realms: "
+ saml.stream().map(Map.Entry::getKey).map(Object::toString).collect(Collectors.joining(", ")));
terminal.println("Use the -" + optionName(realmSpec) + " option to specify an explicit realm");
throw new UserException(ExitCodes.CONFIG,
"Found multiple SAML realms, please specify one with '-" + optionName(realmSpec) + "'");
}
final Map.Entry<String, Settings> entry = saml.get(0);
final Map.Entry<RealmConfig.RealmIdentifier, Settings> entry = saml.get(0);
terminal.println("Building metadata for SAML realm " + entry.getKey());
return buildRealm(entry.getKey(), entry.getValue(), env);
return buildRealm(entry.getKey(), env, settings);
}
}
@ -467,12 +471,12 @@ public class SamlMetadataCommand extends EnvironmentAwareCommand {
return spec.options().get(0);
}
private RealmConfig buildRealm(String name, Settings settings, Environment env) {
return new RealmConfig(name, settings, env.settings(), env, new ThreadContext(env.settings()));
private RealmConfig buildRealm(RealmConfig.RealmIdentifier identifier, Environment env, Settings globalSettings ) {
return new RealmConfig(identifier, globalSettings, env, new ThreadContext(globalSettings));
}
private boolean isSamlRealm(String realmType) {
return SamlRealmSettings.TYPE.equals(realmType);
private boolean isSamlRealm(RealmConfig.RealmIdentifier realmIdentifier) {
return SamlRealmSettings.TYPE.equals(realmIdentifier.getType());
}
private Locale findLocale(OptionSet options) {

View File

@ -28,7 +28,6 @@ import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.lease.Releasable;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.CollectionUtils;
@ -48,7 +47,6 @@ import org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.CertParsingUtils;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.core.ssl.X509KeyPairSettings;
import org.elasticsearch.xpack.security.authc.Realms;
@ -107,7 +105,7 @@ import java.util.stream.Stream;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.CLOCK_SKEW;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.DN_ATTRIBUTE;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.ENCRYPTION_KEY_ALIAS;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.ENCRYPTION_SETTINGS;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.ENCRYPTION_SETTING_KEY;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.FORCE_AUTHN;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.GROUPS_ATTRIBUTE;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.IDP_ENTITY_ID;
@ -124,11 +122,10 @@ import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.REQUESTED_AUTHN_CONTEXT_CLASS_REF;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.SIGNING_KEY_ALIAS;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.SIGNING_MESSAGE_TYPES;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.SIGNING_SETTINGS;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.SIGNING_SETTING_KEY;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.SP_ACS;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.SP_ENTITY_ID;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.SP_LOGOUT;
import static org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings.TYPE;
/**
* This class is {@link Releasable} because it uses a library that thinks timers and timer tasks
@ -196,7 +193,7 @@ public final class SamlRealm extends Realm implements Releasable {
final Clock clock = Clock.systemUTC();
final IdpConfiguration idpConfiguration = getIdpConfiguration(config, metadataResolver, idpDescriptor);
final TimeValue maxSkew = CLOCK_SKEW.get(config.settings());
final TimeValue maxSkew = config.getSetting(CLOCK_SKEW);
final SamlAuthenticator authenticator = new SamlAuthenticator(clock, idpConfiguration, serviceProvider, maxSkew);
final SamlLogoutRequestHandler logoutHandler =
new SamlLogoutRequestHandler(clock, idpConfiguration, serviceProvider, maxSkew);
@ -212,7 +209,7 @@ public final class SamlRealm extends Realm implements Releasable {
// For testing
SamlRealm(RealmConfig config, UserRoleMapper roleMapper, SamlAuthenticator authenticator, SamlLogoutRequestHandler logoutHandler,
Supplier<EntityDescriptor> idpDescriptor, SpConfiguration spConfiguration) throws Exception {
super(TYPE, config);
super(config);
this.roleMapper = roleMapper;
this.authenticator = authenticator;
@ -222,10 +219,10 @@ public final class SamlRealm extends Realm implements Releasable {
this.serviceProvider = spConfiguration;
this.nameIdPolicy = new SamlAuthnRequestBuilder.NameIDPolicySettings(require(config, NAMEID_FORMAT),
NAMEID_ALLOW_CREATE.get(config.settings()), NAMEID_SP_QUALIFIER.get(config.settings()));
this.forceAuthn = FORCE_AUTHN.exists(config.settings()) ? FORCE_AUTHN.get(config.settings()) : null;
this.useSingleLogout = IDP_SINGLE_LOGOUT.get(config.settings());
this.populateUserMetadata = POPULATE_USER_METADATA.get(config.settings());
config.getSetting(NAMEID_ALLOW_CREATE), config.getSetting(NAMEID_SP_QUALIFIER));
this.forceAuthn = config.getSetting(FORCE_AUTHN, () -> null);
this.useSingleLogout = config.getSetting(IDP_SINGLE_LOGOUT);
this.populateUserMetadata = config.getSetting(POPULATE_USER_METADATA);
this.principalAttribute = AttributeParser.forSetting(logger, PRINCIPAL_ATTRIBUTE, config, true);
this.groupsAttribute = AttributeParser.forSetting(logger, GROUPS_ATTRIBUTE, config, false);
@ -244,8 +241,8 @@ public final class SamlRealm extends Realm implements Releasable {
delegatedRealms = new DelegatedAuthorizationSupport(realms, config, licenseState);
}
static String require(RealmConfig config, Setting<String> setting) {
final String value = setting.get(config.settings());
static String require(RealmConfig config, Setting.AffixSetting<String> setting) {
final String value = config.getSetting(setting);
if (value.isEmpty()) {
throw new IllegalArgumentException("The configuration setting [" + RealmSettings.getFullSettingKey(config, setting)
+ "] is required");
@ -287,8 +284,8 @@ public final class SamlRealm extends Realm implements Releasable {
static SpConfiguration getSpConfiguration(RealmConfig config) throws IOException, GeneralSecurityException {
final String serviceProviderId = require(config, SP_ENTITY_ID);
final String assertionConsumerServiceURL = require(config, SP_ACS);
final String logoutUrl = SP_LOGOUT.get(config.settings());
final List<String> reqAuthnCtxClassRef = REQUESTED_AUTHN_CONTEXT_CLASS_REF.get(config.settings());
final String logoutUrl = config.getSetting(SP_LOGOUT);
final List<String> reqAuthnCtxClassRef = config.getSetting(REQUESTED_AUTHN_CONTEXT_CLASS_REF);
return new SpConfiguration(serviceProviderId, assertionConsumerServiceURL,
logoutUrl, buildSigningConfiguration(config), buildEncryptionCredential(config), reqAuthnCtxClassRef);
}
@ -296,35 +293,37 @@ public final class SamlRealm extends Realm implements Releasable {
// Package-private for testing
static List<X509Credential> buildEncryptionCredential(RealmConfig config) throws IOException, GeneralSecurityException {
return buildCredential(config, ENCRYPTION_SETTINGS, ENCRYPTION_KEY_ALIAS, true);
return buildCredential(config,
RealmSettings.realmSettingPrefix(config.identifier()) + ENCRYPTION_SETTING_KEY,
ENCRYPTION_KEY_ALIAS, true);
}
static SigningConfiguration buildSigningConfiguration(RealmConfig config) throws IOException, GeneralSecurityException {
final List<X509Credential> credentials = buildCredential(config, SIGNING_SETTINGS, SIGNING_KEY_ALIAS, false);
final List<X509Credential> credentials = buildCredential(config,
RealmSettings.realmSettingPrefix(config.identifier()) + SIGNING_SETTING_KEY, SIGNING_KEY_ALIAS, false);
if (credentials == null || credentials.isEmpty()) {
if (SIGNING_MESSAGE_TYPES.exists(config.settings())) {
if (config.hasSetting(SIGNING_MESSAGE_TYPES)) {
throw new IllegalArgumentException("The setting [" + RealmSettings.getFullSettingKey(config, SIGNING_MESSAGE_TYPES)
+ "] cannot be specified if there are no signing credentials");
} else {
return new SigningConfiguration(Collections.emptySet(), null);
}
} else {
final List<String> types = SIGNING_MESSAGE_TYPES.get(config.settings());
final List<String> types = config.getSetting(SIGNING_MESSAGE_TYPES);
return new SigningConfiguration(Sets.newHashSet(types), credentials.get(0));
}
}
private static List<X509Credential> buildCredential(RealmConfig config, X509KeyPairSettings keyPairSettings,
Setting<String> aliasSetting, final boolean allowMultiple) {
final X509KeyManager keyManager = CertParsingUtils.getKeyManager(keyPairSettings, config.settings(), null, config.env());
private static List<X509Credential> buildCredential(RealmConfig config, String prefix, Setting.AffixSetting<String> aliasSetting,
boolean allowMultiple) {
final X509KeyPairSettings keyPairSettings = X509KeyPairSettings.withPrefix(prefix, false);
final X509KeyManager keyManager = CertParsingUtils.getKeyManager(keyPairSettings, config.globalSettings(), null, config.env());
if (keyManager == null) {
return null;
}
final Set<String> aliases = new HashSet<>();
final String configuredAlias = aliasSetting.get(config.settings());
final String configuredAlias = config.getSetting(aliasSetting);
if (Strings.isNullOrEmpty(configuredAlias)) {
final String[] serverAliases = keyManager.getServerAliases("RSA", null);
@ -334,11 +333,11 @@ public final class SamlRealm extends Realm implements Releasable {
if (aliases.isEmpty()) {
throw new IllegalArgumentException(
"The configured key store for " + RealmSettings.getFullSettingKey(config, keyPairSettings.getPrefix())
"The configured key store for " + prefix
+ " does not contain any RSA key pairs");
} else if (allowMultiple == false && aliases.size() > 1) {
throw new IllegalArgumentException(
"The configured key store for " + RealmSettings.getFullSettingKey(config, keyPairSettings.getPrefix())
"The configured key store for " + prefix
+ " has multiple keys but no alias has been specified (from setting "
+ RealmSettings.getFullSettingKey(config, aliasSetting) + ")");
}
@ -350,7 +349,7 @@ public final class SamlRealm extends Realm implements Releasable {
for (String alias : aliases) {
if (keyManager.getPrivateKey(alias) == null) {
throw new IllegalArgumentException(
"The configured key store for " + RealmSettings.getFullSettingKey(config, keyPairSettings.getPrefix())
"The configured key store for " + prefix
+ " does not have a key associated with alias [" + alias + "] "
+ ((Strings.isNullOrEmpty(configuredAlias) == false)
? "(from setting " + RealmSettings.getFullSettingKey(config, aliasSetting) + ")"
@ -416,7 +415,7 @@ public final class SamlRealm extends Realm implements Releasable {
}
private void buildUser(SamlAttributes attributes, ActionListener<AuthenticationResult> baseListener) {
final String principal = resolveSingleValueAttribute(attributes, principalAttribute, PRINCIPAL_ATTRIBUTE.name());
final String principal = resolveSingleValueAttribute(attributes, principalAttribute, PRINCIPAL_ATTRIBUTE.name(config));
if (Strings.isNullOrEmpty(principal)) {
baseListener.onResponse(AuthenticationResult.unsuccessful(
principalAttribute + " not found in " + attributes.attributes(), null));
@ -455,9 +454,9 @@ public final class SamlRealm extends Realm implements Releasable {
final List<String> groups = groupsAttribute.getAttribute(attributes);
final String dn = resolveSingleValueAttribute(attributes, dnAttribute, DN_ATTRIBUTE.name());
final String name = resolveSingleValueAttribute(attributes, nameAttribute, NAME_ATTRIBUTE.name());
final String mail = resolveSingleValueAttribute(attributes, mailAttribute, MAIL_ATTRIBUTE.name());
final String dn = resolveSingleValueAttribute(attributes, dnAttribute, DN_ATTRIBUTE.name(config));
final String name = resolveSingleValueAttribute(attributes, nameAttribute, NAME_ATTRIBUTE.name(config));
final String mail = resolveSingleValueAttribute(attributes, mailAttribute, MAIL_ATTRIBUTE.name(config));
UserRoleMapper.UserData userData = new UserRoleMapper.UserData(principal, dn, groups, userMeta, config);
roleMapper.resolveRoles(userData, ActionListener.wrap(roles -> {
final User user = new User(principal, roles.toArray(new String[roles.size()]), name, mail, userMeta, true);
@ -526,7 +525,7 @@ public final class SamlRealm extends Realm implements Releasable {
HttpClientBuilder builder = HttpClientBuilder.create();
// ssl setup
final String sslKey = RealmSettings.getFullSettingKey(config, SamlRealmSettings.SSL_PREFIX);
final String sslKey = RealmSettings.realmSslPrefix(config.identifier());
final SSLConfiguration sslConfiguration = sslService.getSSLConfiguration(sslKey);
boolean isHostnameVerificationEnabled = sslConfiguration.verificationMode().isHostnameVerificationEnabled();
HostnameVerifier verifier = isHostnameVerificationEnabled ? new DefaultHostnameVerifier() : NoopHostnameVerifier.INSTANCE;
@ -534,7 +533,7 @@ public final class SamlRealm extends Realm implements Releasable {
builder.setSSLSocketFactory(factory);
HTTPMetadataResolver resolver = new PrivilegedHTTPMetadataResolver(builder.build(), metadataUrl);
TimeValue refresh = IDP_METADATA_HTTP_REFRESH.get(config.settings());
TimeValue refresh = config.getSetting(IDP_METADATA_HTTP_REFRESH);
resolver.setMinRefreshDelay(refresh.millis());
resolver.setMaxRefreshDelay(refresh.millis());
initialiseResolver(resolver, config);
@ -579,7 +578,7 @@ public final class SamlRealm extends Realm implements Releasable {
final Path path = config.env().configFile().resolve(metadataPath);
final FilesystemMetadataResolver resolver = new FilesystemMetadataResolver(path.toFile());
if (IDP_METADATA_HTTP_REFRESH.exists(config.settings())) {
if (config.hasSetting(IDP_METADATA_HTTP_REFRESH)) {
logger.info("Ignoring setting [{}] because the IdP metadata is being loaded from a file",
RealmSettings.getFullSettingKey(config, IDP_METADATA_HTTP_REFRESH));
}
@ -744,13 +743,13 @@ public final class SamlRealm extends Realm implements Releasable {
static AttributeParser forSetting(Logger logger, SamlRealmSettings.AttributeSetting setting, RealmConfig realmConfig,
boolean required) {
final Settings settings = realmConfig.settings();
if (setting.getAttribute().exists(settings)) {
String attributeName = setting.getAttribute().get(settings);
if (setting.getPattern().exists(settings)) {
Pattern regex = Pattern.compile(setting.getPattern().get(settings));
if (realmConfig.hasSetting(setting.getAttribute())) {
String attributeName = realmConfig.getSetting(setting.getAttribute());
if (realmConfig.hasSetting(setting.getPattern())) {
Pattern regex = Pattern.compile(realmConfig.getSetting(setting.getPattern()));
return new AttributeParser(
"SAML Attribute [" + attributeName + "] with pattern [" + regex.pattern() + "] for [" + setting.name() + "]",
"SAML Attribute [" + attributeName + "] with pattern [" + regex.pattern() + "] for ["
+ setting.name(realmConfig) + "]",
attributes -> attributes.getAttributeValues(attributeName).stream().map(s -> {
final Matcher matcher = regex.matcher(s);
if (matcher.find() == false) {
@ -768,17 +767,19 @@ public final class SamlRealm extends Realm implements Releasable {
);
} else {
return new AttributeParser(
"SAML Attribute [" + attributeName + "] for [" + setting.name() + "]",
"SAML Attribute [" + attributeName + "] for [" + setting.name(realmConfig) + "]",
attributes -> attributes.getAttributeValues(attributeName));
}
} else if (required) {
throw new SettingsException("Setting " + RealmSettings.getFullSettingKey(realmConfig, setting.getAttribute())
+ " is required");
} else if (setting.getPattern().exists(settings)) {
throw new SettingsException("Setting " + RealmSettings.getFullSettingKey(realmConfig, setting.getPattern())
+ " cannot be set unless " + RealmSettings.getFullSettingKey(realmConfig, setting.getAttribute()) + " is also set");
throw new SettingsException("Setting [" + RealmSettings.getFullSettingKey(realmConfig, setting.getAttribute())
+ "] is required");
} else if (realmConfig.hasSetting(setting.getPattern())) {
throw new SettingsException("Setting [" + RealmSettings.getFullSettingKey(realmConfig, setting.getPattern())
+ "] cannot be set unless [" + RealmSettings.getFullSettingKey(realmConfig, setting.getAttribute())
+ "] is also set");
} else {
return new AttributeParser("No SAML attribute for [" + setting.name() + "]", attributes -> Collections.emptyList());
return new AttributeParser("No SAML attribute for [" + setting.name(realmConfig) + "]",
attributes -> Collections.emptyList());
}
}

View File

@ -34,20 +34,20 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
private final boolean authenticationEnabled;
final Hasher cacheHasher;
protected CachingUsernamePasswordRealm(String type, RealmConfig config, ThreadPool threadPool) {
super(type, config);
cacheHasher = Hasher.resolve(CachingUsernamePasswordRealmSettings.CACHE_HASH_ALGO_SETTING.get(config.settings()));
protected CachingUsernamePasswordRealm(RealmConfig config, ThreadPool threadPool) {
super(config);
cacheHasher = Hasher.resolve(this.config.getSetting(CachingUsernamePasswordRealmSettings.CACHE_HASH_ALGO_SETTING));
this.threadPool = threadPool;
final TimeValue ttl = CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING.get(config.settings());
final TimeValue ttl = this.config.getSetting(CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING);
if (ttl.getNanos() > 0) {
cache = CacheBuilder.<String, ListenableFuture<UserWithHash>>builder()
.setExpireAfterWrite(ttl)
.setMaximumWeight(CachingUsernamePasswordRealmSettings.CACHE_MAX_USERS_SETTING.get(config.settings()))
.build();
.setExpireAfterWrite(ttl)
.setMaximumWeight(this.config.getSetting(CachingUsernamePasswordRealmSettings.CACHE_MAX_USERS_SETTING))
.build();
} else {
cache = null;
}
this.authenticationEnabled = CachingUsernamePasswordRealmSettings.AUTHC_ENABLED_SETTING.get(config.settings());
this.authenticationEnabled = config.getSetting(CachingUsernamePasswordRealmSettings.AUTHC_ENABLED_SETTING);
}
@Override
@ -86,7 +86,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
* This method will respond with {@link AuthenticationResult#notHandled()} if
* {@link CachingUsernamePasswordRealmSettings#AUTHC_ENABLED_SETTING authentication is not enabled}.
* @param authToken The authentication token
* @param listener to be called at completion
* @param listener to be called at completion
*/
@Override
public final void authenticate(AuthenticationToken authToken, ActionListener<AuthenticationResult> listener) {

View File

@ -10,6 +10,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.LicenseUtils;
@ -17,15 +18,14 @@ import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.core.security.authc.Realm;
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.security.user.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.common.Strings.collectionToDelimitedString;
import static org.elasticsearch.xpack.core.security.authc.support.DelegatedAuthorizationSettings.AUTHZ_REALMS;
/**
* Utility class for supporting "delegated authorization" (aka "authorization_realms", aka "lookup realms").
@ -46,7 +46,7 @@ public class DelegatedAuthorizationSupport {
* {@link #DelegatedAuthorizationSupport(Iterable, List, Settings, ThreadContext, XPackLicenseState)}
*/
public DelegatedAuthorizationSupport(Iterable<? extends Realm> allRealms, RealmConfig config, XPackLicenseState licenseState) {
this(allRealms, DelegatedAuthorizationSettings.AUTHZ_REALMS.get(config.settings()), config.globalSettings(), config.threadContext(),
this(allRealms, config.getSetting(AUTHZ_REALMS), config.globalSettings(), config.threadContext(),
licenseState);
}
@ -82,14 +82,14 @@ public class DelegatedAuthorizationSupport {
public void resolve(String username, ActionListener<AuthenticationResult> resultListener) {
if (licenseState.isAuthorizationRealmAllowed() == false) {
resultListener.onResponse(AuthenticationResult.unsuccessful(
DelegatedAuthorizationSettings.AUTHZ_REALMS.getKey() + " are not permitted",
LicenseUtils.newComplianceException(DelegatedAuthorizationSettings.AUTHZ_REALMS.getKey())
DelegatedAuthorizationSettings.AUTHZ_REALMS_SUFFIX + " are not permitted",
LicenseUtils.newComplianceException(DelegatedAuthorizationSettings.AUTHZ_REALMS_SUFFIX)
));
return;
}
if (hasDelegation() == false) {
resultListener.onResponse(AuthenticationResult.unsuccessful(
"No [" + DelegatedAuthorizationSettings.AUTHZ_REALMS.getKey() + "] have been configured", null));
"No [" + DelegatedAuthorizationSettings.AUTHZ_REALMS_SUFFIX + "] have been configured", null));
return;
}
ActionListener<Tuple<User, Realm>> userListener = ActionListener.wrap(tuple -> {
@ -123,13 +123,12 @@ public class DelegatedAuthorizationSupport {
* @throws IllegalArgumentException if a chain is detected
*/
private void checkForRealmChains(Iterable<Realm> delegatedRealms, Settings globalSettings) {
final Map<String, Settings> settingsByRealm = RealmSettings.getRealmSettings(globalSettings);
for (Realm realm : delegatedRealms) {
final Settings realmSettings = settingsByRealm.get(realm.name());
if (realmSettings != null && DelegatedAuthorizationSettings.AUTHZ_REALMS.exists(realmSettings)) {
throw new IllegalArgumentException("cannot use realm [" + realm +
"] as an authorization realm - it is already delegating authorization to [" +
DelegatedAuthorizationSettings.AUTHZ_REALMS.get(realmSettings) + "]");
Setting<List<String>> realmAuthzSetting = AUTHZ_REALMS.apply(realm.type()).getConcreteSettingForNamespace(realm.name());
if (realmAuthzSetting.exists(globalSettings)) {
throw new IllegalArgumentException("cannot use realm [" + realm
+ "] as an authorization realm - it is already delegating authorization to [" + realmAuthzSetting.get(globalSettings)
+ "]");
}
}
}

View File

@ -30,7 +30,6 @@ import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.env.Environment;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
@ -59,8 +58,8 @@ public class DnRoleMapper implements UserRoleMapper {
public DnRoleMapper(RealmConfig config, ResourceWatcherService watcherService) {
this.config = config;
useUnmappedGroupsAsRoles = DnRoleMapperSettings.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING.get(config.settings());
file = resolveFile(config.settings(), config.env());
useUnmappedGroupsAsRoles = config.getSetting(DnRoleMapperSettings.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING);
file = resolveFile(config);
dnRoles = parseFileLenient(file, logger, config.type(), config.name());
FileWatcher watcher = new FileWatcher(file.getParent());
watcher.addListener(new FileListener());
@ -80,9 +79,9 @@ public class DnRoleMapper implements UserRoleMapper {
listeners.add(Objects.requireNonNull(listener, "listener cannot be null"));
}
public static Path resolveFile(Settings settings, Environment env) {
String location = DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING.get(settings);
return XPackPlugin.resolveConfigFile(env, location);
public static Path resolveFile(RealmConfig realmConfig) {
String location = realmConfig.getSetting(DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING);
return XPackPlugin.resolveConfigFile(realmConfig.env(), location);
}
/**

View File

@ -43,8 +43,8 @@ public class RoleMappingFileBootstrapCheck implements BootstrapCheck {
}
public static BootstrapCheck create(RealmConfig realmConfig) {
if (realmConfig.enabled() && DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING.exists(realmConfig.settings())) {
Path file = DnRoleMapper.resolveFile(realmConfig.settings(), realmConfig.env());
if (realmConfig.enabled() && realmConfig.hasSetting(DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING)) {
Path file = DnRoleMapper.resolveFile(realmConfig);
return new RoleMappingFileBootstrapCheck(realmConfig, file);
}
return null;

View File

@ -13,8 +13,8 @@ import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken
abstract class UsernamePasswordRealm extends Realm {
UsernamePasswordRealm(String type, RealmConfig config) {
super(type, config);
UsernamePasswordRealm(RealmConfig config) {
super(config);
}
@Override

View File

@ -29,7 +29,7 @@ public class CompositeRoleMapper implements UserRoleMapper {
private List<UserRoleMapper> delegates;
public CompositeRoleMapper(String realmType, RealmConfig realmConfig,
public CompositeRoleMapper(RealmConfig realmConfig,
ResourceWatcherService watcherService,
NativeRoleMappingStore nativeRoleMappingStore) {
this(new DnRoleMapper(realmConfig, watcherService), nativeRoleMappingStore);

View File

@ -135,10 +135,8 @@ public class SecuritySettingsSource extends NodeConfigurationSource {
.put(LoggingAuditTrail.EMIT_HOST_NAME_SETTING.getKey(), randomBoolean())
.put(LoggingAuditTrail.EMIT_NODE_NAME_SETTING.getKey(), randomBoolean())
.put(LoggingAuditTrail.EMIT_NODE_ID_SETTING.getKey(), randomBoolean())
.put("xpack.security.authc.realms.file.type", FileRealmSettings.TYPE)
.put("xpack.security.authc.realms.file.order", 0)
.put("xpack.security.authc.realms.index.type", NativeRealmSettings.TYPE)
.put("xpack.security.authc.realms.index.order", "1");
.put("xpack.security.authc.realms." + FileRealmSettings.TYPE + ".file.order", 0)
.put("xpack.security.authc.realms." + NativeRealmSettings.TYPE + ".index.order", "1");
addNodeSSLSettings(builder);
return builder.build();
}

View File

@ -14,6 +14,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings;
import org.elasticsearch.xpack.security.LocalStateSecurity;
import org.hamcrest.Matcher;
@ -39,37 +40,35 @@ public class SettingsFilterTests extends ESTestCase {
public void testFiltering() throws Exception {
final boolean useLegacyLdapBindPassword = randomBoolean();
configureUnfilteredSetting("xpack.security.authc.realms.file.type", "file");
configureUnfilteredSetting("xpack.security.authc.realms.file.file1.enabled", "true");
// ldap realm filtering
configureUnfilteredSetting("xpack.security.authc.realms.ldap1.type", "ldap");
configureUnfilteredSetting("xpack.security.authc.realms.ldap1.enabled", "false");
configureUnfilteredSetting("xpack.security.authc.realms.ldap1.url", "ldap://host.domain");
configureFilteredSetting("xpack.security.authc.realms.ldap1.hostname_verification", Boolean.toString(randomBoolean()));
configureFilteredSetting("xpack.security.authc.realms.ldap1.bind_dn", randomAlphaOfLength(5));
configureUnfilteredSetting("xpack.security.authc.realms.ldap.ldap1.enabled", "false");
configureUnfilteredSetting("xpack.security.authc.realms.ldap.ldap1.url", "ldap://host.domain");
configureFilteredSetting("xpack.security.authc.realms.ldap.ldap1.hostname_verification", Boolean.toString(randomBoolean()));
configureFilteredSetting("xpack.security.authc.realms.ldap.ldap1.bind_dn", randomAlphaOfLength(5));
if (useLegacyLdapBindPassword) {
configureFilteredSetting("xpack.security.authc.realms.ldap1.bind_password", randomAlphaOfLength(5));
configureFilteredSetting("xpack.security.authc.realms.ldap.ldap1.bind_password", randomAlphaOfLength(5));
} else {
configureSecureSetting("xpack.security.authc.realms.ldap1.secure_bind_password", randomAlphaOfLengthBetween(3, 8));
configureSecureSetting("xpack.security.authc.realms.ldap.ldap1.secure_bind_password", randomAlphaOfLengthBetween(3, 8));
}
// active directory filtering
configureUnfilteredSetting("xpack.security.authc.realms.ad1.type", "active_directory");
configureUnfilteredSetting("xpack.security.authc.realms.ad1.enabled", "false");
configureUnfilteredSetting("xpack.security.authc.realms.ad1.url", "ldap://host.domain");
configureFilteredSetting("xpack.security.authc.realms.ad1.hostname_verification", Boolean.toString(randomBoolean()));
configureUnfilteredSetting("xpack.security.authc.realms.active_directory.ad1.enabled", "false");
configureUnfilteredSetting("xpack.security.authc.realms.active_directory.ad1.url", "ldap://host.domain");
configureFilteredSetting("xpack.security.authc.realms.active_directory.ad1.hostname_verification",
Boolean.toString(randomBoolean()));
// pki filtering
configureUnfilteredSetting("xpack.security.authc.realms.pki1.type", "pki");
configureUnfilteredSetting("xpack.security.authc.realms.pki1.order", "0");
configureUnfilteredSetting("xpack.security.authc.realms.pki.pki1.order", "0");
if (inFipsJvm() == false) {
configureFilteredSetting("xpack.security.authc.realms.pki1.truststore.path",
configureFilteredSetting("xpack.security.authc.realms.pki.pki1.truststore.path",
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks").toString());
configureFilteredSetting("xpack.ssl.keystore.path",
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks").toString());
}
configureSecureSetting("xpack.security.authc.realms.pki1.truststore.secure_password", "truststore-testnode-only");
configureFilteredSetting("xpack.security.authc.realms.pki1.truststore.algorithm", "SunX509");
configureSecureSetting("xpack.security.authc.realms.pki.pki1.truststore.secure_password", "truststore-testnode-only");
configureFilteredSetting("xpack.security.authc.realms.pki.pki1.truststore.algorithm", "SunX509");
configureFilteredSetting("xpack.ssl.cipher_suites",
@ -134,7 +133,9 @@ public class SettingsFilterTests extends ESTestCase {
}
if (useLegacyLdapBindPassword) {
assertSettingDeprecationsAndWarnings(new Setting<?>[]{PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD});
assertSettingDeprecationsAndWarnings(new Setting<?>[]{PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD
.apply(LdapRealmSettings.LDAP_TYPE)
.getConcreteSettingForNamespace("ldap1")});
}
}

View File

@ -12,7 +12,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.security.authc.pki.PkiRealmSettings;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.hamcrest.Matchers;
@ -26,7 +25,7 @@ public class PkiRealmBootstrapCheckTests extends ESTestCase {
public void testBootstrapCheckWithPkiRealm() throws Exception {
Settings settings = Settings.builder()
.put("xpack.security.authc.realms.test_pki.type", PkiRealmSettings.TYPE)
.put("xpack.security.authc.realms.pki.test_pki.order", 0)
.put("path.home", createTempDir())
.build();
Environment env = TestEnvironment.newEnvironment(settings);
@ -88,8 +87,7 @@ public class PkiRealmBootstrapCheckTests extends ESTestCase {
public void testBootstrapCheckWithDisabledRealm() throws Exception {
Settings settings = Settings.builder()
.put("xpack.security.authc.realms.test_pki.type", PkiRealmSettings.TYPE)
.put("xpack.security.authc.realms.test_pki.enabled", false)
.put("xpack.security.authc.realms.pki.test_pki.enabled", false)
.put("xpack.ssl.client_authentication", "none")
.put("path.home", createTempDir())
.build();
@ -102,7 +100,7 @@ public class PkiRealmBootstrapCheckTests extends ESTestCase {
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString("xpack.security.http.ssl.secure_key_passphrase", "testnode");
Settings settings = Settings.builder()
.put("xpack.security.authc.realms.test_pki.type", PkiRealmSettings.TYPE)
.put("xpack.security.authc.realms.pki.test_pki.order", 0)
.put("xpack.security.http.ssl.enabled", true)
.put("xpack.security.http.ssl.client_authentication", expectFail ? "none" : "optional")
.put("xpack.security.http.ssl.key",

View File

@ -36,7 +36,6 @@ import org.elasticsearch.xpack.core.security.SecurityExtension;
import org.elasticsearch.xpack.core.security.SecurityField;
import org.elasticsearch.xpack.core.security.authc.Realm;
import org.elasticsearch.xpack.core.security.authc.file.FileRealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
import org.elasticsearch.xpack.core.security.authz.AuthorizationServiceField;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissions;
@ -46,6 +45,7 @@ import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail;
import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail;
import org.elasticsearch.xpack.security.authc.Realms;
import org.hamcrest.Matchers;
import org.junit.Before;
import java.io.IOException;
@ -61,11 +61,13 @@ import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_FORMAT_SETTING;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_INDEX_FORMAT;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.mockito.Mockito.mock;
@ -79,9 +81,11 @@ public class SecurityTests extends ESTestCase {
public static class DummyExtension implements SecurityExtension {
private String realmType;
DummyExtension(String realmType) {
this.realmType = realmType;
}
@Override
public Map<String, Realm.Factory> getRealms(ResourceWatcherService resourceWatcherService) {
return Collections.singletonMap(realmType, config -> null);
@ -153,7 +157,7 @@ public class SecurityTests extends ESTestCase {
public void testCustomRealmExtensionConflict() throws Exception {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> createComponents(Settings.EMPTY, new DummyExtension(FileRealmSettings.TYPE)));
() -> createComponents(Settings.EMPTY, new DummyExtension(FileRealmSettings.TYPE)));
assertEquals("Realm type [" + FileRealmSettings.TYPE + "] is already registered", e.getMessage());
}
@ -175,8 +179,8 @@ public class SecurityTests extends ESTestCase {
public void testIndexAuditTrail() throws Exception {
Settings settings = Settings.builder()
.put(XPackSettings.AUDIT_ENABLED.getKey(), true)
.put(Security.AUDIT_OUTPUTS_SETTING.getKey(), "index").build();
.put(XPackSettings.AUDIT_ENABLED.getKey(), true)
.put(Security.AUDIT_OUTPUTS_SETTING.getKey(), "index").build();
Collection<Object> components = createComponents(settings);
AuditTrailService service = findComponent(AuditTrailService.class, components);
assertNotNull(service);
@ -186,8 +190,8 @@ public class SecurityTests extends ESTestCase {
public void testIndexAndLoggingAuditTrail() throws Exception {
Settings settings = Settings.builder()
.put(XPackSettings.AUDIT_ENABLED.getKey(), true)
.put(Security.AUDIT_OUTPUTS_SETTING.getKey(), "index,logfile").build();
.put(XPackSettings.AUDIT_ENABLED.getKey(), true)
.put(Security.AUDIT_OUTPUTS_SETTING.getKey(), "index,logfile").build();
Collection<Object> components = createComponents(settings);
AuditTrailService service = findComponent(AuditTrailService.class, components);
assertNotNull(service);
@ -198,8 +202,8 @@ public class SecurityTests extends ESTestCase {
public void testUnknownOutput() {
Settings settings = Settings.builder()
.put(XPackSettings.AUDIT_ENABLED.getKey(), true)
.put(Security.AUDIT_OUTPUTS_SETTING.getKey(), "foo").build();
.put(XPackSettings.AUDIT_ENABLED.getKey(), true)
.put(Security.AUDIT_OUTPUTS_SETTING.getKey(), "foo").build();
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> createComponents(settings));
assertEquals("Unknown audit trail output [foo]", e.getMessage());
}
@ -212,9 +216,9 @@ public class SecurityTests extends ESTestCase {
public void testTransportSettingNetty4Both() {
Settings both4 = Security.additionalSettings(Settings.builder()
.put(NetworkModule.TRANSPORT_TYPE_KEY, SecurityField.NAME4)
.put(NetworkModule.HTTP_TYPE_KEY, SecurityField.NAME4)
.build(), true, false);
.put(NetworkModule.TRANSPORT_TYPE_KEY, SecurityField.NAME4)
.put(NetworkModule.HTTP_TYPE_KEY, SecurityField.NAME4)
.build(), true, false);
assertFalse(NetworkModule.TRANSPORT_TYPE_SETTING.exists(both4));
assertFalse(NetworkModule.HTTP_TYPE_SETTING.exists(both4));
}
@ -237,12 +241,28 @@ public class SecurityTests extends ESTestCase {
public void testSettingFilter() throws Exception {
createComponents(Settings.EMPTY);
final List<String> filter = security.getSettingsFilter();
assertThat(filter, hasItem(SecurityField.setting("authc.realms.*.bind_dn")));
assertThat(filter, hasItem(SecurityField.setting("authc.realms.*.bind_password")));
assertThat(filter, hasItem(SecurityField.setting("authc.realms.*." + SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING)));
assertThat(filter, hasItem(SecurityField.setting("authc.realms.*.ssl.truststore.password")));
assertThat(filter, hasItem(SecurityField.setting("authc.realms.*.ssl.truststore.path")));
assertThat(filter, hasItem(SecurityField.setting("authc.realms.*.ssl.truststore.algorithm")));
assertThat(filter, hasItem("transport.profiles.*.xpack.security.*"));
}
public void testFilteredSettings() throws Exception {
createComponents(Settings.EMPTY);
final List<Setting<?>> realmSettings = security.getSettings().stream()
.filter(s -> s.getKey().startsWith("xpack.security.authc.realms"))
.collect(Collectors.toList());
Arrays.asList(
"bind_dn", "bind_password",
"hostname_verification",
"truststore.password", "truststore.path", "truststore.algorithm",
"keystore.key_password").forEach(suffix -> {
final List<Setting<?>> matching = realmSettings.stream()
.filter(s -> s.getKey().endsWith("." + suffix))
.collect(Collectors.toList());
assertThat("For suffix " + suffix, matching, Matchers.not(empty()));
matching.forEach(setting -> assertThat("For setting " + setting,
setting.getProperties(), Matchers.hasItem(Setting.Property.Filtered)));
});
}
public void testJoinValidatorOnDisabledSecurity() throws Exception {
@ -258,7 +278,7 @@ public class SecurityTests extends ESTestCase {
assertNotNull(joinValidator);
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
joinValidator.accept(node, ClusterState.builder(ClusterName.DEFAULT).build());
int numIters = randomIntBetween(1,10);
int numIters = randomIntBetween(1, 10);
for (int i = 0; i < numIters; i++) {
boolean tlsOn = randomBoolean();
String discoveryType = randomFrom("single-node", "zen", randomAlphaOfLength(4));
@ -318,18 +338,18 @@ public class SecurityTests extends ESTestCase {
assertNotNull(joinValidator);
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_INDEX_NAME)
.settings(settings(Version.V_6_1_0).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_INDEX_FORMAT - 1))
.numberOfShards(1).numberOfReplicas(0)
.build();
.settings(settings(Version.V_6_1_0).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_INDEX_FORMAT - 1))
.numberOfShards(1).numberOfReplicas(0)
.build();
DiscoveryNode existingOtherNode = new DiscoveryNode("bar", buildNewFakeTransportAddress(), Version.V_6_1_0);
DiscoveryNodes discoveryNodes = DiscoveryNodes.builder().add(existingOtherNode).build();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
.nodes(discoveryNodes)
.metaData(MetaData.builder().put(indexMetaData, true).build()).build();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
.nodes(discoveryNodes)
.metaData(MetaData.builder().put(indexMetaData, true).build()).build();
IllegalStateException e = expectThrows(IllegalStateException.class,
() -> joinValidator.accept(node, clusterState));
() -> joinValidator.accept(node, clusterState));
assertThat(e.getMessage(), equalTo("Security index is not on the current version [6] - " +
"The Upgrade API must be run for 7.x nodes to join the cluster"));
"The Upgrade API must be run for 7.x nodes to join the cluster"));
}
public void testIndexJoinValidator_FullyCurrentCluster() throws Exception {
@ -339,14 +359,14 @@ public class SecurityTests extends ESTestCase {
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
int indexFormat = randomBoolean() ? INTERNAL_INDEX_FORMAT : INTERNAL_INDEX_FORMAT - 1;
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_INDEX_NAME)
.settings(settings(Version.V_6_1_0).put(INDEX_FORMAT_SETTING.getKey(), indexFormat))
.numberOfShards(1).numberOfReplicas(0)
.build();
.settings(settings(Version.V_6_1_0).put(INDEX_FORMAT_SETTING.getKey(), indexFormat))
.numberOfShards(1).numberOfReplicas(0)
.build();
DiscoveryNode existingOtherNode = new DiscoveryNode("bar", buildNewFakeTransportAddress(), Version.CURRENT);
DiscoveryNodes discoveryNodes = DiscoveryNodes.builder().add(existingOtherNode).build();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
.nodes(discoveryNodes)
.metaData(MetaData.builder().put(indexMetaData, true).build()).build();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
.nodes(discoveryNodes)
.metaData(MetaData.builder().put(indexMetaData, true).build()).build();
joinValidator.accept(node, clusterState);
}
@ -357,14 +377,14 @@ public class SecurityTests extends ESTestCase {
Version version = randomBoolean() ? Version.CURRENT : Version.V_6_1_0;
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_INDEX_NAME)
.settings(settings(version).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_INDEX_FORMAT))
.numberOfShards(1).numberOfReplicas(0)
.build();
.settings(settings(version).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_INDEX_FORMAT))
.numberOfShards(1).numberOfReplicas(0)
.build();
DiscoveryNode existingOtherNode = new DiscoveryNode("bar", buildNewFakeTransportAddress(), version);
DiscoveryNodes discoveryNodes = DiscoveryNodes.builder().add(existingOtherNode).build();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
.nodes(discoveryNodes)
.metaData(MetaData.builder().put(indexMetaData, true).build()).build();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
.nodes(discoveryNodes)
.metaData(MetaData.builder().put(indexMetaData, true).build()).build();
joinValidator.accept(node, clusterState);
}
@ -375,8 +395,8 @@ public class SecurityTests extends ESTestCase {
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
DiscoveryNode existingOtherNode = new DiscoveryNode("bar", buildNewFakeTransportAddress(), Version.V_6_1_0);
DiscoveryNodes discoveryNodes = DiscoveryNodes.builder().add(existingOtherNode).build();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
.nodes(discoveryNodes).build();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
.nodes(discoveryNodes).build();
joinValidator.accept(node, clusterState);
}

View File

@ -54,6 +54,7 @@ import org.elasticsearch.xpack.core.security.action.saml.SamlInvalidateSessionRe
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmConfig.RealmIdentifier;
import org.elasticsearch.xpack.core.security.authc.esnative.NativeRealmSettings;
import org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings;
import org.elasticsearch.xpack.core.security.user.User;
@ -84,6 +85,7 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
@ -181,16 +183,20 @@ public class TransportSamlInvalidateSessionActionTests extends SamlTestCase {
final Path metadata = PathUtils.get(SamlRealm.class.getResource("idp1.xml").toURI());
final Environment env = TestEnvironment.newEnvironment(settings);
final RealmIdentifier identifier = new RealmIdentifier("saml", "saml1");
final Settings realmSettings = Settings.builder()
.put(SamlRealmSettings.IDP_METADATA_PATH.getKey(), metadata.toString())
.put(SamlRealmSettings.IDP_ENTITY_ID.getKey(), SamlRealmTests.TEST_IDP_ENTITY_ID)
.put(SamlRealmSettings.SP_ENTITY_ID.getKey(), SamlRealmTestHelper.SP_ENTITY_ID)
.put(SamlRealmSettings.SP_ACS.getKey(), SamlRealmTestHelper.SP_ACS_URL)
.put(SamlRealmSettings.SP_LOGOUT.getKey(), SamlRealmTestHelper.SP_LOGOUT_URL)
.put("attributes.principal", "uid")
.put(getFullSettingKey(identifier.getName(), SamlRealmSettings.IDP_METADATA_PATH), metadata.toString())
.put(getFullSettingKey(identifier.getName(), SamlRealmSettings.IDP_ENTITY_ID), SamlRealmTests.TEST_IDP_ENTITY_ID)
.put(getFullSettingKey(identifier.getName(), SamlRealmSettings.SP_ENTITY_ID), SamlRealmTestHelper.SP_ENTITY_ID)
.put(getFullSettingKey(identifier.getName(), SamlRealmSettings.SP_ACS), SamlRealmTestHelper.SP_ACS_URL)
.put(getFullSettingKey(identifier.getName(), SamlRealmSettings.SP_LOGOUT), SamlRealmTestHelper.SP_LOGOUT_URL)
.put(getFullSettingKey(identifier.getName(), SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getAttribute()), "uid")
.build();
final RealmConfig realmConfig = new RealmConfig("saml1", realmSettings, settings, env, threadContext);
final RealmConfig realmConfig = new RealmConfig(
identifier,
mergeSettings(realmSettings, settings),
env, threadContext);
samlRealm = SamlRealmTestHelper.buildRealm(realmConfig, null);
when(realms.realm(realmConfig.name())).thenReturn(samlRealm);
when(realms.stream()).thenAnswer(i -> Stream.of(samlRealm));

View File

@ -45,6 +45,7 @@ import org.elasticsearch.xpack.core.security.action.saml.SamlLogoutRequest;
import org.elasticsearch.xpack.core.security.action.saml.SamlLogoutResponse;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmConfig.RealmIdentifier;
import org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.ssl.SSLService;
@ -69,6 +70,7 @@ import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey;
import static org.elasticsearch.xpack.security.authc.TokenServiceTests.mockGetTokenFromId;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.startsWith;
@ -194,15 +196,18 @@ public class TransportSamlLogoutActionTests extends SamlTestCase {
final Path metadata = PathUtils.get(SamlRealm.class.getResource("idp1.xml").toURI());
final Environment env = TestEnvironment.newEnvironment(settings);
final RealmIdentifier realmIdentifier = new RealmIdentifier("saml", "saml1");
final Settings realmSettings = Settings.builder()
.put(SamlRealmSettings.IDP_METADATA_PATH.getKey(), metadata.toString())
.put(SamlRealmSettings.IDP_ENTITY_ID.getKey(), SamlRealmTests.TEST_IDP_ENTITY_ID)
.put(SamlRealmSettings.SP_ENTITY_ID.getKey(), SP_URL)
.put(SamlRealmSettings.SP_ACS.getKey(), SP_URL)
.put("attributes.principal", "uid")
.put(getFullSettingKey("saml1", SamlRealmSettings.IDP_METADATA_PATH), metadata.toString())
.put(getFullSettingKey("saml1", SamlRealmSettings.IDP_ENTITY_ID), SamlRealmTests.TEST_IDP_ENTITY_ID)
.put(getFullSettingKey("saml1", SamlRealmSettings.SP_ENTITY_ID), SP_URL)
.put(getFullSettingKey("saml1", SamlRealmSettings.SP_ACS), SP_URL)
.put(getFullSettingKey("saml1", SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getAttribute()), "uid")
.build();
final RealmConfig realmConfig = new RealmConfig("saml1", realmSettings, settings, env, threadContext);
final RealmConfig realmConfig = new RealmConfig(realmIdentifier, mergeSettings(realmSettings, settings),
env, threadContext);
samlRealm = SamlRealm.create(realmConfig, mock(SSLService.class), mock(ResourceWatcherService.class), mock(UserRoleMapper.class));
when(realms.realm(realmConfig.name())).thenReturn(samlRealm);
}
@ -219,7 +224,7 @@ public class TransportSamlLogoutActionTests extends SamlTestCase {
.put(SamlRealm.USER_METADATA_NAMEID_FORMAT, NameID.TRANSIENT)
.put(SamlRealm.USER_METADATA_NAMEID_VALUE, nameId)
.map();
final User user = new User("punisher", new String[] { "superuser" }, null, null, userMetaData, true);
final User user = new User("punisher", new String[]{"superuser"}, null, null, userMetaData, true);
final Authentication.RealmRef realmRef = new Authentication.RealmRef(samlRealm.name(), SamlRealmSettings.TYPE, "node01");
final Authentication authentication = new Authentication(user, realmRef, null);

View File

@ -46,12 +46,12 @@ public class InternalRealmsTests extends ESTestCase {
verifyZeroInteractions(securityIndex);
Settings settings = Settings.builder().put("path.home", createTempDir()).build();
factories.get(NativeRealmSettings.TYPE).create(new RealmConfig("test", Settings.EMPTY, settings,
TestEnvironment.newEnvironment(settings), new ThreadContext(settings)));
factories.get(NativeRealmSettings.TYPE).create(new RealmConfig(new RealmConfig.RealmIdentifier(NativeRealmSettings.TYPE, "test"),
Settings.EMPTY, settings, TestEnvironment.newEnvironment(settings), new ThreadContext(settings)));
verify(securityIndex).addIndexStateListener(isA(BiConsumer.class));
factories.get(NativeRealmSettings.TYPE).create(new RealmConfig("test", Settings.EMPTY, settings,
TestEnvironment.newEnvironment(settings), new ThreadContext(settings)));
factories.get(NativeRealmSettings.TYPE).create(new RealmConfig(new RealmConfig.RealmIdentifier(NativeRealmSettings.TYPE, "test"),
Settings.EMPTY, settings, TestEnvironment.newEnvironment(settings), new ThreadContext(settings)));
verify(securityIndex, times(2)).addIndexStateListener(isA(BiConsumer.class));
}

View File

@ -5,6 +5,7 @@
*/
package org.elasticsearch.xpack.security.authc;
import org.elasticsearch.common.settings.AbstractScopedSettings;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.SecureSettings;
import org.elasticsearch.common.settings.Setting;
@ -12,45 +13,26 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.security.SecurityExtension;
import org.elasticsearch.xpack.core.security.authc.InternalRealmsSettings;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.Hasher;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.notNullValue;
public class RealmSettingsTests extends ESTestCase {
private static final List<String> CACHE_HASHING_ALGOS = Arrays.stream(Hasher.values()).map(Hasher::name).collect(Collectors.toList());
public void testRealmWithoutTypeDoesNotValidate() throws Exception {
final Settings.Builder builder = baseSettings("x", false);
builder.remove("type");
assertErrorWithMessage("empty1", "missing realm type", realm("empty1", builder).build());
}
public void testRealmWithBlankTypeDoesNotValidate() throws Exception {
final Settings.Builder builder = baseSettings("", false);
assertErrorWithMessage("empty2", "missing realm type", realm("empty2", builder).build());
}
/**
* This test exists because (in 5.x), we want to be backwards compatible and accept custom realms that
* have not been updated to explicitly declare their settings.
*
* @see org.elasticsearch.xpack.core.security.SecurityExtension#getRealmSettings()
*/
public void testRealmWithUnknownTypeAcceptsAllSettings() throws Exception {
final Settings.Builder settings = baseSettings("tam", true)
.put("ip", "8.6.75.309")
.put(randomAlphaOfLengthBetween(4, 8), randomTimeValue());
assertSuccess(realm("tam", settings));
final Settings.Builder builder = baseSettings(false);
assertErrorWithMessage("", "empty", "unknown setting [" + realmPrefix("", "empty"), realm("", "empty", builder).build());
}
public void testFileRealmWithAllSettingsValidatesSuccessfully() throws Exception {
@ -58,8 +40,8 @@ public class RealmSettingsTests extends ESTestCase {
}
public void testFileRealmWithUnknownConfigurationDoesNotValidate() throws Exception {
final Settings.Builder builder = realm("file2", fileSettings().put("not-valid", randomInt()));
assertErrorWithCause("file2", "unknown setting [not-valid]", builder.build());
final Settings.Builder builder = realm("file", "file2", fileSettings().put("not-valid", randomInt()));
assertErrorWithMessage("file", "file2", "unknown setting [" + realmPrefix("file", "file2") + "not-valid]", builder.build());
}
public void testNativeRealmWithAllSettingsValidatesSuccessfully() throws Exception {
@ -67,8 +49,8 @@ public class RealmSettingsTests extends ESTestCase {
}
public void testNativeRealmWithUnknownConfigurationDoesNotValidate() throws Exception {
final Settings.Builder builder = realm("native2", nativeSettings().put("not-valid", randomAlphaOfLength(10)));
assertErrorWithCause("native2", "unknown setting [not-valid]", builder.build());
final Settings.Builder builder = realm("native", "native2", nativeSettings().put("not-valid", randomAlphaOfLength(10)));
assertErrorWithMessage("native", "native2", "unknown setting [" + realmPrefix("native", "native2") + "not-valid]", builder.build());
}
public void testLdapRealmWithUserTemplatesAndGroupAttributesValidatesSuccessfully() throws Exception {
@ -92,15 +74,8 @@ public class RealmSettingsTests extends ESTestCase {
}
public void testPkiRealmWithFullSslSettingsDoesNotValidate() throws Exception {
final Settings.Builder realm = realm("pki3", configureSsl("", pkiSettings(true), true, true));
assertError("pki3", realm.build());
}
public void testPkiRealmWithClosedSecurePasswordValidatesSuccessfully() throws Exception {
final Settings.Builder builder = pkiRealm("pki4", true);
builder.getSecureSettings().close();
final Settings settings = builder.build();
assertSuccess(settings);
final Settings.Builder realm = realm("pki", "pki3", configureSsl("", pkiSettings(true), true, true));
assertError("pki", "pki3", realm.build());
}
public void testSettingsWithMultipleRealmsValidatesSuccessfully() throws Exception {
@ -115,23 +90,23 @@ public class RealmSettingsTests extends ESTestCase {
}
private Settings.Builder nativeRealm(String name) {
return realm(name, nativeSettings());
return realm("native", name, nativeSettings());
}
private Settings.Builder nativeSettings() {
return baseSettings("native", true);
return baseSettings(true);
}
private Settings.Builder fileRealm(String name) {
return realm(name, fileSettings());
return realm("file", name, fileSettings());
}
private Settings.Builder fileSettings() {
return baseSettings("file", true);
return baseSettings(true);
}
private Settings.Builder ldapRealm(String name, boolean userSearch, boolean groupSearch) {
return realm(name, ldapSettings(userSearch, groupSearch));
return realm("ldap", name, ldapSettings(userSearch, groupSearch));
}
private Settings.Builder ldapSettings(boolean userSearch, boolean groupSearch) {
@ -140,7 +115,7 @@ public class RealmSettingsTests extends ESTestCase {
.put("follow_referrals", randomBoolean());
SecuritySettingsSource.addSecureSettings(builder, secureSettings -> {
secureSettings.setString("bind_password", "t0p_s3cr3t");
secureSettings.setString("secure_bind_password", "t0p_s3cr3t");
});
if (userSearch) {
@ -171,7 +146,7 @@ public class RealmSettingsTests extends ESTestCase {
}
private Settings.Builder activeDirectoryRealm(String name, boolean configureSSL) {
return realm(name, activeDirectorySettings(configureSSL));
return realm("active_directory", name, activeDirectorySettings(configureSSL));
}
private Settings.Builder activeDirectorySettings(boolean configureSSL) {
@ -186,7 +161,7 @@ public class RealmSettingsTests extends ESTestCase {
}
private Settings.Builder commonLdapSettings(String type, boolean configureSSL) {
final Settings.Builder builder = baseSettings(type, true)
final Settings.Builder builder = baseSettings(true)
.putList("url", "ldap://dir1.internal:9876", "ldap://dir2.internal:9876", "ldap://dir3.internal:9876")
.put("load_balance.type", "round_robin")
.put("load_balance.cache_ttl", randomTimeValue())
@ -202,11 +177,11 @@ public class RealmSettingsTests extends ESTestCase {
}
private Settings.Builder pkiRealm(String name, boolean useTrustStore) {
return realm(name, pkiSettings(useTrustStore));
return realm("pki", name, pkiSettings(useTrustStore));
}
private Settings.Builder pkiSettings(boolean useTrustStore) {
final Settings.Builder builder = baseSettings("pki", false)
final Settings.Builder builder = baseSettings(false)
.put("username_pattern", "CN=\\D(\\d+)(?:,\\|$)")
.put("files.role_mapping", "x-pack/" + randomAlphaOfLength(8) + ".yml");
@ -232,7 +207,7 @@ public class RealmSettingsTests extends ESTestCase {
} else {
builder.put(prefix + "key", "x-pack/ssl/" + randomAlphaOfLength(5) + ".key");
SecuritySettingsSource.addSecureSettings(builder, secureSettings ->
secureSettings.setString(prefix + "secure_key_passphrase", randomAlphaOfLength(32)));
secureSettings.setString(prefix + "secure_key_passphrase", randomAlphaOfLength(32)));
builder.put(prefix + "certificate", "ssl/" + randomAlphaOfLength(5) + ".cert");
}
@ -240,7 +215,7 @@ public class RealmSettingsTests extends ESTestCase {
if (useTrustStore) {
builder.put(prefix + "truststore.path", "x-pack/ssl/" + randomAlphaOfLength(5) + ".jts");
SecuritySettingsSource.addSecureSettings(builder, secureSettings ->
secureSettings.setString(prefix + "truststore.secure_password", randomAlphaOfLength(8)));
secureSettings.setString(prefix + "truststore.secure_password", randomAlphaOfLength(8)));
} else {
builder.put(prefix + "certificate_authorities", "ssl/" + randomAlphaOfLength(8) + ".ca");
}
@ -252,9 +227,8 @@ public class RealmSettingsTests extends ESTestCase {
return builder;
}
private Settings.Builder baseSettings(String type, boolean withCacheSettings) {
private Settings.Builder baseSettings(boolean withCacheSettings) {
final Settings.Builder builder = Settings.builder()
.put("type", type)
.put("order", randomInt())
.put("enabled", true);
if (withCacheSettings) {
@ -265,8 +239,8 @@ public class RealmSettingsTests extends ESTestCase {
return builder;
}
private Settings.Builder realm(String name, Settings.Builder settings) {
final String prefix = realmPrefix(name);
private Settings.Builder realm(String type, String name, Settings.Builder settings) {
final String prefix = realmPrefix(type, name);
final MockSecureSettings secureSettings = normaliseSecureSettingPrefix(prefix, settings.getSecureSettings());
final Settings.Builder builder = Settings.builder().put(settings.normalizePrefix(prefix).build(), false);
if (secureSettings != null) {
@ -291,8 +265,8 @@ public class RealmSettingsTests extends ESTestCase {
}
}
private String realmPrefix(String name) {
return RealmSettings.PREFIX + name + ".";
private String realmPrefix(String type, String name) {
return RealmSettings.PREFIX + type + "." + name + ".";
}
private void assertSuccess(Settings.Builder builder) {
@ -300,33 +274,37 @@ public class RealmSettingsTests extends ESTestCase {
}
private void assertSuccess(Settings settings) {
assertThat(group().get(settings), notNullValue());
try {
validate(settings);
} catch (RuntimeException e) {
fail("Settings do not validate: " + e);
}
}
private void assertErrorWithCause(String realmName, String message, Settings settings) {
final IllegalArgumentException exception = assertError(realmName, settings);
private void assertErrorWithCause(String realmType, String realmName, String message, Settings settings) {
final IllegalArgumentException exception = assertError(realmType, realmName, settings);
assertThat(exception.getCause(), notNullValue());
assertThat(exception.getCause().getMessage(), containsString(message));
}
private void assertErrorWithMessage(String realmName, String message, Settings settings) {
final IllegalArgumentException exception = assertError(realmName, settings);
private void assertErrorWithMessage(String realmType, String realmName, String message, Settings settings) {
final IllegalArgumentException exception = assertError(realmType, realmName, settings);
assertThat(exception.getMessage(), containsString(message));
}
private IllegalArgumentException assertError(String realmName, Settings settings) {
private IllegalArgumentException assertError(String realmType, String realmName, Settings settings) {
final IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
() -> group().get(settings)
() -> validate(settings)
);
assertThat(exception.getMessage(), containsString(realmPrefix(realmName)));
assertThat(exception.getMessage(), containsString(realmPrefix(realmType, realmName)));
return exception;
}
private Setting<?> group() {
final List<Setting<?>> list = new ArrayList<>();
final List<SecurityExtension> noExtensions = Collections.emptyList();
RealmSettings.addSettings(list, noExtensions);
assertThat(list, hasSize(1));
return list.get(0);
private void validate(Settings settings) {
final Set<Setting<?>> settingsSet = new HashSet<>(InternalRealmsSettings.getSettings());
final AbstractScopedSettings validator = new AbstractScopedSettings(settings, settingsSet, Collections.emptySet(),
Setting.Property.NodeScope) {
};
validator.validate(settings, false);
}
}

View File

@ -83,8 +83,7 @@ public class RealmsTests extends ESTestCase {
Collections.shuffle(orders, random());
Map<Integer, Integer> orderToIndex = new HashMap<>();
for (int i = 0; i < randomRealmTypesCount; i++) {
builder.put("xpack.security.authc.realms.realm_" + i + ".type", "type_" + i);
builder.put("xpack.security.authc.realms.realm_" + i + ".order", orders.get(i));
builder.put("xpack.security.authc.realms.type_" + i + ".realm_" + i + ".order", orders.get(i));
orderToIndex.put(orders.get(i), i);
}
Settings settings = builder.build();
@ -119,11 +118,10 @@ public class RealmsTests extends ESTestCase {
TreeMap<String, Integer> nameToRealmId = new TreeMap<>();
for (int i = 0; i < randomRealmTypesCount; i++) {
int randomizedRealmId = randomSeq.get(i);
String randomizedRealmName = randomAlphaOfLengthBetween(12,32);
String randomizedRealmName = randomAlphaOfLengthBetween(12, 32);
nameToRealmId.put("realm_" + randomizedRealmName, randomizedRealmId);
builder.put("xpack.security.authc.realms.realm_" + randomizedRealmName + ".type", "type_" + randomizedRealmId);
// set same order for all realms
builder.put("xpack.security.authc.realms.realm_" + randomizedRealmName + ".order", 1);
builder.put("xpack.security.authc.realms.type_" + randomizedRealmId + ".realm_" + randomizedRealmName + ".order", 1);
}
Settings settings = builder.build();
Environment env = TestEnvironment.newEnvironment(settings);
@ -148,10 +146,8 @@ public class RealmsTests extends ESTestCase {
public void testWithSettingsWithMultipleInternalRealmsOfSameType() throws Exception {
Settings settings = Settings.builder()
.put("xpack.security.authc.realms.realm_1.type", FileRealmSettings.TYPE)
.put("xpack.security.authc.realms.realm_1.order", 0)
.put("xpack.security.authc.realms.realm_2.type", FileRealmSettings.TYPE)
.put("xpack.security.authc.realms.realm_2.order", 1)
.put("xpack.security.authc.realms.file.realm_1.order", 0)
.put("xpack.security.authc.realms.file.realm_2.order", 1)
.put("path.home", createTempDir())
.build();
Environment env = TestEnvironment.newEnvironment(settings);
@ -191,8 +187,7 @@ public class RealmsTests extends ESTestCase {
Collections.shuffle(orders, random());
Map<Integer, Integer> orderToIndex = new HashMap<>();
for (int i = 0; i < randomRealmTypesCount; i++) {
builder.put("xpack.security.authc.realms.realm_" + i + ".type", "type_" + i);
builder.put("xpack.security.authc.realms.realm_" + i + ".order", orders.get(i));
builder.put("xpack.security.authc.realms.type_" + i + ".realm_" + i + ".order", orders.get(i));
orderToIndex.put(orders.get(i), i);
}
Settings settings = builder.build();
@ -252,13 +247,11 @@ public class RealmsTests extends ESTestCase {
assertThat(factories.get("type_0"), notNullValue());
Settings.Builder builder = Settings.builder()
.put("path.home", createTempDir())
.put("xpack.security.authc.realms.foo.type", "ldap")
.put("xpack.security.authc.realms.foo.order", "0")
.put("xpack.security.authc.realms.custom.type", "type_0")
.put("xpack.security.authc.realms.custom.order", "1");
.put("xpack.security.authc.realms.ldap.foo.order", "0")
.put("xpack.security.authc.realms.type_0.custom.order", "1");
Settings settings = builder.build();
Environment env = TestEnvironment.newEnvironment(settings);
Realms realms = new Realms(settings, env, factories, licenseState, threadContext, reservedRealm );
Realms realms = new Realms(settings, env, factories, licenseState, threadContext, reservedRealm);
Iterator<Realm> iter = realms.iterator();
assertThat(iter.hasNext(), is(true));
Realm realm = iter.next();
@ -282,7 +275,7 @@ public class RealmsTests extends ESTestCase {
i = 0;
while (iter.hasNext()) {
realm = iter.next();
assertThat(realm.getType(), is("ldap"));
assertThat(realm.type(), is("ldap"));
i++;
}
assertThat(i, is(1));
@ -303,15 +296,13 @@ public class RealmsTests extends ESTestCase {
assertThat(iter.hasNext(), is(false));
}
public void testUnlicensedWithNativeRealmSettingss() throws Exception {
public void testUnlicensedWithNativeRealmSettings() throws Exception {
factories.put(LdapRealmSettings.LDAP_TYPE, config -> new DummyRealm(LdapRealmSettings.LDAP_TYPE, config));
final String type = randomFrom(FileRealmSettings.TYPE, NativeRealmSettings.TYPE);
Settings.Builder builder = Settings.builder()
.put("path.home", createTempDir())
.put("xpack.security.authc.realms.foo.type", "ldap")
.put("xpack.security.authc.realms.foo.order", "0")
.put("xpack.security.authc.realms.native.type", type)
.put("xpack.security.authc.realms.native.order", "1");
.put("xpack.security.authc.realms.ldap.foo.order", "0")
.put("xpack.security.authc.realms." + type + ".native.order", "1");
Settings settings = builder.build();
Environment env = TestEnvironment.newEnvironment(settings);
Realms realms = new Realms(settings, env, factories, licenseState, threadContext, reservedRealm);
@ -343,8 +334,7 @@ public class RealmsTests extends ESTestCase {
factories.put(selectedRealmType, config -> new DummyRealm(selectedRealmType, config));
Settings.Builder builder = Settings.builder()
.put("path.home", createTempDir())
.put("xpack.security.authc.realms.foo.type", selectedRealmType)
.put("xpack.security.authc.realms.foo.order", "0");
.put("xpack.security.authc.realms." + selectedRealmType + ".foo.order", "0");
Settings settings = builder.build();
Environment env = TestEnvironment.newEnvironment(settings);
Realms realms = new Realms(settings, env, factories, licenseState, threadContext, reservedRealm);
@ -394,10 +384,9 @@ public class RealmsTests extends ESTestCase {
Collections.shuffle(orders, random());
Map<Integer, Integer> orderToIndex = new HashMap<>();
for (int i = 0; i < randomRealmTypesCount; i++) {
builder.put("xpack.security.authc.realms.realm_" + i + ".type", "type_" + i);
builder.put("xpack.security.authc.realms.realm_" + i + ".order", orders.get(i));
builder.put("xpack.security.authc.realms.type_" + i + ".realm_" + i + ".order", orders.get(i));
boolean enabled = randomBoolean();
builder.put("xpack.security.authc.realms.realm_" + i + ".enabled", enabled);
builder.put("xpack.security.authc.realms.type_" + i + ".realm_" + i + ".enabled", enabled);
if (enabled) {
orderToIndex.put(orders.get(i), i);
logger.error("put [{}] -> [{}]", orders.get(i), i);
@ -405,7 +394,7 @@ public class RealmsTests extends ESTestCase {
}
Settings settings = builder.build();
Environment env = TestEnvironment.newEnvironment(settings);
Realms realms = new Realms(settings, env, factories, licenseState, threadContext, reservedRealm );
Realms realms = new Realms(settings, env, factories, licenseState, threadContext, reservedRealm);
Iterator<Realm> iterator = realms.iterator();
Realm realm = iterator.next();
assertThat(realm, is(reservedRealm));
@ -438,11 +427,10 @@ public class RealmsTests extends ESTestCase {
public void testAuthcAuthzDisabled() throws Exception {
Settings settings = Settings.builder()
.put("path.home", createTempDir())
.put("xpack.security.authc.realms.realm_1.type", FileRealmSettings.TYPE)
.put("xpack.security.authc.realms.realm_1.order", 0)
.put("xpack.security.authc.realms." + FileRealmSettings.TYPE + ".realm_1.order", 0)
.build();
Environment env = TestEnvironment.newEnvironment(settings);
Realms realms = new Realms(settings, env, factories, licenseState, threadContext, reservedRealm );
Realms realms = new Realms(settings, env, factories, licenseState, threadContext, reservedRealm);
assertThat(realms.iterator().hasNext(), is(true));
@ -454,10 +442,8 @@ public class RealmsTests extends ESTestCase {
// test realms with duplicate values
Settings.Builder builder = Settings.builder()
.put("path.home", createTempDir())
.put("xpack.security.authc.realms.foo.type", "type_0")
.put("xpack.security.authc.realms.foo.order", "0")
.put("xpack.security.authc.realms.bar.type", "type_0")
.put("xpack.security.authc.realms.bar.order", "1");
.put("xpack.security.authc.realms.type_0.foo.order", "0")
.put("xpack.security.authc.realms.type_0.bar.order", "1");
Settings settings = builder.build();
Environment env = TestEnvironment.newEnvironment(settings);
Realms realms = new Realms(settings, env, factories, licenseState, threadContext, reservedRealm);
@ -525,10 +511,8 @@ public class RealmsTests extends ESTestCase {
public void testInitRealmsFailsForMultipleKerberosRealms() throws IOException {
final Settings.Builder builder = Settings.builder().put("path.home", createTempDir());
builder.put("xpack.security.authc.realms.realm_1.type", "kerberos");
builder.put("xpack.security.authc.realms.realm_1.order", 1);
builder.put("xpack.security.authc.realms.realm_2.type", "kerberos");
builder.put("xpack.security.authc.realms.realm_2.order", 2);
builder.put("xpack.security.authc.realms.kerberos.realm_1.order", 1);
builder.put("xpack.security.authc.realms.kerberos.realm_2.order", 2);
final Settings settings = builder.build();
Environment env = TestEnvironment.newEnvironment(settings);
final IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
@ -540,7 +524,7 @@ public class RealmsTests extends ESTestCase {
static class DummyRealm extends Realm {
DummyRealm(String type, RealmConfig config) {
super(type, config);
super(config);
}
@Override

View File

@ -32,8 +32,8 @@ public class NativeRealmTests extends ESTestCase {
final AtomicInteger numInvalidation = new AtomicInteger(0);
int expectedInvalidation = 0;
Settings settings = Settings.builder().put("path.home", createTempDir()).build();
RealmConfig config = new RealmConfig("native", Settings.EMPTY, settings, TestEnvironment.newEnvironment(settings),
new ThreadContext(settings));
RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("native", "native"), Settings.EMPTY,
settings, TestEnvironment.newEnvironment(settings), new ThreadContext(settings));
final NativeRealm nativeRealm = new NativeRealm(config, mock(NativeUsersStore.class), threadPool) {
@Override
void clearCache() {

View File

@ -15,6 +15,7 @@ import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.Hasher;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.user.User;
@ -42,6 +43,8 @@ import static org.mockito.Mockito.when;
public class FileRealmTests extends ESTestCase {
private static final RealmConfig.RealmIdentifier REALM_IDENTIFIER = new RealmConfig.RealmIdentifier("file", "file-test");
private static final Answer<AuthenticationResult> VERIFY_PASSWORD_ANSWER = inv -> {
assertThat(inv.getArguments().length, is(3));
Supplier<User> supplier = (Supplier<User>) inv.getArguments()[2];
@ -69,8 +72,7 @@ public class FileRealmTests extends ESTestCase {
when(userPasswdStore.verifyPassword(eq("user1"), eq(new SecureString("test123")), any(Supplier.class)))
.thenAnswer(VERIFY_PASSWORD_ANSWER);
when(userRolesStore.roles("user1")).thenReturn(new String[] { "role1", "role2" });
RealmConfig config = new RealmConfig("file-test", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings),
threadContext);
RealmConfig config = getRealmConfig(Settings.EMPTY);
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore, threadPool);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
@ -84,12 +86,17 @@ public class FileRealmTests extends ESTestCase {
assertThat(user.roles(), arrayContaining("role1", "role2"));
}
private RealmConfig getRealmConfig(Settings settings) {
return new RealmConfig(REALM_IDENTIFIER,
mergeSettings(settings, globalSettings),
TestEnvironment.newEnvironment(globalSettings), threadContext);
}
public void testAuthenticateCaching() throws Exception {
Settings settings = Settings.builder()
.put("cache.hash_algo", Hasher.values()[randomIntBetween(0, Hasher.values().length - 1)].name().toLowerCase(Locale.ROOT))
.build();
RealmConfig config = new RealmConfig("file-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
threadContext);
.put(RealmSettings.realmSettingPrefix(REALM_IDENTIFIER) + "cache.hash_algo",
Hasher.values()[randomIntBetween(0, Hasher.values().length - 1)].name().toLowerCase(Locale.ROOT)).build();
RealmConfig config = getRealmConfig(settings);
when(userPasswdStore.verifyPassword(eq("user1"), eq(new SecureString("test123")), any(Supplier.class)))
.thenAnswer(VERIFY_PASSWORD_ANSWER);
when(userRolesStore.roles("user1")).thenReturn(new String[]{"role1", "role2"});
@ -104,8 +111,7 @@ public class FileRealmTests extends ESTestCase {
}
public void testAuthenticateCachingRefresh() throws Exception {
RealmConfig config = new RealmConfig("file-test", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings),
threadContext);
RealmConfig config = getRealmConfig(Settings.EMPTY);
userPasswdStore = spy(new UserPasswdStore(config));
userRolesStore = spy(new UserRolesStore(config));
when(userPasswdStore.verifyPassword(eq("user1"), eq(new SecureString("test123")), any(Supplier.class)))
@ -144,8 +150,7 @@ public class FileRealmTests extends ESTestCase {
}
public void testToken() throws Exception {
RealmConfig config = new RealmConfig("file-test", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings),
threadContext);
RealmConfig config = getRealmConfig(Settings.EMPTY);
when(userPasswdStore.verifyPassword(eq("user1"), eq(new SecureString("test123")), any(Supplier.class)))
.thenAnswer(VERIFY_PASSWORD_ANSWER);
when(userRolesStore.roles("user1")).thenReturn(new String[]{"role1", "role2"});
@ -164,8 +169,7 @@ public class FileRealmTests extends ESTestCase {
public void testLookup() throws Exception {
when(userPasswdStore.userExists("user1")).thenReturn(true);
when(userRolesStore.roles("user1")).thenReturn(new String[] { "role1", "role2" });
RealmConfig config = new RealmConfig("file-test", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings),
threadContext);
RealmConfig config = getRealmConfig(Settings.EMPTY);
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore, threadPool);
PlainActionFuture<User> future = new PlainActionFuture<>();
@ -182,8 +186,7 @@ public class FileRealmTests extends ESTestCase {
public void testLookupCaching() throws Exception {
when(userPasswdStore.userExists("user1")).thenReturn(true);
when(userRolesStore.roles("user1")).thenReturn(new String[] { "role1", "role2" });
RealmConfig config = new RealmConfig("file-test", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings),
threadContext);
RealmConfig config = getRealmConfig(Settings.EMPTY);
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore, threadPool);
PlainActionFuture<User> future = new PlainActionFuture<>();
@ -198,8 +201,7 @@ public class FileRealmTests extends ESTestCase {
}
public void testLookupCachingWithRefresh() throws Exception {
RealmConfig config = new RealmConfig("file-test", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings),
threadContext);
RealmConfig config = getRealmConfig(Settings.EMPTY);
userPasswdStore = spy(new UserPasswdStore(config));
userRolesStore = spy(new UserRolesStore(config));
doReturn(true).when(userPasswdStore).userExists("user1");
@ -243,17 +245,16 @@ public class FileRealmTests extends ESTestCase {
Settings.Builder settings = Settings.builder();
int order = randomIntBetween(0, 10);
settings.put("order", order);
settings.put(RealmSettings.realmSettingPrefix(REALM_IDENTIFIER) + "order", order);
RealmConfig config = new RealmConfig("file-realm", settings.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings),
threadContext);
RealmConfig config = getRealmConfig(settings.build());
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore, threadPool);
PlainActionFuture<Map<String, Object>> future = new PlainActionFuture<>();
realm.usageStats(future);
Map<String, Object> usage = future.get();
assertThat(usage, is(notNullValue()));
assertThat(usage, hasEntry("name", "file-realm"));
assertThat(usage, hasEntry("name", REALM_IDENTIFIER.getName()));
assertThat(usage, hasEntry("order", order));
assertThat(usage, hasEntry("size", userCount));
}
@ -269,4 +270,9 @@ public class FileRealmTests extends ESTestCase {
super(config, mock(ResourceWatcherService.class));
}
}
private Settings mergeSettings(Settings local, Settings global) {
return Settings.builder().put(global).put(local).build();
}
}

View File

@ -76,7 +76,7 @@ public class FileUserPasswdStoreTests extends ESTestCase {
Files.write(file, Collections.singletonList("aldlfkjldjdflkjd"), StandardCharsets.UTF_16);
Settings fileSettings = randomBoolean() ? Settings.EMPTY : Settings.builder().put("files.users", file.toAbsolutePath()).build();
RealmConfig config = new RealmConfig("file-test", fileSettings, settings, env, threadPool.getThreadContext());
RealmConfig config = getRealmConfig(fileSettings);
ResourceWatcherService watcherService = new ResourceWatcherService(settings, threadPool);
FileUserPasswdStore store = new FileUserPasswdStore(config, watcherService);
assertThat(store.usersCount(), is(0));
@ -90,7 +90,7 @@ public class FileUserPasswdStoreTests extends ESTestCase {
Files.copy(users, file, StandardCopyOption.REPLACE_EXISTING);
final Hasher hasher = Hasher.resolve(settings.get("xpack.security.authc.password_hashing.algorithm"));
Settings fileSettings = randomBoolean() ? Settings.EMPTY : Settings.builder().put("files.users", file.toAbsolutePath()).build();
RealmConfig config = new RealmConfig("file-test", fileSettings, settings, env, threadPool.getThreadContext());
RealmConfig config = getRealmConfig(fileSettings);
ResourceWatcherService watcherService = new ResourceWatcherService(settings, threadPool);
final CountDownLatch latch = new CountDownLatch(1);
@ -120,6 +120,11 @@ public class FileUserPasswdStoreTests extends ESTestCase {
assertThat(result.getUser(), is(user));
}
private RealmConfig getRealmConfig(Settings fileSettings) {
final RealmConfig.RealmIdentifier identifier = new RealmConfig.RealmIdentifier("file", "file-test");
return new RealmConfig(identifier, fileSettings, settings, env, threadPool.getThreadContext());
}
public void testStore_AutoReload_WithParseFailures() throws Exception {
Path users = getDataPath("users");
Path xpackConf = env.configFile();
@ -131,7 +136,7 @@ public class FileUserPasswdStoreTests extends ESTestCase {
.put("files.users", testUsers.toAbsolutePath())
.build();
RealmConfig config = new RealmConfig("file-test", fileSettings, settings, env, threadPool.getThreadContext());
RealmConfig config = getRealmConfig(fileSettings);
ResourceWatcherService watcherService = new ResourceWatcherService(settings, threadPool);
final CountDownLatch latch = new CountDownLatch(1);

View File

@ -78,7 +78,8 @@ public class FileUserRolesStoreTests extends ESTestCase {
.put("files.users_roles", file.toAbsolutePath())
.build();
RealmConfig config = new RealmConfig("file-test", fileSettings, settings, env, new ThreadContext(Settings.EMPTY));
RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("file", "file-test"), fileSettings, settings, env,
new ThreadContext(Settings.EMPTY));
ResourceWatcherService watcherService = new ResourceWatcherService(settings, threadPool);
FileUserRolesStore store = new FileUserRolesStore(config, watcherService);
assertThat(store.entriesCount(), is(0));
@ -93,7 +94,8 @@ public class FileUserRolesStoreTests extends ESTestCase {
.put("files.users_roles", tmp.toAbsolutePath())
.build();
RealmConfig config = new RealmConfig("file-test", fileSettings, settings, env, new ThreadContext(Settings.EMPTY));
RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("file", "file-test"), fileSettings, settings, env,
new ThreadContext(Settings.EMPTY));
ResourceWatcherService watcherService = new ResourceWatcherService(settings, threadPool);
final CountDownLatch latch = new CountDownLatch(1);
@ -131,7 +133,8 @@ public class FileUserRolesStoreTests extends ESTestCase {
.put("files.users_roles", tmp.toAbsolutePath())
.build();
RealmConfig config = new RealmConfig("file-test", fileSettings, settings, env, new ThreadContext(Settings.EMPTY));
RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("file", "file-test"), fileSettings, settings, env,
new ThreadContext(Settings.EMPTY));
ResourceWatcherService watcherService = new ResourceWatcherService(settings, threadPool);
final CountDownLatch latch = new CountDownLatch(1);
@ -224,7 +227,8 @@ public class FileUserRolesStoreTests extends ESTestCase {
.build();
Environment env = TestEnvironment.newEnvironment(settings);
RealmConfig config = new RealmConfig("file-test", fileSettings, settings, env, new ThreadContext(Settings.EMPTY));
RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("file", "file-test"), fileSettings, settings, env,
new ThreadContext(Settings.EMPTY));
ResourceWatcherService watcherService = new ResourceWatcherService(settings, threadPool);
FileUserRolesStore store = new FileUserRolesStore(config, watcherService);
assertThat(store.roles("user"), equalTo(Strings.EMPTY_ARRAY));

View File

@ -18,10 +18,11 @@ import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.authc.support.MockLookupRealm;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.authc.support.MockLookupRealm;
import org.ietf.jgss.GSSException;
import javax.security.auth.login.LoginException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Collections;
@ -29,8 +30,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.security.auth.login.LoginException;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
@ -60,8 +59,8 @@ public class KerberosRealmAuthenticateFailedTests extends KerberosRealmTestCase
final boolean throwExceptionForInvalidTicket = validTicket ? false : randomBoolean();
final boolean throwLoginException = randomBoolean();
final byte[] decodedTicket = randomByteArrayOfLength(5);
final Path keytabPath = config.env().configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(config.settings()));
final boolean krbDebug = KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.get(config.settings());
final Path keytabPath = config.env().configFile().resolve(config.getSetting(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH));
final boolean krbDebug = config.getSetting(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE);
if (validTicket) {
mockKerberosTicketValidator(decodedTicket, keytabPath, krbDebug, new Tuple<>(username, outToken), null);
} else {
@ -122,16 +121,16 @@ public class KerberosRealmAuthenticateFailedTests extends KerberosRealmTestCase
public void testDelegatedAuthorizationFailedToResolve() throws Exception {
final String username = randomPrincipalName();
final MockLookupRealm otherRealm = new MockLookupRealm(new RealmConfig("other_realm", Settings.EMPTY, globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)));
final MockLookupRealm otherRealm = new MockLookupRealm(new RealmConfig(new RealmConfig.RealmIdentifier("mock", "other_realm"),
Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)));
final User lookupUser = new User(randomAlphaOfLength(5));
otherRealm.registerUser(lookupUser);
settings = Settings.builder().put(settings).putList("authorization_realms", "other_realm").build();
final KerberosRealm kerberosRealm = createKerberosRealm(Collections.singletonList(otherRealm), username);
final byte[] decodedTicket = "base64encodedticket".getBytes(StandardCharsets.UTF_8);
final Path keytabPath = config.env().configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(config.settings()));
final boolean krbDebug = KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.get(config.settings());
final Path keytabPath = config.env().configFile().resolve(config.getSetting(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH));
final boolean krbDebug = config.getSetting(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE);
mockKerberosTicketValidator(decodedTicket, keytabPath, krbDebug, new Tuple<>(username, "out-token"), null);
final KerberosAuthenticationToken kerberosAuthenticationToken = new KerberosAuthenticationToken(decodedTicket);

View File

@ -15,6 +15,7 @@ import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper.UserData;
import org.ietf.jgss.GSSException;
import javax.security.auth.login.LoginException;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
@ -22,8 +23,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.security.auth.login.LoginException;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;
@ -47,8 +46,8 @@ public class KerberosRealmCacheTests extends KerberosRealmTestCase {
metadata.put(KerberosRealm.KRB_METADATA_UPN_KEY, username);
final User expectedUser = new User(expectedUsername, roles.toArray(new String[roles.size()]), null, null, metadata, true);
final byte[] decodedTicket = randomByteArrayOfLength(10);
final Path keytabPath = config.env().configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(config.settings()));
final boolean krbDebug = KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.get(config.settings());
final Path keytabPath = config.env().configFile().resolve(config.getSetting(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH));
final boolean krbDebug = config.getSetting(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE);
mockKerberosTicketValidator(decodedTicket, keytabPath, krbDebug, new Tuple<>(username, outToken), null);
final KerberosAuthenticationToken kerberosAuthenticationToken = new KerberosAuthenticationToken(decodedTicket);
@ -73,8 +72,8 @@ public class KerberosRealmCacheTests extends KerberosRealmTestCase {
final String authNUsername = randomFrom(userNames);
final byte[] decodedTicket = randomByteArrayOfLength(10);
final Path keytabPath = config.env().configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(config.settings()));
final boolean krbDebug = KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.get(config.settings());
final Path keytabPath = config.env().configFile().resolve(config.getSetting(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH));
final boolean krbDebug = config.getSetting(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE);
mockKerberosTicketValidator(decodedTicket, keytabPath, krbDebug, new Tuple<>(authNUsername, outToken), null);
final String expectedUsername = maybeRemoveRealmName(authNUsername);
final Map<String, Object> metadata = new HashMap<>();
@ -110,9 +109,8 @@ public class KerberosRealmCacheTests extends KerberosRealmTestCase {
public void testAuthenticateWithValidTicketSucessAuthnWithUserDetailsWhenCacheDisabled()
throws LoginException, GSSException, IOException {
// if cache.ttl <= 0 then the cache is disabled
settings = buildKerberosRealmSettings(
writeKeyTab(dir.resolve("key.keytab"), randomAlphaOfLength(4)).toString(), 100, "0m", true,
randomBoolean());
settings = buildKerberosRealmSettings(REALM_NAME,
writeKeyTab(dir.resolve("key.keytab"), randomAlphaOfLength(4)).toString(), 100, "0m", true, randomBoolean());
final String username = randomPrincipalName();
final String outToken = randomAlphaOfLength(10);
final KerberosRealm kerberosRealm = createKerberosRealm(username);
@ -123,8 +121,8 @@ public class KerberosRealmCacheTests extends KerberosRealmTestCase {
metadata.put(KerberosRealm.KRB_METADATA_UPN_KEY, username);
final User expectedUser = new User(expectedUsername, roles.toArray(new String[roles.size()]), null, null, metadata, true);
final byte[] decodedTicket = randomByteArrayOfLength(10);
final Path keytabPath = config.env().configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(config.settings()));
final boolean krbDebug = KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.get(config.settings());
final Path keytabPath = config.env().configFile().resolve(config.getSetting(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH));
final boolean krbDebug = config.getSetting(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE);
mockKerberosTicketValidator(decodedTicket, keytabPath, krbDebug, new Tuple<>(username, outToken), null);
final KerberosAuthenticationToken kerberosAuthenticationToken = new KerberosAuthenticationToken(decodedTicket);

View File

@ -8,7 +8,11 @@ package org.elasticsearch.xpack.security.authc.kerberos;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmConfig.RealmIdentifier;
import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings;
import java.io.IOException;
@ -32,15 +36,18 @@ public class KerberosRealmSettingsTests extends ESTestCase {
final String cacheTTL = randomLongBetween(10L, 100L) + "m";
final boolean enableDebugLogs = randomBoolean();
final boolean removeRealmName = randomBoolean();
final Settings settings = KerberosRealmTestCase.buildKerberosRealmSettings(keytabPathConfig, maxUsers, cacheTTL, enableDebugLogs,
removeRealmName);
final Settings settings = KerberosRealmTestCase.buildKerberosRealmSettings(KerberosRealmTestCase.REALM_NAME,
keytabPathConfig, maxUsers, cacheTTL, enableDebugLogs, removeRealmName);
final RealmIdentifier identifier = new RealmIdentifier(KerberosRealmSettings.TYPE, KerberosRealmTestCase.REALM_NAME);
final RealmConfig config = new RealmConfig(identifier,
settings, TestEnvironment.newEnvironment(settings), new ThreadContext(settings));
assertThat(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(settings), equalTo(keytabPathConfig));
assertThat(KerberosRealmSettings.CACHE_TTL_SETTING.get(settings),
assertThat(config.getSetting(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH), equalTo(keytabPathConfig));
assertThat(config.getSetting(KerberosRealmSettings.CACHE_TTL_SETTING),
equalTo(TimeValue.parseTimeValue(cacheTTL, KerberosRealmSettings.CACHE_TTL_SETTING.getKey())));
assertThat(KerberosRealmSettings.CACHE_MAX_USERS_SETTING.get(settings), equalTo(maxUsers));
assertThat(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.get(settings), is(enableDebugLogs));
assertThat(KerberosRealmSettings.SETTING_REMOVE_REALM_NAME.get(settings), is(removeRealmName));
assertThat(config.getSetting(KerberosRealmSettings.CACHE_MAX_USERS_SETTING), equalTo(maxUsers));
assertThat(config.getSetting(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE), is(enableDebugLogs));
assertThat(config.getSetting(KerberosRealmSettings.SETTING_REMOVE_REALM_NAME), is(removeRealmName));
}
}

View File

@ -22,6 +22,7 @@ import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.core.security.authc.Realm;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings;
import org.elasticsearch.xpack.core.security.support.Exceptions;
import org.elasticsearch.xpack.core.security.user.User;
@ -57,6 +58,8 @@ import static org.mockito.Mockito.when;
public abstract class KerberosRealmTestCase extends ESTestCase {
protected static final String REALM_NAME = "test-kerb-realm";
protected Path dir;
protected ThreadPool threadPool;
protected Settings globalSettings;
@ -76,8 +79,8 @@ public abstract class KerberosRealmTestCase extends ESTestCase {
resourceWatcherService = new ResourceWatcherService(Settings.EMPTY, threadPool);
dir = createTempDir();
globalSettings = Settings.builder().put("path.home", dir).build();
settings = buildKerberosRealmSettings(writeKeyTab(dir.resolve("key.keytab"), "asa").toString(),
100, "10m", true, randomBoolean());
settings = buildKerberosRealmSettings(REALM_NAME,
writeKeyTab(dir.resolve("key.keytab"), "asa").toString(), 100, "10m", true, randomBoolean());
licenseState = mock(XPackLicenseState.class);
when(licenseState.isAuthorizationRealmAllowed()).thenReturn(true);
}
@ -89,7 +92,7 @@ public abstract class KerberosRealmTestCase extends ESTestCase {
}
protected void mockKerberosTicketValidator(final byte[] decodedTicket, final Path keytabPath, final boolean krbDebug,
final Tuple<String, String> value, final Exception e) {
final Tuple<String, String> value, final Exception e) {
assert value != null || e != null;
doAnswer((i) -> {
ActionListener<Tuple<String, String>> listener = (ActionListener<Tuple<String, String>>) i.getArguments()[3];
@ -109,7 +112,7 @@ public abstract class KerberosRealmTestCase extends ESTestCase {
final Map<String, List<String>> responseHeaders = threadPool.getThreadContext().getResponseHeaders();
assertThat(responseHeaders, is(notNullValue()));
assertThat(responseHeaders.get(KerberosAuthenticationToken.WWW_AUTHENTICATE).get(0),
is(equalTo(KerberosAuthenticationToken.NEGOTIATE_AUTH_HEADER_PREFIX + outToken)));
is(equalTo(KerberosAuthenticationToken.NEGOTIATE_AUTH_HEADER_PREFIX + outToken)));
}
protected KerberosRealm createKerberosRealm(final String... userForRoleMapping) {
@ -117,17 +120,25 @@ public abstract class KerberosRealmTestCase extends ESTestCase {
}
protected KerberosRealm createKerberosRealm(final List<Realm> delegatedRealms, final String... userForRoleMapping) {
config = new RealmConfig("test-kerb-realm", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
final RealmConfig.RealmIdentifier id = new RealmConfig.RealmIdentifier(KerberosRealmSettings.TYPE, REALM_NAME);
config = new RealmConfig(id, merge(id, settings, globalSettings),
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
mockNativeRoleMappingStore = roleMappingStore(Arrays.asList(userForRoleMapping));
mockKerberosTicketValidator = mock(KerberosTicketValidator.class);
final KerberosRealm kerberosRealm =
new KerberosRealm(config, mockNativeRoleMappingStore, mockKerberosTicketValidator, threadPool, null);
new KerberosRealm(config, mockNativeRoleMappingStore, mockKerberosTicketValidator, threadPool, null);
Collections.shuffle(delegatedRealms, random());
kerberosRealm.initialize(delegatedRealms, licenseState);
return kerberosRealm;
}
private Settings merge(RealmConfig.RealmIdentifier identifier, Settings realmSettings, Settings globalSettings) {
return Settings.builder().put(realmSettings)
.normalizePrefix(RealmSettings.realmSettingPrefix(identifier))
.put(globalSettings)
.build();
}
@SuppressWarnings("unchecked")
protected NativeRoleMappingStore roleMappingStore(final List<String> userNames) {
final List<String> expectedUserNames = userNames.stream().map(this::maybeRemoveRealmName).collect(Collectors.toList());
@ -145,7 +156,7 @@ public abstract class KerberosRealmTestCase extends ESTestCase {
listener.onResponse(roles);
} else {
listener.onFailure(
Exceptions.authorizationError("Expected UPN '" + expectedUserNames + "' but was '" + userData.getUsername() + "'"));
Exceptions.authorizationError("Expected UPN '" + expectedUserNames + "' but was '" + userData.getUsername() + "'"));
}
return null;
}).when(roleMapper).resolveRoles(any(UserRoleMapper.UserData.class), any(ActionListener.class));
@ -175,7 +186,11 @@ public abstract class KerberosRealmTestCase extends ESTestCase {
* @return username after removal of realm
*/
protected String maybeRemoveRealmName(final String principalName) {
if (KerberosRealmSettings.SETTING_REMOVE_REALM_NAME.get(settings)) {
return maybeRemoveRealmName(REALM_NAME, principalName);
}
protected String maybeRemoveRealmName(String realmName, final String principalName) {
if (KerberosRealmSettings.SETTING_REMOVE_REALM_NAME.getConcreteSettingForNamespace(realmName).get(settings)) {
int foundAtIndex = principalName.indexOf('@');
if (foundAtIndex > 0) {
return principalName.substring(0, foundAtIndex);
@ -218,27 +233,39 @@ public abstract class KerberosRealmTestCase extends ESTestCase {
* @param keytabPath key tab file path
* @return {@link Settings} for kerberos realm
*/
public static Settings buildKerberosRealmSettings(final String keytabPath) {
return buildKerberosRealmSettings(keytabPath, 100, "10m", true, false);
public static Settings buildKerberosRealmSettings(final String realmName,final String keytabPath) {
return buildKerberosRealmSettings(realmName, keytabPath, 100, "10m", true, false);
}
public static Settings buildKerberosRealmSettings(String realmName, String keytabPath, int maxUsersInCache, String cacheTTL,
boolean enableDebugging, boolean removeRealmName) {
final Settings global = Settings.builder().put("path.home", createTempDir()).build();
return buildKerberosRealmSettings(realmName, keytabPath, maxUsersInCache, cacheTTL, enableDebugging, removeRealmName, global);
}
/**
* Build kerberos realm settings
*
* @param keytabPath key tab file path
* @param realmName the name of the realm to configure
* @param keytabPath key tab file path
* @param maxUsersInCache max users to be maintained in cache
* @param cacheTTL time to live for cached entries
* @param cacheTTL time to live for cached entries
* @param enableDebugging for krb5 logs
* @param removeRealmName {@code true} if we want to remove realm name from the username of form 'user@REALM'
* @param globalSettings Any global settings to include
* @return {@link Settings} for kerberos realm
*/
public static Settings buildKerberosRealmSettings(final String keytabPath, final int maxUsersInCache, final String cacheTTL,
final boolean enableDebugging, final boolean removeRealmName) {
final Settings.Builder builder = Settings.builder().put(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.getKey(), keytabPath)
.put(KerberosRealmSettings.CACHE_MAX_USERS_SETTING.getKey(), maxUsersInCache)
.put(KerberosRealmSettings.CACHE_TTL_SETTING.getKey(), cacheTTL)
.put(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.getKey(), enableDebugging)
.put(KerberosRealmSettings.SETTING_REMOVE_REALM_NAME.getKey(), removeRealmName);
public static Settings buildKerberosRealmSettings(String realmName, String keytabPath, int maxUsersInCache, String cacheTTL,
boolean enableDebugging, boolean removeRealmName, Settings globalSettings) {
final Settings.Builder builder = Settings.builder()
.put(RealmSettings.getFullSettingKey(realmName, KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH), keytabPath)
.put(RealmSettings.getFullSettingKey(realmName, KerberosRealmSettings.CACHE_MAX_USERS_SETTING), maxUsersInCache)
.put(RealmSettings.getFullSettingKey(realmName, KerberosRealmSettings.CACHE_TTL_SETTING), cacheTTL)
.put(RealmSettings.getFullSettingKey(realmName, KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE), enableDebugging)
.put(RealmSettings.getFullSettingKey(realmName, KerberosRealmSettings.SETTING_REMOVE_REALM_NAME), removeRealmName)
.put(globalSettings);
return builder.build();
}
}

View File

@ -15,16 +15,17 @@ import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.authc.support.MockLookupRealm;
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper.UserData;
import org.ietf.jgss.GSSException;
import javax.security.auth.login.LoginException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
@ -43,8 +44,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.security.auth.login.LoginException;
import static org.elasticsearch.xpack.security.authc.kerberos.KerberosRealmTestCase.buildKerberosRealmSettings;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
@ -78,8 +78,8 @@ public class KerberosRealmTests extends KerberosRealmTestCase {
metadata.put(KerberosRealm.KRB_METADATA_UPN_KEY, username);
final User expectedUser = new User(expectedUsername, roles.toArray(new String[roles.size()]), null, null, metadata, true);
final byte[] decodedTicket = "base64encodedticket".getBytes(StandardCharsets.UTF_8);
final Path keytabPath = config.env().configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(config.settings()));
final boolean krbDebug = KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.get(config.settings());
final Path keytabPath = config.env().configFile().resolve(config.getSetting(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH));
final boolean krbDebug = config.getSetting(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE);
mockKerberosTicketValidator(decodedTicket, keytabPath, krbDebug, new Tuple<>(username, "out-token"), null);
final KerberosAuthenticationToken kerberosAuthenticationToken = new KerberosAuthenticationToken(decodedTicket);
@ -98,8 +98,8 @@ public class KerberosRealmTests extends KerberosRealmTestCase {
final String username = randomPrincipalName();
final KerberosRealm kerberosRealm = createKerberosRealm(username);
final byte[] decodedTicket = "base64encodedticket".getBytes(StandardCharsets.UTF_8);
final Path keytabPath = config.env().configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(config.settings()));
final boolean krbDebug = KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.get(config.settings());
final Path keytabPath = config.env().configFile().resolve(config.getSetting(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH));
final boolean krbDebug = config.getSetting(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE);
mockKerberosTicketValidator(decodedTicket, keytabPath, krbDebug, new Tuple<>("does-not-exist@REALM", "out-token"), null);
final PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
@ -160,9 +160,10 @@ public class KerberosRealmTests extends KerberosRealmTestCase {
}
private void assertKerberosRealmConstructorFails(final String keytabPath, final String expectedErrorMessage) {
settings = buildKerberosRealmSettings(keytabPath, 100, "10m", true, randomBoolean());
config = new RealmConfig("test-kerb-realm", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
final String realmName = "test-kerb-realm";
settings = buildKerberosRealmSettings(realmName, keytabPath, 100, "10m", true, randomBoolean(), globalSettings);
config = new RealmConfig(new RealmConfig.RealmIdentifier(KerberosRealmSettings.TYPE, realmName), settings,
TestEnvironment.newEnvironment(settings), new ThreadContext(settings));
mockNativeRoleMappingStore = roleMappingStore(Arrays.asList("user"));
mockKerberosTicketValidator = mock(KerberosTicketValidator.class);
final IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
@ -173,8 +174,8 @@ public class KerberosRealmTests extends KerberosRealmTestCase {
public void testDelegatedAuthorization() throws Exception {
final String username = randomPrincipalName();
final String expectedUsername = maybeRemoveRealmName(username);
final MockLookupRealm otherRealm = spy(new MockLookupRealm(new RealmConfig("other_realm", Settings.EMPTY, globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings))));
final MockLookupRealm otherRealm = spy(new MockLookupRealm(new RealmConfig(new RealmConfig.RealmIdentifier("mock", "other_realm"),
globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings))));
final User lookupUser = new User(expectedUsername, new String[] { "admin-role" }, expectedUsername,
expectedUsername + "@example.com", Collections.singletonMap("k1", "v1"), true);
otherRealm.registerUser(lookupUser);
@ -183,8 +184,8 @@ public class KerberosRealmTests extends KerberosRealmTestCase {
final KerberosRealm kerberosRealm = createKerberosRealm(Collections.singletonList(otherRealm), username);
final User expectedUser = lookupUser;
final byte[] decodedTicket = "base64encodedticket".getBytes(StandardCharsets.UTF_8);
final Path keytabPath = config.env().configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(config.settings()));
final boolean krbDebug = KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.get(config.settings());
final Path keytabPath = config.env().configFile().resolve(config.getSetting(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH));
final boolean krbDebug = config.getSetting(KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE);
mockKerberosTicketValidator(decodedTicket, keytabPath, krbDebug, new Tuple<>(username, "out-token"), null);
final KerberosAuthenticationToken kerberosAuthenticationToken = new KerberosAuthenticationToken(decodedTicket);

View File

@ -33,11 +33,13 @@ import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.ldap.ActiveDirectorySessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapLoadBalancingSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.support.CachingUsernamePasswordRealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.DnRoleMapperSettings;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.core.ssl.VerificationMode;
import org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactory.DownLevelADAuthenticator;
@ -52,8 +54,10 @@ import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.URLS_SETTING;
import static org.hamcrest.Matchers.arrayContaining;
@ -85,7 +89,6 @@ import static org.mockito.Mockito.verify;
public class ActiveDirectoryRealmTests extends ESTestCase {
private static final String PASSWORD = "password";
private static final String ROLE_MAPPING_FILE_SETTING = DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING.getKey();
static int numberOfLdapServers;
InMemoryDirectoryServer[] directoryServers;
@ -150,24 +153,24 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
* Creates a realm with the provided settings, rebuilds the SSL Service to be aware of the new realm, and then returns
* the RealmConfig
*/
private RealmConfig setupRealm(String realmName, Settings settings) {
final Settings merged = Settings.builder()
.put(settings)
.normalizePrefix("xpack.security.authc.realms." + realmName + ".")
.put(globalSettings)
.build();
final Environment env = TestEnvironment.newEnvironment(merged);
this.sslService = new SSLService(merged, env);
return new RealmConfig(realmName, settings, merged, env, new ThreadContext(merged));
private RealmConfig setupRealm(RealmConfig.RealmIdentifier realmIdentifier, Settings localSettings) {
final Settings mergedSettings = Settings.builder().put(globalSettings).put(localSettings).build();
final Environment env = TestEnvironment.newEnvironment(mergedSettings);
this.sslService = new SSLService(mergedSettings, env);
return new RealmConfig(
realmIdentifier,
mergedSettings,
env, new ThreadContext(mergedSettings)
);
}
public void testAuthenticateUserPrincipleName() throws Exception {
Settings settings = settings();
RealmConfig config = setupRealm("testAuthenticateUserPrincipleName", settings);
final RealmConfig.RealmIdentifier realmIdentifier = realmId("testAuthenticateUserPrincipleName");
Settings settings = settings(realmIdentifier);
RealmConfig config = setupRealm(realmIdentifier, settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
LdapRealm realm = new LdapRealm(config, sessionFactory, roleMapper, threadPool);
realm.initialize(Collections.singleton(realm), licenseState);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
@ -180,11 +183,12 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
}
public void testAuthenticateSAMAccountName() throws Exception {
Settings settings = settings();
RealmConfig config = setupRealm("testAuthenticateSAMAccountName", settings);
final RealmConfig.RealmIdentifier realmIdentifier = realmId("testAuthenticateSAMAccountName");
Settings settings = settings(realmIdentifier);
RealmConfig config = setupRealm(realmIdentifier, settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
LdapRealm realm = new LdapRealm(config, sessionFactory, roleMapper, threadPool);
realm.initialize(Collections.singleton(realm), licenseState);
// Thor does not have a UPN of form CN=Thor@ad.test.elasticsearch.com
@ -205,11 +209,12 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
}
public void testAuthenticateCachesSuccessfulAuthentications() throws Exception {
Settings settings = settings();
RealmConfig config = setupRealm("testAuthenticateCachesSuccesfulAuthentications", settings);
final RealmConfig.RealmIdentifier realmIdentifier = realmId("testAuthenticateCachesSuccesfulAuthentications");
Settings settings = settings(realmIdentifier);
RealmConfig config = setupRealm(realmIdentifier, settings);
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService, threadPool));
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
LdapRealm realm = new LdapRealm(config, sessionFactory, roleMapper, threadPool);
realm.initialize(Collections.singleton(realm), licenseState);
int count = randomIntBetween(2, 10);
@ -224,11 +229,14 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
}
public void testAuthenticateCachingCanBeDisabled() throws Exception {
Settings settings = settings(Settings.builder().put(CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING.getKey(), -1).build());
RealmConfig config = setupRealm("testAuthenticateCachingCanBeDisabled", settings);
final RealmConfig.RealmIdentifier realmIdentifier = realmId("testAuthenticateCachingCanBeDisabled");
final Settings settings = settings(realmIdentifier, Settings.builder()
.put(getFullSettingKey(realmIdentifier, CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING), -1)
.build());
RealmConfig config = setupRealm(realmIdentifier, settings);
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService, threadPool));
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
LdapRealm realm = new LdapRealm(config, sessionFactory, roleMapper, threadPool);
realm.initialize(Collections.singleton(realm), licenseState);
int count = randomIntBetween(2, 10);
@ -243,11 +251,12 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
}
public void testAuthenticateCachingClearsCacheOnRoleMapperRefresh() throws Exception {
Settings settings = settings();
RealmConfig config = setupRealm("testAuthenticateCachingClearsCacheOnRoleMapperRefresh", settings);
final RealmConfig.RealmIdentifier realmIdentifier = realmId("testAuthenticateCachingClearsCacheOnRoleMapperRefresh");
Settings settings = settings(realmIdentifier);
RealmConfig config = setupRealm(realmIdentifier, settings);
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService, threadPool));
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
LdapRealm realm = new LdapRealm(config, sessionFactory, roleMapper, threadPool);
realm.initialize(Collections.singleton(realm), licenseState);
int count = randomIntBetween(2, 10);
@ -281,22 +290,24 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
}
private void doUnauthenticatedLookup(boolean pooled) throws Exception {
final RealmConfig.RealmIdentifier realmIdentifier = realmId("testUnauthenticatedLookupWithConnectionPool");
final Settings.Builder builder = Settings.builder()
.put(ActiveDirectorySessionFactorySettings.POOL_ENABLED.getKey(), pooled)
.put(PoolingSessionFactorySettings.BIND_DN.getKey(), "CN=ironman@ad.test.elasticsearch.com");
.put(getFullSettingKey(realmIdentifier.getName(), ActiveDirectorySessionFactorySettings.POOL_ENABLED), pooled)
.put(getFullSettingKey(realmIdentifier, PoolingSessionFactorySettings.BIND_DN), "CN=ironman@ad.test.elasticsearch.com");
final boolean useLegacyBindPassword = randomBoolean();
if (useLegacyBindPassword) {
builder.put(PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD.getKey(), PASSWORD);
builder.put(getFullSettingKey(realmIdentifier, PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD), PASSWORD);
} else {
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(PoolingSessionFactorySettings.SECURE_BIND_PASSWORD.getKey(), PASSWORD);
secureSettings.setString(getFullSettingKey(realmIdentifier, PoolingSessionFactorySettings.SECURE_BIND_PASSWORD), PASSWORD);
builder.setSecureSettings(secureSettings);
}
Settings settings = settings(builder.build());
RealmConfig config = setupRealm("testUnauthenticatedLookupWithConnectionPool", settings);
Settings settings = settings(realmIdentifier, builder.build());
RealmConfig config = setupRealm(realmIdentifier, settings);
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool)) {
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
LdapRealm realm = new LdapRealm(config, sessionFactory, roleMapper, threadPool);
realm.initialize(Collections.singleton(realm), licenseState);
PlainActionFuture<User> future = new PlainActionFuture<>();
@ -308,13 +319,14 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
}
public void testRealmMapsGroupsToRoles() throws Exception {
Settings settings = settings(Settings.builder()
.put(ROLE_MAPPING_FILE_SETTING, getDataPath("role_mapping.yml"))
final RealmConfig.RealmIdentifier realmId = realmId("testRealmMapsGroupsToRoles");
Settings settings = settings(realmId, Settings.builder()
.put(getFullSettingKey(realmId, DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING), getDataPath("role_mapping.yml"))
.build());
RealmConfig config = setupRealm("testRealmMapsGroupsToRoles", settings);
RealmConfig config = setupRealm(realmId, settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
LdapRealm realm = new LdapRealm(config, sessionFactory, roleMapper, threadPool);
realm.initialize(Collections.singleton(realm), licenseState);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
@ -325,13 +337,14 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
}
public void testRealmMapsUsersToRoles() throws Exception {
Settings settings = settings(Settings.builder()
.put(ROLE_MAPPING_FILE_SETTING, getDataPath("role_mapping.yml"))
final RealmConfig.RealmIdentifier realmId = realmId("testRealmMapsGroupsToRoles");
Settings settings = settings(realmId, Settings.builder()
.put(getFullSettingKey(realmId, DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING), getDataPath("role_mapping.yml"))
.build());
RealmConfig config = setupRealm("testRealmMapsGroupsToRoles", settings);
RealmConfig config = setupRealm(realmId, settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
LdapRealm realm = new LdapRealm(config, sessionFactory, roleMapper, threadPool);
realm.initialize(Collections.singleton(realm), licenseState);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
@ -342,15 +355,16 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
}
public void testRealmUsageStats() throws Exception {
final RealmConfig.RealmIdentifier realmId = realmId("testRealmUsageStats");
String loadBalanceType = randomFrom("failover", "round_robin");
Settings settings = settings(Settings.builder()
.put(ROLE_MAPPING_FILE_SETTING, getDataPath("role_mapping.yml"))
.put("load_balance.type", loadBalanceType)
Settings settings = settings(realmId, Settings.builder()
.put(getFullSettingKey(realmId, DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING), getDataPath("role_mapping.yml"))
.put(getFullSettingKey(realmId, LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING), loadBalanceType)
.build());
RealmConfig config = setupRealm("testRealmUsageStats", settings);
RealmConfig config = setupRealm(realmId, settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
LdapRealm realm = new LdapRealm(config, sessionFactory, roleMapper, threadPool);
realm.initialize(Collections.singleton(realm), licenseState);
PlainActionFuture<Map<String, Object>> future = new PlainActionFuture<>();
@ -365,8 +379,9 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
}
public void testDefaultSearchFilters() throws Exception {
Settings settings = settings();
RealmConfig config = setupRealm("testDefaultSearchFilters", settings);
final RealmConfig.RealmIdentifier realmIdentifier = realmId("testDefaultSearchFilters");
Settings settings = settings(realmIdentifier);
RealmConfig config = setupRealm(realmIdentifier, settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
assertEquals("(&(objectClass=user)(|(sAMAccountName={0})(userPrincipalName={0}@ad.test.elasticsearch.com)))",
sessionFactory.defaultADAuthenticator.getUserSearchFilter());
@ -375,43 +390,61 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
}
public void testCustomSearchFilters() throws Exception {
Settings settings = settings(Settings.builder()
.put(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_FILTER_SETTING, "(objectClass=default)")
.put(ActiveDirectorySessionFactorySettings.AD_UPN_USER_SEARCH_FILTER_SETTING, "(objectClass=upn)")
.put(ActiveDirectorySessionFactorySettings.AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING, "(objectClass=down level)")
final RealmConfig.RealmIdentifier realmId = realmId("testDefaultSearchFilters");
Settings settings = settings(realmId, Settings.builder()
.put(getFullSettingKey(realmId.getName(), ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_FILTER_SETTING),
"(objectClass=default)")
.put(getFullSettingKey(realmId.getName(), ActiveDirectorySessionFactorySettings.AD_UPN_USER_SEARCH_FILTER_SETTING),
"(objectClass=upn)")
.put(getFullSettingKey(realmId.getName(), ActiveDirectorySessionFactorySettings.AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING),
"(objectClass=down level)")
.build());
RealmConfig config = setupRealm("testDefaultSearchFilters", settings);
RealmConfig config = setupRealm(realmId, settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
assertEquals("(objectClass=default)", sessionFactory.defaultADAuthenticator.getUserSearchFilter());
assertEquals("(objectClass=upn)", sessionFactory.upnADAuthenticator.getUserSearchFilter());
assertEquals("(objectClass=down level)", sessionFactory.downLevelADAuthenticator.getUserSearchFilter());
}
public RealmConfig.RealmIdentifier realmId(String realmName) {
return new RealmConfig.RealmIdentifier(LdapRealmSettings.AD_TYPE, realmName.toLowerCase(Locale.ROOT));
}
private Settings settings(RealmConfig.RealmIdentifier realmIdentifier) throws Exception {
return settings(realmIdentifier, Settings.EMPTY);
}
public void testBuildUrlFromDomainNameAndDefaultPort() throws Exception {
final RealmConfig.RealmIdentifier realmId = realmId("testBuildUrlFromDomainNameAndDefaultPort");
Settings settings = Settings.builder()
.put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, "ad.test.elasticsearch.com")
.put(getFullSettingKey(realmId.getName(), ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING),
"ad.test.elasticsearch.com")
.build();
RealmConfig config = setupRealm("testBuildUrlFromDomainNameAndDefaultPort", settings);
RealmConfig config = setupRealm(realmId, settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
assertSingleLdapServer(sessionFactory, "ad.test.elasticsearch.com", 389);
}
public void testBuildUrlFromDomainNameAndCustomPort() throws Exception {
final RealmConfig.RealmIdentifier realmId = realmId("testBuildUrlFromDomainNameAndCustomPort");
Settings settings = Settings.builder()
.put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, "ad.test.elasticsearch.com")
.put(ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING.getKey(), 10389)
.put(getFullSettingKey(realmId.getName(), ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING),
"ad.test.elasticsearch.com")
.put(getFullSettingKey(realmId.getName(), ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING), 10389)
.build();
RealmConfig config = setupRealm("testBuildUrlFromDomainNameAndCustomPort", settings);
RealmConfig config = setupRealm(realmId, settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
assertSingleLdapServer(sessionFactory, "ad.test.elasticsearch.com", 10389);
}
public void testUrlConfiguredInSettings() throws Exception {
final RealmConfig.RealmIdentifier realmId = realmId("testBuildUrlFromDomainNameAndCustomPort");
Settings settings = Settings.builder()
.put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, "ad.test.elasticsearch.com")
.put(SessionFactorySettings.URLS_SETTING, "ldap://ad01.testing.elastic.co:20389/")
.put(getFullSettingKey(realmId.getName(), ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING),
"ad.test.elasticsearch.com")
.put(getFullSettingKey(realmId, SessionFactorySettings.URLS_SETTING), "ldap://ad01.testing.elastic.co:20389/")
.build();
RealmConfig config = setupRealm("testBuildUrlFromDomainNameAndCustomPort", settings);
RealmConfig config = setupRealm(realmId, settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
assertSingleLdapServer(sessionFactory, "ad01.testing.elastic.co", 20389);
}
@ -426,19 +459,17 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
assertThat(sss.getPort(), equalTo(port));
}
private Settings settings() throws Exception {
return settings(Settings.EMPTY);
}
private Settings settings(Settings extraSettings) throws Exception {
private Settings settings(RealmConfig.RealmIdentifier realmIdentifier, Settings extraSettings) throws Exception {
Settings.Builder builder = Settings.builder()
.putList(URLS_SETTING, ldapUrls())
.put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, "ad.test.elasticsearch.com")
.put(DnRoleMapperSettings.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING.getKey(), true);
.putList(getFullSettingKey(realmIdentifier, URLS_SETTING), ldapUrls())
.put(getFullSettingKey(realmIdentifier.getName(), ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING),
"ad.test.elasticsearch.com")
.put(getFullSettingKey(realmIdentifier, DnRoleMapperSettings.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING), true);
if (randomBoolean()) {
builder.put("ssl.verification_mode", VerificationMode.CERTIFICATE);
builder.put(getFullSettingKey(realmIdentifier, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM),
VerificationMode.CERTIFICATE);
} else {
builder.put(HOSTNAME_VERIFICATION_SETTING, false);
builder.put(getFullSettingKey(realmIdentifier, HOSTNAME_VERIFICATION_SETTING), false);
}
return builder.put(extraSettings).build();
}

View File

@ -10,7 +10,11 @@ import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPInterface;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver;
import org.elasticsearch.test.ESTestCase;
import org.junit.After;
@ -24,6 +28,13 @@ public abstract class GroupsResolverTestCase extends ESTestCase {
LDAPConnection ldapConnection;
protected static RealmConfig config(RealmConfig.RealmIdentifier realmId, Settings settings) {
if (settings.hasValue("path.home") == false) {
settings = Settings.builder().put(settings).put("path.home", createTempDir()).build();
}
return new RealmConfig(realmId, settings, TestEnvironment.newEnvironment(settings), new ThreadContext(Settings.EMPTY));
}
protected abstract String ldapUrl();
protected abstract String bindDN();

View File

@ -9,7 +9,9 @@ import com.unboundid.ldap.sdk.LDAPURL;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.SecureSettings;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
@ -24,12 +26,16 @@ import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapSessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapUserSearchSessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.SearchGroupsResolverSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.core.security.authc.support.CachingUsernamePasswordRealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.DelegatedAuthorizationSettings;
import org.elasticsearch.xpack.core.security.authc.support.DnRoleMapperSettings;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.core.ssl.VerificationMode;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase;
@ -43,7 +49,9 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.URLS_SETTING;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.contains;
@ -69,8 +77,6 @@ public class LdapRealmTests extends LdapTestCase {
public static final String VALID_USERNAME = "Thomas Masterman Hardy";
public static final String PASSWORD = "pass";
private static final String USER_DN_TEMPLATES_SETTING_KEY = LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING.getKey();
private ThreadPool threadPool;
private ResourceWatcherService resourceWatcherService;
private Settings defaultGlobalSettings;
@ -97,10 +103,9 @@ public class LdapRealmTests extends LdapTestCase {
String groupSearchBase = "o=sevenSeas";
String userTemplate = VALID_USER_TEMPLATE;
Settings settings = buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE);
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings,
TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
RealmConfig config = getRealmConfig(REALM_IDENTIFIER, settings);
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
LdapRealm ldap = new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService),
LdapRealm ldap = new LdapRealm(config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService),
threadPool);
ldap.initialize(Collections.singleton(ldap), licenseState);
@ -117,18 +122,23 @@ public class LdapRealmTests extends LdapTestCase {
assertThat((List<?>) user.metadata().get("ldap_groups"), contains("cn=HMS Victory,ou=crews,ou=groups,o=sevenSeas"));
}
private RealmConfig getRealmConfig(RealmConfig.RealmIdentifier identifier, Settings settings) {
final Settings globalSettings = mergeSettings(settings, defaultGlobalSettings);
final Environment env = TestEnvironment.newEnvironment(globalSettings);
return new RealmConfig(identifier, globalSettings, env, new ThreadContext(globalSettings));
}
public void testAuthenticateOneLevelGroupSearch() throws Exception {
String groupSearchBase = "ou=crews,ou=groups,o=sevenSeas";
String userTemplate = VALID_USER_TEMPLATE;
Settings settings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
.build();
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings,
TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
RealmConfig config = getRealmConfig(REALM_IDENTIFIER, settings);
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
LdapRealm ldap =
new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
new LdapRealm(config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
ldap.initialize(Collections.singleton(ldap), licenseState);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
@ -150,13 +160,12 @@ public class LdapRealmTests extends LdapTestCase {
Settings settings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE))
.build();
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings,
TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
RealmConfig config = getRealmConfig(REALM_IDENTIFIER, settings);
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
ldapFactory = spy(ldapFactory);
LdapRealm ldap =
new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
new LdapRealm(config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
ldap.initialize(Collections.singleton(ldap), licenseState);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
@ -177,13 +186,12 @@ public class LdapRealmTests extends LdapTestCase {
Settings settings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE))
.build();
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings,
TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
RealmConfig config = getRealmConfig(REALM_IDENTIFIER, settings);
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = buildGroupAsRoleMapper(resourceWatcherService);
ldapFactory = spy(ldapFactory);
LdapRealm ldap = new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory, roleMapper, threadPool);
LdapRealm ldap = new LdapRealm(config, ldapFactory, roleMapper, threadPool);
ldap.initialize(Collections.singleton(ldap), licenseState);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
@ -211,15 +219,14 @@ public class LdapRealmTests extends LdapTestCase {
String userTemplate = VALID_USER_TEMPLATE;
Settings settings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE))
.put(CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING.getKey(), -1)
.put(getFullSettingKey(REALM_IDENTIFIER, CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING), -1)
.build();
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings,
TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
RealmConfig config = getRealmConfig(REALM_IDENTIFIER, settings);
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
ldapFactory = spy(ldapFactory);
LdapRealm ldap =
new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
new LdapRealm(config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
ldap.initialize(Collections.singleton(ldap), licenseState);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
@ -238,23 +245,23 @@ public class LdapRealmTests extends LdapTestCase {
String userTemplate = VALID_USER_TEMPLATE;
final Settings.Builder builder = Settings.builder()
.put(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE))
.putList(DelegatedAuthorizationSettings.AUTHZ_REALMS.getKey(), "mock_lookup");
.putList(getFullSettingKey(REALM_IDENTIFIER, DelegatedAuthorizationSettings.AUTHZ_REALMS), "mock_lookup");
if (randomBoolean()) {
// maybe disable caching
builder.put(CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING.getKey(), -1);
builder.put(getFullSettingKey(REALM_IDENTIFIER, CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING), -1);
}
final Settings realmSettings = builder.build();
final Environment env = TestEnvironment.newEnvironment(defaultGlobalSettings);
RealmConfig config = new RealmConfig("test-ldap-realm", realmSettings, defaultGlobalSettings, env, threadPool.getThreadContext());
RealmConfig config = new RealmConfig(REALM_IDENTIFIER, realmSettings, env, threadPool.getThreadContext());
final LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
final DnRoleMapper roleMapper = buildGroupAsRoleMapper(resourceWatcherService);
final LdapRealm ldap = new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory, roleMapper, threadPool);
final LdapRealm ldap = new LdapRealm(config, ldapFactory, roleMapper, threadPool);
final MockLookupRealm mockLookup = new MockLookupRealm(new RealmConfig("mock_lookup", Settings.EMPTY, defaultGlobalSettings, env,
threadPool.getThreadContext()));
final MockLookupRealm mockLookup = new MockLookupRealm(new RealmConfig(new RealmConfig.RealmIdentifier("mock", "mock_lookup"),
defaultGlobalSettings, env, threadPool.getThreadContext()));
ldap.initialize(Arrays.asList(ldap, mockLookup), licenseState);
mockLookup.initialize(Arrays.asList(ldap, mockLookup), licenseState);
@ -276,98 +283,81 @@ public class LdapRealmTests extends LdapTestCase {
}
public void testLdapRealmSelectsLdapSessionFactory() throws Exception {
final RealmConfig.RealmIdentifier identifier = new RealmConfig.RealmIdentifier(LdapRealmSettings.LDAP_TYPE, "test-ldap-realm");
String groupSearchBase = "o=sevenSeas";
String userTemplate = VALID_USER_TEMPLATE;
Settings settings = Settings.builder()
.putList(URLS_SETTING, ldapUrls())
.putList(USER_DN_TEMPLATES_SETTING_KEY, userTemplate)
.put("group_search.base_dn", groupSearchBase)
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
.putList(getFullSettingKey(identifier, URLS_SETTING), ldapUrls())
.putList(getFullSettingKey(identifier.getName(), LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING), userTemplate)
.put(getFullSettingKey(identifier, SearchGroupsResolverSettings.BASE_DN), groupSearchBase)
.put(getFullSettingKey(identifier, SearchGroupsResolverSettings.SCOPE), LdapSearchScope.SUB_TREE)
.put(getFullSettingKey(identifier, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), VerificationMode.CERTIFICATE)
.build();
final String realmName = "test-ldap-realm";
final Settings globalSettings = Settings.builder()
.put(settings)
.normalizePrefix(RealmSettings.PREFIX + realmName + ".")
.put(defaultGlobalSettings)
.build();
final Environment env = TestEnvironment.newEnvironment(globalSettings);
final RealmConfig config = new RealmConfig(realmName, settings, globalSettings, env, new ThreadContext(globalSettings));
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, new SSLService(globalSettings, env), threadPool,
LdapRealmSettings.LDAP_TYPE);
RealmConfig config = getRealmConfig(identifier, settings);
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, new SSLService(settings, config.env()), threadPool);
assertThat(sessionFactory, is(instanceOf(LdapSessionFactory.class)));
}
public void testLdapRealmSelectsLdapUserSearchSessionFactory() throws Exception {
final RealmConfig.RealmIdentifier identifier
= new RealmConfig.RealmIdentifier(LdapRealmSettings.LDAP_TYPE, "test-ldap-realm-user-search");
String groupSearchBase = "o=sevenSeas";
Settings settings = Settings.builder()
.putList(URLS_SETTING, ldapUrls())
.put("user_search.base_dn", "")
.put("bind_dn", "cn=Thomas Masterman Hardy,ou=people,o=sevenSeas")
.setSecureSettings(secureSettings("secure_bind_password", PASSWORD))
.put("group_search.base_dn", groupSearchBase)
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
.put(defaultGlobalSettings)
.putList(getFullSettingKey(identifier, URLS_SETTING), ldapUrls())
.put(getFullSettingKey(identifier.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), "")
.put(getFullSettingKey(identifier, PoolingSessionFactorySettings.BIND_DN),
"cn=Thomas Masterman Hardy,ou=people,o=sevenSeas")
.setSecureSettings(secureSettings(PoolingSessionFactorySettings.SECURE_BIND_PASSWORD, identifier, PASSWORD))
.put(getFullSettingKey(identifier, SearchGroupsResolverSettings.BASE_DN), groupSearchBase)
.put(getFullSettingKey(identifier, SearchGroupsResolverSettings.SCOPE), LdapSearchScope.SUB_TREE)
.put(getFullSettingKey(identifier, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), VerificationMode.CERTIFICATE)
.build();
final String realmName = "test-ldap-realm-user-search";
final Settings globalSettings = Settings.builder()
.put(settings)
.normalizePrefix(RealmSettings.PREFIX + realmName + ".")
.put(defaultGlobalSettings)
.build();
final Environment env = TestEnvironment.newEnvironment(globalSettings);
final RealmConfig config = new RealmConfig(realmName, settings, globalSettings, env, new ThreadContext(globalSettings));
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, new SSLService(globalSettings, env), threadPool,
LdapRealmSettings.LDAP_TYPE);
final RealmConfig config = getRealmConfig(identifier, settings);
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, new SSLService(config.globalSettings(), config.env()), threadPool);
try {
assertThat(sessionFactory, is(instanceOf(LdapUserSearchSessionFactory.class)));
} finally {
((LdapUserSearchSessionFactory)sessionFactory).close();
((LdapUserSearchSessionFactory) sessionFactory).close();
}
}
private MockSecureSettings secureSettings(String key, String value) {
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(key, value);
return secureSettings;
}
public void testLdapRealmThrowsExceptionForUserTemplateAndSearchSettings() throws Exception {
final RealmConfig.RealmIdentifier identifier
= new RealmConfig.RealmIdentifier(LdapRealmSettings.LDAP_TYPE, "test-ldap-realm-user-search");
Settings settings = Settings.builder()
.putList(URLS_SETTING, ldapUrls())
.putList(USER_DN_TEMPLATES_SETTING_KEY, "cn=foo")
.put("user_search.base_dn", "cn=bar")
.put("group_search.base_dn", "")
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
.putList(getFullSettingKey(identifier, URLS_SETTING), ldapUrls())
.putList(getFullSettingKey(identifier.getName(), LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING), "cn=foo")
.put(getFullSettingKey(identifier.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), "cn=bar")
.put(getFullSettingKey(identifier, SearchGroupsResolverSettings.BASE_DN), "")
.put(getFullSettingKey(identifier, SearchGroupsResolverSettings.SCOPE), LdapSearchScope.SUB_TREE)
.put(getFullSettingKey(identifier, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), VerificationMode.CERTIFICATE)
.build();
RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, defaultGlobalSettings,
TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
RealmConfig config = getRealmConfig(identifier, settings);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> LdapRealm.sessionFactory(config, null, threadPool, LdapRealmSettings.LDAP_TYPE));
() -> LdapRealm.sessionFactory(config, null, threadPool));
assertThat(e.getMessage(),
containsString("settings were found for both" +
" user search [xpack.security.authc.realms.test-ldap-realm-user-search.user_search.] and" +
" user template [xpack.security.authc.realms.test-ldap-realm-user-search.user_dn_templates]"));
" user search [xpack.security.authc.realms.ldap.test-ldap-realm-user-search.user_search.base_dn] and" +
" user template [xpack.security.authc.realms.ldap.test-ldap-realm-user-search.user_dn_templates]"));
}
public void testLdapRealmThrowsExceptionWhenNeitherUserTemplateNorSearchSettingsProvided() throws Exception {
final RealmConfig.RealmIdentifier identifier
= new RealmConfig.RealmIdentifier(LdapRealmSettings.LDAP_TYPE, "test-ldap-realm-user-search");
Settings settings = Settings.builder()
.putList(URLS_SETTING, ldapUrls())
.put("group_search.base_dn", "")
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
.putList(getFullSettingKey(identifier, URLS_SETTING), ldapUrls())
.put(getFullSettingKey(identifier, SearchGroupsResolverSettings.BASE_DN), "")
.put(getFullSettingKey(identifier, SearchGroupsResolverSettings.SCOPE), LdapSearchScope.SUB_TREE)
.put(getFullSettingKey(identifier, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), VerificationMode.CERTIFICATE)
.build();
RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, defaultGlobalSettings,
TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
RealmConfig config = getRealmConfig(identifier, settings);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> LdapRealm.sessionFactory(config, null, threadPool, LdapRealmSettings.LDAP_TYPE));
() -> LdapRealm.sessionFactory(config, null, threadPool));
assertThat(e.getMessage(),
containsString("settings were not found for either" +
" user search [xpack.security.authc.realms.test-ldap-realm-user-search.user_search.] or" +
" user template [xpack.security.authc.realms.test-ldap-realm-user-search.user_dn_templates]"));
" user search [xpack.security.authc.realms.ldap.test-ldap-realm-user-search.user_search.base_dn] or" +
" user template [xpack.security.authc.realms.ldap.test-ldap-realm-user-search.user_dn_templates]"));
}
public void testLdapRealmMapsUserDNToRole() throws Exception {
@ -375,14 +365,13 @@ public class LdapRealmTests extends LdapTestCase {
String userTemplate = VALID_USER_TEMPLATE;
Settings settings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE))
.put(DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING.getKey(),
.put(getFullSettingKey(REALM_IDENTIFIER, DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING),
getDataPath("/org/elasticsearch/xpack/security/authc/support/role_mapping.yml"))
.build();
RealmConfig config = new RealmConfig("test-ldap-realm-userdn", settings, defaultGlobalSettings,
TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
RealmConfig config = getRealmConfig(REALM_IDENTIFIER, settings);
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
LdapRealm ldap = new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory,
LdapRealm ldap = new LdapRealm(config, ldapFactory,
new DnRoleMapper(config, resourceWatcherService), threadPool);
ldap.initialize(Collections.singleton(ldap), licenseState);
@ -407,10 +396,9 @@ public class LdapRealmTests extends LdapTestCase {
String groupSearchBase = "o=sevenSeas";
String userTemplate = VALID_USER_TEMPLATE;
Settings settings = buildLdapSettings(new String[] { url.toString() }, userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE);
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings,
TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
RealmConfig config = getRealmConfig(REALM_IDENTIFIER, settings);
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
LdapRealm ldap = new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService),
LdapRealm ldap = new LdapRealm(config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService),
threadPool);
ldap.initialize(Collections.singleton(ldap), licenseState);
@ -425,47 +413,47 @@ public class LdapRealmTests extends LdapTestCase {
}
public void testUsageStats() throws Exception {
final RealmConfig.RealmIdentifier identifier = new RealmConfig.RealmIdentifier(LdapRealmSettings.LDAP_TYPE, "ldap-realm");
String groupSearchBase = "o=sevenSeas";
Settings.Builder settings = Settings.builder()
.putList(URLS_SETTING, ldapUrls())
.put("bind_dn", "cn=Thomas Masterman Hardy,ou=people,o=sevenSeas")
.put("bind_password", PASSWORD)
.put("group_search.base_dn", groupSearchBase)
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put(LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING.getKey(), "--")
.put("ssl.verification_mode", VerificationMode.CERTIFICATE);
.putList(getFullSettingKey(identifier, URLS_SETTING), ldapUrls())
.put(getFullSettingKey(identifier, PoolingSessionFactorySettings.BIND_DN),
"cn=Thomas Masterman Hardy,ou=people,o=sevenSeas")
.put(getFullSettingKey(identifier, PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD), PASSWORD)
.put(getFullSettingKey(identifier, SearchGroupsResolverSettings.BASE_DN), groupSearchBase)
.put(getFullSettingKey(identifier, SearchGroupsResolverSettings.SCOPE), LdapSearchScope.SUB_TREE)
.put(getFullSettingKey(identifier.getName(), LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING), "--")
.put(getFullSettingKey(identifier, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), VerificationMode.CERTIFICATE);
int order = randomIntBetween(0, 10);
settings.put("order", order);
settings.put(getFullSettingKey(identifier, RealmSettings.ORDER_SETTING), order);
boolean userSearch = randomBoolean();
if (userSearch) {
settings.put("user_search.base_dn", "");
settings.put(getFullSettingKey(identifier.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), "");
}
final Settings realmSettings = settings.build();
final String realmName = "ldap-realm";
final Settings globalSettings = Settings.builder()
.put(realmSettings)
.normalizePrefix(RealmSettings.PREFIX + realmName + ".")
.put(defaultGlobalSettings)
.build();
final Environment env = TestEnvironment.newEnvironment(globalSettings);
final RealmConfig config = new RealmConfig(realmName, realmSettings, globalSettings, env, new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(identifier, settings.build());
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, new SSLService(globalSettings, env), threadPool);
LdapRealm realm = new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory,
new DnRoleMapper(config, resourceWatcherService), threadPool);
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, new SSLService(config.globalSettings(), config.env()), threadPool);
LdapRealm realm = new LdapRealm(config, ldapFactory, new DnRoleMapper(config, resourceWatcherService), threadPool);
realm.initialize(Collections.singleton(realm), licenseState);
PlainActionFuture<Map<String, Object>> future = new PlainActionFuture<>();
realm.usageStats(future);
Map<String, Object> stats = future.get();
assertThat(stats, is(notNullValue()));
assertThat(stats, hasEntry("name", realmName));
assertThat(stats, hasEntry("name", identifier.getName()));
assertThat(stats, hasEntry("order", realm.order()));
assertThat(stats, hasEntry("size", 0));
assertThat(stats, hasEntry("ssl", false));
assertThat(stats, hasEntry("user_search", userSearch));
}
private SecureSettings secureSettings(Function<String, Setting.AffixSetting<SecureString>> settingFactory,
RealmConfig.RealmIdentifier identifier, String value) {
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(getFullSettingKey(identifier, settingFactory), value);
return secureSettings;
}
}

View File

@ -9,7 +9,6 @@ import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPURL;
import com.unboundid.ldap.sdk.SimpleBindRequest;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
@ -18,6 +17,7 @@ import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
import org.elasticsearch.xpack.core.ssl.SSLService;
@ -59,11 +59,11 @@ public class LdapSessionFactoryTests extends LdapTestCase {
Settings settings = Settings.builder()
.put(buildLdapSettings(ldapUrl, userTemplates, groupSearchBase, LdapSearchScope.SUB_TREE))
.put(SessionFactorySettings.TIMEOUT_TCP_READ_SETTING, "1ms") //1 millisecond
.put(RealmSettings.getFullSettingKey(REALM_IDENTIFIER, SessionFactorySettings.TIMEOUT_TCP_READ_SETTING), "1ms")
.put("path.home", createTempDir())
.build();
RealmConfig config = new RealmConfig("ldap_realm", settings, globalSettings,
RealmConfig config = new RealmConfig(REALM_IDENTIFIER, mergeSettings(settings, globalSettings),
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
String user = "Horatio Hornblower";
@ -83,14 +83,14 @@ public class LdapSessionFactoryTests extends LdapTestCase {
public void testBindWithTemplates() throws Exception {
String groupSearchBase = "o=sevenSeas";
String[] userTemplates = new String[] {
String[] userTemplates = new String[]{
"cn={0},ou=something,ou=obviously,ou=incorrect,o=sevenSeas",
"wrongname={0},ou=people,o=sevenSeas",
"cn={0},ou=people,o=sevenSeas", //this last one should work
};
RealmConfig config = new RealmConfig("ldap_realm",
buildLdapSettings(ldapUrls(), userTemplates, groupSearchBase, LdapSearchScope.SUB_TREE),
globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig(REALM_IDENTIFIER,
mergeSettings(buildLdapSettings(ldapUrls(), userTemplates, groupSearchBase, LdapSearchScope.SUB_TREE), globalSettings),
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
@ -107,14 +107,14 @@ public class LdapSessionFactoryTests extends LdapTestCase {
public void testBindWithBogusTemplates() throws Exception {
String groupSearchBase = "o=sevenSeas";
String[] userTemplates = new String[] {
String[] userTemplates = new String[]{
"cn={0},ou=something,ou=obviously,ou=incorrect,o=sevenSeas",
"wrongname={0},ou=people,o=sevenSeas",
"asdf={0},ou=people,o=sevenSeas", //none of these should work
};
RealmConfig config = new RealmConfig("ldap_realm",
buildLdapSettings(ldapUrls(), userTemplates, groupSearchBase, LdapSearchScope.SUB_TREE),
globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig(REALM_IDENTIFIER,
mergeSettings(buildLdapSettings(ldapUrls(), userTemplates, groupSearchBase, LdapSearchScope.SUB_TREE), globalSettings),
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService, threadPool);
@ -131,9 +131,9 @@ public class LdapSessionFactoryTests extends LdapTestCase {
public void testGroupLookupSubtree() throws Exception {
String groupSearchBase = "o=sevenSeas";
String userTemplate = "cn={0},ou=people,o=sevenSeas";
RealmConfig config = new RealmConfig("ldap_realm",
buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE),
globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig(REALM_IDENTIFIER,
mergeSettings(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE), globalSettings),
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService, threadPool);
@ -151,9 +151,9 @@ public class LdapSessionFactoryTests extends LdapTestCase {
public void testGroupLookupOneLevel() throws Exception {
String groupSearchBase = "ou=crews,ou=groups,o=sevenSeas";
String userTemplate = "cn={0},ou=people,o=sevenSeas";
RealmConfig config = new RealmConfig("ldap_realm",
buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL),
globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig(REALM_IDENTIFIER,
mergeSettings(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL), globalSettings),
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService, threadPool);
@ -170,9 +170,9 @@ public class LdapSessionFactoryTests extends LdapTestCase {
public void testGroupLookupBase() throws Exception {
String groupSearchBase = "cn=HMS Lydia,ou=crews,ou=groups,o=sevenSeas";
String userTemplate = "cn={0},ou=people,o=sevenSeas";
RealmConfig config = new RealmConfig("ldap_realm",
buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.BASE),
globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig(REALM_IDENTIFIER,
mergeSettings(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.BASE), globalSettings),
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService, threadPool);

View File

@ -36,18 +36,18 @@ public class LdapTestUtils {
if (useGlobalSSL) {
builder.put("xpack.ssl.truststore.path", truststore);
// fake realm to load config with certificate verification mode
builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", truststore);
builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
builder.put("xpack.security.authc.realms.ldap.bar.ssl.truststore.path", truststore);
builder.put("xpack.security.authc.realms.ldap.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
secureSettings.setString("xpack.ssl.truststore.secure_password", "changeit");
secureSettings.setString("xpack.security.authc.realms.bar.ssl.truststore.secure_password", "changeit");
secureSettings.setString("xpack.security.authc.realms.ldap.bar.ssl.truststore.secure_password", "changeit");
} else {
// fake realms so ssl will get loaded
builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", truststore);
builder.put("xpack.security.authc.realms.foo.ssl.verification_mode", VerificationMode.FULL);
builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", truststore);
builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
secureSettings.setString("xpack.security.authc.realms.foo.ssl.truststore.secure_password", "changeit");
secureSettings.setString("xpack.security.authc.realms.bar.ssl.truststore.secure_password", "changeit");
builder.put("xpack.security.authc.realms.ldap.foo.ssl.truststore.path", truststore);
builder.put("xpack.security.authc.realms.ldap.foo.ssl.verification_mode", VerificationMode.FULL);
builder.put("xpack.security.authc.realms.ldap.bar.ssl.truststore.path", truststore);
builder.put("xpack.security.authc.realms.ldap.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
secureSettings.setString("xpack.security.authc.realms.ldap.foo.ssl.truststore.secure_password", "changeit");
secureSettings.setString("xpack.security.authc.realms.ldap.bar.ssl.truststore.secure_password", "changeit");
}
Settings settings = builder.build();
Environment env = TestEnvironment.newEnvironment(settings);
@ -64,7 +64,7 @@ public class LdapTestUtils {
if (useGlobalSSL) {
sslConfiguration = sslService.getSSLConfiguration("xpack.ssl");
} else {
sslConfiguration = sslService.getSSLConfiguration("xpack.security.authc.realms.foo.ssl");
sslConfiguration = sslService.getSSLConfiguration("xpack.security.authc.realms.ldap.foo.ssl");
}
return LdapUtils.privilegedConnect(() -> new LDAPConnection(sslService.sslSocketFactory(sslConfiguration), options,
ldapurl.getHost(), ldapurl.getPort(), bindDN, bindPassword));

View File

@ -41,6 +41,7 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isEmptyString;
@ -85,18 +86,18 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
final boolean useAttribute = randomBoolean();
Settings.Builder builder = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, "", LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", "")
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put("user_search.pool.enabled", randomBoolean());
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), "")
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN),
"cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.POOL_ENABLED), randomBoolean());
final boolean useLegacyBindPassword = configureBindPassword(builder);
if (useAttribute) {
builder.put("user_search.attribute", "cn");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE), "cn");
} else {
builder.put("user_search.filter", "(cn={0})");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_FILTER), "(cn={0})");
}
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(builder);
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
try {
@ -105,7 +106,13 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
sessionFactory.close();
}
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword);
}
private RealmConfig getRealmConfig(Settings.Builder builder) {
return new RealmConfig(REALM_IDENTIFIER,
mergeSettings(builder.build(), globalSettings),
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
}
public void testUserSearchSubTree() throws Exception {
@ -115,17 +122,17 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
final boolean useAttribute = randomBoolean();
Settings.Builder builder = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put("user_search.pool.enabled", randomBoolean());
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN),
"cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.POOL_ENABLED), randomBoolean());
final boolean useLegacyBindPassword = configureBindPassword(builder);
if (useAttribute) {
builder.put("user_search.attribute", "cn");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE), "cn");
} else {
builder.put("user_search.filter", "(cn={0})");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_FILTER), "(cn={0})");
}
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(builder);
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
@ -150,7 +157,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
sessionFactory.close();
}
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword);
}
public void testUserSearchBaseScopeFailsWithWrongBaseDN() throws Exception {
@ -160,18 +167,18 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
final boolean useAttribute = randomBoolean();
Settings.Builder builder = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put("user_search.scope", LdapSearchScope.BASE)
.put("user_search.pool.enabled", randomBoolean());
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN),
"cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_SCOPE), LdapSearchScope.BASE)
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.POOL_ENABLED), randomBoolean());
final boolean useLegacyBindPassword = configureBindPassword(builder);
if (useAttribute) {
builder.put("user_search.attribute", "cn");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE), "cn");
} else {
builder.put("user_search.filter", "(cn={0})");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_FILTER), "(cn={0})");
}
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(builder);
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
@ -185,7 +192,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
sessionFactory.close();
}
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword);
}
public void testUserSearchBaseScopePassesWithCorrectBaseDN() throws Exception {
@ -194,19 +201,19 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
Settings.Builder builder = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put("user_search.scope", LdapSearchScope.BASE)
.put("user_search.pool.enabled", randomBoolean());
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN),
"cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_SCOPE), LdapSearchScope.BASE)
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.POOL_ENABLED), randomBoolean());
final boolean useLegacyBindPassword = configureBindPassword(builder);
final boolean useAttribute = randomBoolean();
if (useAttribute) {
builder.put("user_search.attribute", "cn");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE), "cn");
} else {
builder.put("user_search.filter", "(cn={0})");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_FILTER), "(cn={0})");
}
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(builder);
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
@ -231,7 +238,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
sessionFactory.close();
}
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword);
}
public void testUserSearchOneLevelScopeFailsWithWrongBaseDN() throws Exception {
@ -240,19 +247,20 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
Settings.Builder builder = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put("user_search.scope", LdapSearchScope.ONE_LEVEL)
.put("user_search.pool.enabled", randomBoolean());
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN),
"cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_SCOPE),
LdapSearchScope.ONE_LEVEL)
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.POOL_ENABLED), randomBoolean());
final boolean useLegacyBindPassword = configureBindPassword(builder);
final boolean useAttribute = randomBoolean();
if (useAttribute) {
builder.put("user_search.attribute", "cn");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE), "cn");
} else {
builder.put("user_search.filter", "(cn={0})");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_FILTER), "(cn={0})");
}
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(builder);
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
@ -266,7 +274,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
sessionFactory.close();
}
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword);
}
public void testUserSearchOneLevelScopePassesWithCorrectBaseDN() throws Exception {
@ -275,19 +283,20 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
Settings.Builder builder = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put("user_search.scope", LdapSearchScope.ONE_LEVEL)
.put("user_search.pool.enabled", randomBoolean());
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN),
"cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_SCOPE),
LdapSearchScope.ONE_LEVEL)
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.POOL_ENABLED), randomBoolean());
final boolean useLegacyBindPassword = configureBindPassword(builder);
final boolean useAttribute = randomBoolean();
if (useAttribute) {
builder.put("user_search.attribute", "cn");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE), "cn");
} else {
builder.put("user_search.filter", "(cn={0})");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_FILTER), "(cn={0})");
}
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(builder);
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
@ -312,7 +321,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
sessionFactory.close();
}
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword);
}
public void testUserSearchWithBadAttributeFails() throws Exception {
@ -321,18 +330,18 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
Settings.Builder builder = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put("user_search.pool.enabled", randomBoolean());
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN),
"cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.POOL_ENABLED), randomBoolean());
final boolean useLegacyBindPassword = configureBindPassword(builder);
final boolean useAttribute = randomBoolean();
if (useAttribute) {
builder.put("user_search.attribute", "uid1");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE), "uid1");
} else {
builder.put("user_search.filter", "(uid1={0})");
builder.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_FILTER), "(uid1={0})");
}
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(builder);
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
@ -346,7 +355,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
sessionFactory.close();
}
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword);
}
public void testUserSearchWithoutAttributePasses() throws Exception {
@ -355,12 +364,12 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
final Settings.Builder realmSettings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put("user_search.pool.enabled", randomBoolean());
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN),
"cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.POOL_ENABLED), randomBoolean());
final boolean useLegacyBindPassword = configureBindPassword(realmSettings);
RealmConfig config = new RealmConfig("ldap_realm", realmSettings.build(), globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(realmSettings);
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
@ -385,7 +394,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
sessionFactory.close();
}
assertDeprecationWarnings(false, useLegacyBindPassword);
assertDeprecationWarnings(config.identifier(), false, useLegacyBindPassword);
}
public void testConnectionPoolDefaultSettings() throws Exception {
@ -393,11 +402,11 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
String userSearchBase = "o=sevenSeas";
final Settings.Builder realmSettings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas");
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN),
"cn=Horatio Hornblower,ou=people,o=sevenSeas");
configureBindPassword(realmSettings);
RealmConfig config = new RealmConfig("ldap_realm", realmSettings.build(), globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(realmSettings);
LDAPConnectionPool connectionPool = LdapUserSearchSessionFactory.createConnectionPool(config, new SingleServerSet("localhost",
randomFrom(ldapServers).getListenPort()), TimeValue.timeValueSeconds(5), NoOpLogger.INSTANCE,
@ -422,14 +431,14 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
String userSearchBase = "o=sevenSeas";
final Settings.Builder realmSettings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put("user_search.pool.initial_size", 10)
.put("user_search.pool.size", 12)
.put("user_search.pool.health_check.enabled", false);
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN),
"cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.POOL_INITIAL_SIZE), 10)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.POOL_SIZE), 12)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.HEALTH_CHECK_ENABLED), false);
configureBindPassword(realmSettings);
RealmConfig config = new RealmConfig("ldap_realm", realmSettings.build(), globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(realmSettings);
LDAPConnectionPool connectionPool = LdapUserSearchSessionFactory.createConnectionPool(config, new SingleServerSet("localhost",
randomFrom(ldapServers).getListenPort()), TimeValue.timeValueSeconds(5), NoOpLogger.INSTANCE,
@ -448,11 +457,10 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
public void testThatEmptyBindDNWithHealthCheckEnabledDoesNotThrow() throws Exception {
String groupSearchBase = "o=sevenSeas";
String userSearchBase = "o=sevenSeas";
RealmConfig config = new RealmConfig("ldap_realm", Settings.builder()
RealmConfig config = getRealmConfig(Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("bind_password", "pass")
.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD), "pass"));
LdapUserSearchSessionFactory searchSessionFactory = null;
try {
@ -463,18 +471,17 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
}
}
assertDeprecationWarnings(false, true);
assertDeprecationWarnings(config.identifier(), false, true);
}
public void testThatEmptyBindDNAndDisabledPoolingDoesNotThrow() throws Exception {
String groupSearchBase = "o=sevenSeas";
String userSearchBase = "o=sevenSeas";
RealmConfig config = new RealmConfig("ldap_realm", Settings.builder()
RealmConfig config = getRealmConfig(Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("user_search.pool.enabled", false)
.put("bind_password", "pass")
.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.POOL_ENABLED), false)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD), "pass"));
LdapUserSearchSessionFactory searchSessionFactory = null;
try {
@ -488,7 +495,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
}
}
assertDeprecationWarnings(false, true);
assertDeprecationWarnings(config.identifier(), false, true);
}
public void testEmptyBindDNReturnsAnonymousBindRequest() throws LDAPException {
@ -496,15 +503,16 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
String userSearchBase = "o=sevenSeas";
final Settings.Builder realmSettings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase);
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase);
final boolean useLegacyBindPassword = configureBindPassword(realmSettings);
RealmConfig config = new RealmConfig("ldap_realm", realmSettings.build(), globalSettings,
RealmConfig config = new RealmConfig(REALM_IDENTIFIER,
mergeSettings(realmSettings.build(), globalSettings),
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
try (LdapUserSearchSessionFactory searchSessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool)) {
assertThat(searchSessionFactory.bindCredentials, notNullValue());
assertThat(searchSessionFactory.bindCredentials.getBindDN(), isEmptyString());
}
assertDeprecationWarnings(false, useLegacyBindPassword);
assertDeprecationWarnings(config.identifier(), false, useLegacyBindPassword);
}
public void testThatBindRequestReturnsSimpleBindRequest() throws LDAPException {
@ -512,16 +520,17 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
String userSearchBase = "o=sevenSeas";
final Settings.Builder realmSettings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("bind_dn", "cn=ironman")
.put("user_search.base_dn", userSearchBase);
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN), "cn=ironman")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase);
final boolean useLegacyBindPassword = configureBindPassword(realmSettings);
RealmConfig config = new RealmConfig("ldap_realm", realmSettings.build(), globalSettings,
RealmConfig config = new RealmConfig(REALM_IDENTIFIER,
mergeSettings(realmSettings.build(), globalSettings),
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
try (LdapUserSearchSessionFactory searchSessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool)) {
assertThat(searchSessionFactory.bindCredentials, notNullValue());
assertThat(searchSessionFactory.bindCredentials.getBindDN(), is("cn=ironman"));
}
assertDeprecationWarnings(false, useLegacyBindPassword);
assertDeprecationWarnings(config.identifier(), false, useLegacyBindPassword);
}
public void testThatConnectErrorIsNotThrownOnConstruction() throws Exception {
@ -536,17 +545,16 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
final Settings.Builder ldapSettingsBuilder = Settings.builder()
.put(LdapTestCase.buildLdapSettings(new String[]{ldapUrl}, Strings.EMPTY_ARRAY,
groupSearchBase, LdapSearchScope.SUB_TREE))
.put("user_search.base_dn", userSearchBase)
.put("bind_dn", "ironman@ad.test.elasticsearch.com")
.put("user_search.attribute", "cn")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN), "ironman@ad.test.elasticsearch.com")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE), "cn")
.put("timeout.tcp_connect", "500ms")
.put("type", "ldap")
.put("user_search.pool.health_check.enabled", false)
.put("user_search.pool.enabled", randomBoolean());
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapUserSearchSessionFactorySettings.POOL_ENABLED), randomBoolean());
final boolean useLegacyBindPassword = configureBindPassword(ldapSettingsBuilder);
RealmConfig config = new RealmConfig("ldap_realm", ldapSettingsBuilder.build(), globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = getRealmConfig(ldapSettingsBuilder);
LdapUserSearchSessionFactory searchSessionFactory = null;
try {
searchSessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
@ -556,16 +564,20 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
}
}
assertDeprecationWarnings(true, useLegacyBindPassword);
assertDeprecationWarnings(config.identifier(), true, useLegacyBindPassword);
}
private void assertDeprecationWarnings(boolean useAttribute, boolean legacyBindPassword) {
private void assertDeprecationWarnings(RealmConfig.RealmIdentifier realmIdentifier, boolean useAttribute, boolean legacyBindPassword) {
List<Setting<?>> deprecatedSettings = new ArrayList<>();
if (useAttribute) {
deprecatedSettings.add(LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE);
deprecatedSettings.add(LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE
.getConcreteSettingForNamespace(realmIdentifier.getName())
);
}
if (legacyBindPassword) {
deprecatedSettings.add(PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD);
deprecatedSettings.add(PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD
.apply(realmIdentifier.getType())
.getConcreteSettingForNamespace(realmIdentifier.getName()));
}
if (deprecatedSettings.size() > 0) {
assertSettingDeprecationsAndWarnings(deprecatedSettings.toArray(new Setting<?>[deprecatedSettings.size()]));
@ -575,9 +587,10 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
private boolean configureBindPassword(Settings.Builder builder) {
final boolean useLegacyBindPassword = randomBoolean();
if (useLegacyBindPassword) {
builder.put("bind_password", "pass");
builder.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD), "pass");
} else {
builder.setSecureSettings(newSecureSettings("secure_bind_password", "pass"));
final String secureKey = getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.SECURE_BIND_PASSWORD);
builder.setSecureSettings(newSecureSettings(secureKey, "pass"));
}
return useLegacyBindPassword;
}

View File

@ -5,9 +5,6 @@
*/
package org.elasticsearch.xpack.security.authc.ldap;
import java.util.List;
import java.util.concurrent.ExecutionException;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
import com.unboundid.ldap.sdk.LDAPConnectionPool;
@ -19,11 +16,20 @@ import com.unboundid.ldap.sdk.SingleServerSet;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.SearchGroupsResolverSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils;
import org.junit.After;
import java.util.List;
import java.util.concurrent.ExecutionException;
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
@ -32,6 +38,7 @@ import static org.hamcrest.Matchers.iterableWithSize;
public class SearchGroupsResolverInMemoryTests extends LdapTestCase {
private static final String WILLIAM_BUSH = "cn=William Bush,ou=people,o=sevenSeas";
public static final RealmConfig.RealmIdentifier REALM_IDENTIFIER = new RealmConfig.RealmIdentifier("ldap", "ldap1");
private LDAPConnection connection;
@After
@ -54,10 +61,10 @@ public class SearchGroupsResolverInMemoryTests extends LdapTestCase {
connect(options);
final Settings settings = Settings.builder()
.put("group_search.base_dn", "ou=groups,o=sevenSeas")
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put(getFullSettingKey(REALM_IDENTIFIER, SearchGroupsResolverSettings.BASE_DN), "ou=groups,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER, SearchGroupsResolverSettings.SCOPE), LdapSearchScope.SUB_TREE)
.build();
final SearchGroupsResolver resolver = new SearchGroupsResolver(settings);
final SearchGroupsResolver resolver = new SearchGroupsResolver(getConfig(settings));
final PlainActionFuture<List<String>> future = new PlainActionFuture<>();
resolver.resolve(connection, WILLIAM_BUSH, TimeValue.timeValueSeconds(30), logger, null, future);
@ -74,8 +81,8 @@ public class SearchGroupsResolverInMemoryTests extends LdapTestCase {
connect(new LDAPConnectionOptions());
Settings settings = Settings.builder()
.put("group_search.base_dn", "ou=groups,o=sevenSeas")
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put(getFullSettingKey(REALM_IDENTIFIER, SearchGroupsResolverSettings.BASE_DN), "ou=groups,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER, SearchGroupsResolverSettings.SCOPE), LdapSearchScope.SUB_TREE)
.build();
final List<String> groups = resolveGroups(settings, WILLIAM_BUSH);
@ -90,8 +97,8 @@ public class SearchGroupsResolverInMemoryTests extends LdapTestCase {
connect(new LDAPConnectionOptions());
Settings settings = Settings.builder()
.put("group_search.base_dn", "ou=groups,o=sevenSeas")
.put("group_search.user_attribute", "dn")
.put(getFullSettingKey(REALM_IDENTIFIER, SearchGroupsResolverSettings.BASE_DN), "ou=groups,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "dn")
.build();
final List<String> groups = resolveGroups(settings, WILLIAM_BUSH);
@ -106,8 +113,8 @@ public class SearchGroupsResolverInMemoryTests extends LdapTestCase {
connect(new LDAPConnectionOptions());
Settings settings = Settings.builder()
.put("group_search.base_dn", "ou=groups,o=sevenSeas")
.put("group_search.user_attribute", "no-such-attribute")
.put(getFullSettingKey(REALM_IDENTIFIER, SearchGroupsResolverSettings.BASE_DN), "ou=groups,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "no-such-attribute")
.build();
final List<String> groups = resolveGroups(settings, WILLIAM_BUSH);
@ -122,13 +129,13 @@ public class SearchGroupsResolverInMemoryTests extends LdapTestCase {
new SimpleBindRequest("cn=Horatio Hornblower,ou=people,o=sevenSeas", "pass"), 0, 20))) {
final Settings settings = Settings.builder()
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put("bind_password", "pass")
.put("user_search.base_dn", "ou=groups,o=sevenSeas")
.put("group_search.base_dn", "ou=groups,o=sevenSeas")
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.BIND_DN),
"cn=Horatio Hornblower,ou=people,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER, PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD), "pass")
.put(getFullSettingKey(REALM_IDENTIFIER, SearchGroupsResolverSettings.BASE_DN), "ou=groups,o=sevenSeas")
.put(getFullSettingKey(REALM_IDENTIFIER, SearchGroupsResolverSettings.SCOPE), LdapSearchScope.SUB_TREE)
.build();
final SearchGroupsResolver resolver = new SearchGroupsResolver(settings);
final SearchGroupsResolver resolver = new SearchGroupsResolver(getConfig(settings));
final PlainActionFuture<List<String>> future = new PlainActionFuture<>();
resolver.resolve(pool,
"cn=Moultrie Crystal,ou=people,o=sevenSeas",
@ -150,10 +157,17 @@ public class SearchGroupsResolverInMemoryTests extends LdapTestCase {
}
private List<String> resolveGroups(Settings settings, String userDn) {
final SearchGroupsResolver resolver = new SearchGroupsResolver(settings);
final SearchGroupsResolver resolver = new SearchGroupsResolver(getConfig(settings));
final PlainActionFuture<List<String>> future = new PlainActionFuture<>();
resolver.resolve(connection, userDn, TimeValue.timeValueSeconds(30), logger, null, future);
return future.actionGet();
}
private RealmConfig getConfig(Settings settings) {
if (settings.hasValue("path.home") == false) {
settings = Settings.builder().put(settings).put("path.home", createTempDir()).build();
}
return new RealmConfig(REALM_IDENTIFIER, settings, TestEnvironment.newEnvironment(settings), new ThreadContext(settings));
}
}

View File

@ -10,61 +10,72 @@ import com.unboundid.ldap.sdk.RoundRobinDNSServerSet;
import com.unboundid.ldap.sdk.RoundRobinServerSet;
import com.unboundid.ldap.sdk.ServerSet;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapLoadBalancingSettings;
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
public class LdapLoadBalancingTests extends ESTestCase {
private static final RealmConfig.RealmIdentifier REALM_IDENTIFIER = new RealmConfig.RealmIdentifier("ldap", "ldap1");
public void testBadTypeThrowsException() {
String badType = randomAlphaOfLengthBetween(3, 12);
Settings settings = Settings.builder().put(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS + "." +
LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING, badType).build();
Settings settings = getSettings(badType);
try {
LdapLoadBalancing.serverSet(null, null, settings, null, null);
LdapLoadBalancing.serverSet(null, null, getConfig(settings), null, null);
fail("using type [" + badType + "] should have thrown an exception");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("unknown load balance type"));
}
}
public Settings getSettings(String loadBalancerType) {
return Settings.builder()
.put(getFullSettingKey(REALM_IDENTIFIER, LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING), loadBalancerType)
.put("path.home", createTempDir())
.build();
}
public void testFailoverServerSet() {
Settings settings = Settings.builder().put(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS + "." +
LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING, "failover").build();
String[] address = new String[] { "localhost" };
int[] ports = new int[] { 26000 };
ServerSet serverSet = LdapLoadBalancing.serverSet(address, ports, settings, null, null);
Settings settings = getSettings("failover");
String[] address = new String[]{"localhost"};
int[] ports = new int[]{26000};
ServerSet serverSet = LdapLoadBalancing.serverSet(address, ports, getConfig(settings), null, null);
assertThat(serverSet, instanceOf(FailoverServerSet.class));
assertThat(((FailoverServerSet)serverSet).reOrderOnFailover(), is(true));
assertThat(((FailoverServerSet) serverSet).reOrderOnFailover(), is(true));
}
public void testDnsFailover() {
Settings settings = Settings.builder().put(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS + "." +
LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING, "dns_failover").build();
String[] address = new String[] { "foo.bar" };
int[] ports = new int[] { 26000 };
ServerSet serverSet = LdapLoadBalancing.serverSet(address, ports, settings, null, null);
Settings settings = getSettings("dns_failover");
String[] address = new String[]{"foo.bar"};
int[] ports = new int[]{26000};
ServerSet serverSet = LdapLoadBalancing.serverSet(address, ports, getConfig(settings), null, null);
assertThat(serverSet, instanceOf(RoundRobinDNSServerSet.class));
assertThat(((RoundRobinDNSServerSet)serverSet).getAddressSelectionMode(), is(RoundRobinDNSServerSet.AddressSelectionMode.FAILOVER));
assertThat(((RoundRobinDNSServerSet) serverSet).getAddressSelectionMode(),
is(RoundRobinDNSServerSet.AddressSelectionMode.FAILOVER));
}
public void testDnsFailoverBadArgs() {
Settings settings = Settings.builder().put(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS + "." +
LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING, "dns_failover").build();
String[] addresses = new String[] { "foo.bar", "localhost" };
int[] ports = new int[] { 26000, 389 };
final Settings settings = getSettings("dns_failover");
final RealmConfig config = getConfig(settings);
String[] addresses = new String[]{"foo.bar", "localhost"};
int[] ports = new int[]{26000, 389};
try {
LdapLoadBalancing.serverSet(addresses, ports, settings, null, null);
LdapLoadBalancing.serverSet(addresses, ports, config, null, null);
fail("dns server sets only support a single URL");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("single url"));
}
try {
LdapLoadBalancing.serverSet(new String[] { "127.0.0.1" }, new int[] { 389 }, settings, null, null);
LdapLoadBalancing.serverSet(new String[]{"127.0.0.1"}, new int[]{389}, config, null, null);
fail("dns server sets only support DNS names");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("DNS name"));
@ -72,42 +83,44 @@ public class LdapLoadBalancingTests extends ESTestCase {
}
public void testRoundRobin() {
Settings settings = Settings.builder().put(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS + "." +
LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING, "round_robin").build();
String[] address = new String[] { "localhost", "foo.bar" };
int[] ports = new int[] { 389, 389 };
ServerSet serverSet = LdapLoadBalancing.serverSet(address, ports, settings, null, null);
Settings settings = getSettings("round_robin");
String[] address = new String[]{"localhost", "foo.bar"};
int[] ports = new int[]{389, 389};
ServerSet serverSet = LdapLoadBalancing.serverSet(address, ports, getConfig(settings), null, null);
assertThat(serverSet, instanceOf(RoundRobinServerSet.class));
}
public void testDnsRoundRobin() {
Settings settings = Settings.builder().put(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS + "." +
LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING, "dns_round_robin").build();
String[] address = new String[] { "foo.bar" };
int[] ports = new int[] { 26000 };
ServerSet serverSet = LdapLoadBalancing.serverSet(address, ports, settings, null, null);
Settings settings = getSettings("dns_round_robin");
String[] address = new String[]{"foo.bar"};
int[] ports = new int[]{26000};
ServerSet serverSet = LdapLoadBalancing.serverSet(address, ports, getConfig(settings), null, null);
assertThat(serverSet, instanceOf(RoundRobinDNSServerSet.class));
assertThat(((RoundRobinDNSServerSet)serverSet).getAddressSelectionMode(),
assertThat(((RoundRobinDNSServerSet) serverSet).getAddressSelectionMode(),
is(RoundRobinDNSServerSet.AddressSelectionMode.ROUND_ROBIN));
}
public void testDnsRoundRobinBadArgs() {
Settings settings = Settings.builder().put(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS + "." +
LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING, "dns_round_robin").build();
String[] addresses = new String[] { "foo.bar", "localhost" };
int[] ports = new int[] { 26000, 389 };
final Settings settings = getSettings("dns_round_robin");
final RealmConfig config = getConfig(settings);
String[] addresses = new String[]{"foo.bar", "localhost"};
int[] ports = new int[]{26000, 389};
try {
LdapLoadBalancing.serverSet(addresses, ports, settings, null, null);
LdapLoadBalancing.serverSet(addresses, ports, config, null, null);
fail("dns server sets only support a single URL");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("single url"));
}
try {
LdapLoadBalancing.serverSet(new String[] { "127.0.0.1" }, new int[] { 389 }, settings, null, null);
LdapLoadBalancing.serverSet(new String[]{"127.0.0.1"}, new int[]{389}, config, null, null);
fail("dns server sets only support DNS names");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("DNS name"));
}
}
public RealmConfig getConfig(Settings settings) {
return new RealmConfig(REALM_IDENTIFIER, settings, TestEnvironment.newEnvironment(settings), new ThreadContext(settings));
}
}

View File

@ -5,18 +5,24 @@
*/
package org.elasticsearch.xpack.security.authc.ldap.support;
import com.unboundid.ldap.sdk.Attribute;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapMetaDataResolverSettings;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.unboundid.ldap.sdk.Attribute;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.test.ESTestCase;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
@ -30,7 +36,15 @@ public class LdapMetaDataResolverTests extends ESTestCase {
private LdapMetaDataResolver resolver;
public void testParseSettings() throws Exception {
resolver = new LdapMetaDataResolver(Settings.builder().putList("metadata", "cn", "uid").build(), false);
final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier(LdapRealmSettings.LDAP_TYPE, "my_ldap");
final Settings settings = Settings.builder()
.put("path.home", createTempDir())
.putList(RealmSettings.getFullSettingKey(realmId.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING),
"cn", "uid")
.build();
RealmConfig config = new RealmConfig(realmId,
settings, TestEnvironment.newEnvironment(settings), new ThreadContext(settings));
resolver = new LdapMetaDataResolver(config, false);
assertThat(resolver.attributeNames(), arrayContaining("cn", "uid"));
}

View File

@ -13,7 +13,6 @@ import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPInterface;
import com.unboundid.ldap.sdk.LDAPURL;
import com.unboundid.ldap.sdk.SimpleBindRequest;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.common.Strings;
@ -23,13 +22,16 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapSessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.SearchGroupsResolverSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapLoadBalancingSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.support.DnRoleMapperSettings;
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
import org.elasticsearch.xpack.core.ssl.VerificationMode;
import org.elasticsearch.xpack.security.authc.support.DnRoleMapper;
import org.junit.After;
@ -43,12 +45,13 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.URLS_SETTING;
public abstract class LdapTestCase extends ESTestCase {
private static final String USER_DN_TEMPLATES_SETTING_KEY = LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING.getKey();
protected static final RealmConfig.RealmIdentifier REALM_IDENTIFIER = new RealmConfig.RealmIdentifier("ldap", "ldap1");
static int numberOfLdapServers;
protected InMemoryDirectoryServer[] ldapServers;
@ -93,11 +96,11 @@ public abstract class LdapTestCase extends ESTestCase {
}
public static Settings buildLdapSettings(String ldapUrl, String userTemplate, String groupSearchBase, LdapSearchScope scope) {
return buildLdapSettings(new String[] { ldapUrl }, new String[] { userTemplate }, groupSearchBase, scope);
return buildLdapSettings(new String[]{ldapUrl}, new String[]{userTemplate}, groupSearchBase, scope);
}
public static Settings buildLdapSettings(String[] ldapUrl, String userTemplate, String groupSearchBase, LdapSearchScope scope) {
return buildLdapSettings(ldapUrl, new String[] { userTemplate }, groupSearchBase, scope);
return buildLdapSettings(ldapUrl, new String[]{userTemplate}, groupSearchBase, scope);
}
public static Settings buildLdapSettings(String[] ldapUrl, String[] userTemplate, String groupSearchBase, LdapSearchScope scope) {
@ -115,39 +118,45 @@ public abstract class LdapTestCase extends ESTestCase {
String groupSearchBase, LdapSearchScope scope,
LdapLoadBalancing serverSetType,
boolean ignoreReferralErrors) {
return buildLdapSettings(REALM_IDENTIFIER, ldapUrl, userTemplate, groupSearchBase, scope, serverSetType, ignoreReferralErrors);
}
public static Settings buildLdapSettings(RealmConfig.RealmIdentifier realmId, String[] ldapUrl, String[] userTemplate,
String groupSearchBase, LdapSearchScope scope, LdapLoadBalancing serverSetType,
boolean ignoreReferralErrors) {
Settings.Builder builder = Settings.builder()
.putList(URLS_SETTING, ldapUrl)
.putList(USER_DN_TEMPLATES_SETTING_KEY, userTemplate)
.put(SessionFactorySettings.TIMEOUT_TCP_CONNECTION_SETTING, TimeValue.timeValueSeconds(1L))
.put(SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING.getKey(), ignoreReferralErrors)
.put("group_search.base_dn", groupSearchBase)
.put("group_search.scope", scope);
.putList(getFullSettingKey(realmId, URLS_SETTING), ldapUrl)
.putList(getFullSettingKey(realmId.getName(), LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING), userTemplate)
.put(getFullSettingKey(realmId, SessionFactorySettings.TIMEOUT_TCP_CONNECTION_SETTING), TimeValue.timeValueSeconds(1L))
.put(getFullSettingKey(realmId, SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING), ignoreReferralErrors)
.put(getFullSettingKey(realmId, SearchGroupsResolverSettings.BASE_DN), groupSearchBase)
.put(getFullSettingKey(realmId, SearchGroupsResolverSettings.SCOPE), scope);
if (serverSetType != null) {
builder.put(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS + "." +
LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING, serverSetType.toString());
builder.put(getFullSettingKey(realmId, LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING), serverSetType.toString());
}
return builder.build();
}
public static Settings buildLdapSettings(String[] ldapUrl, String userTemplate, boolean hostnameVerification) {
Settings.Builder builder = Settings.builder()
.putList(URLS_SETTING, ldapUrl)
.putList(USER_DN_TEMPLATES_SETTING_KEY, userTemplate);
.putList(getFullSettingKey(REALM_IDENTIFIER, URLS_SETTING), ldapUrl)
.putList(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING), userTemplate);
if (randomBoolean()) {
builder.put("ssl.verification_mode", hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE);
builder.put(getFullSettingKey(REALM_IDENTIFIER, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM),
hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE);
} else {
builder.put(HOSTNAME_VERIFICATION_SETTING, hostnameVerification);
builder.put(getFullSettingKey(REALM_IDENTIFIER, HOSTNAME_VERIFICATION_SETTING), hostnameVerification);
}
return builder.build();
}
protected DnRoleMapper buildGroupAsRoleMapper(ResourceWatcherService resourceWatcherService) {
Settings settings = Settings.builder()
.put(DnRoleMapperSettings.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING.getKey(), true)
.put(getFullSettingKey(REALM_IDENTIFIER, DnRoleMapperSettings.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING), true)
.put("path.home", createTempDir())
.build();
Settings global = Settings.builder().put("path.home", createTempDir()).build();
RealmConfig config = new RealmConfig("ldap1", settings, global, TestEnvironment.newEnvironment(global),
new ThreadContext(Settings.EMPTY));
RealmConfig config = new RealmConfig(REALM_IDENTIFIER, settings,
TestEnvironment.newEnvironment(settings), new ThreadContext(Settings.EMPTY));
return new DnRoleMapper(config, resourceWatcherService);
}
@ -179,12 +188,12 @@ public abstract class LdapTestCase extends ESTestCase {
if (conn instanceof LDAPConnection) {
assertTrue(((LDAPConnection) conn).isConnected());
assertEquals(bindRequest.getBindDN(),
((SimpleBindRequest)((LDAPConnection) conn).getLastBindRequest()).getBindDN());
((SimpleBindRequest) ((LDAPConnection) conn).getLastBindRequest()).getBindDN());
((LDAPConnection) conn).reconnect();
} else if (conn instanceof LDAPConnectionPool) {
try (LDAPConnection c = ((LDAPConnectionPool) conn).getConnection()) {
assertTrue(c.isConnected());
assertEquals(bindRequest.getBindDN(), ((SimpleBindRequest)c.getLastBindRequest()).getBindDN());
assertEquals(bindRequest.getBindDN(), ((SimpleBindRequest) c.getLastBindRequest()).getBindDN());
c.reconnect();
}
}
@ -196,4 +205,15 @@ public abstract class LdapTestCase extends ESTestCase {
}
});
}
protected Settings mergeSettings(Settings local, Settings global) {
final Settings.Builder builder = Settings.builder()
.put(global, true)
.put(local, false);
final Settings.Builder tmpLocal = Settings.builder().put(local, true);
SecuritySettingsSource.addSecureSettings(builder,
mainSecure -> SecuritySettingsSource.addSecureSettings(tmpLocal, localSecure -> mainSecure.merge(localSecure))
);
return builder.build();
}
}

View File

@ -237,8 +237,8 @@ public class SessionFactoryLoadBalancingTests extends LdapTestCase {
String userTemplate = "cn={0},ou=people,o=sevenSeas";
Settings settings = buildLdapSettings(ldapUrls(), new String[] { userTemplate }, groupSearchBase,
LdapSearchScope.SUB_TREE, loadBalancing);
Settings globalSettings = Settings.builder().put("path.home", createTempDir()).build();
RealmConfig config = new RealmConfig("test-session-factory", settings, globalSettings,
Settings globalSettings = Settings.builder().put("path.home", createTempDir()).put(settings).build();
RealmConfig config = new RealmConfig(REALM_IDENTIFIER, globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY));
return new TestSessionFactory(config, new SSLService(Settings.EMPTY, TestEnvironment.newEnvironment(config.globalSettings())),
threadPool);

Some files were not shown because too many files have changed in this diff Show More