diff --git a/docs/reference/migration/migrate_7_0/settings.asciidoc b/docs/reference/migration/migrate_7_0/settings.asciidoc index 85648da4f0d25..dea21a57ad4f4 100644 --- a/docs/reference/migration/migrate_7_0/settings.asciidoc +++ b/docs/reference/migration/migrate_7_0/settings.asciidoc @@ -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. diff --git a/docs/reference/security/securing-communications/tls-ad.asciidoc b/docs/reference/security/securing-communications/tls-ad.asciidoc index 2421925f08ebe..cd0395b6725f2 100644 --- a/docs/reference/security/securing-communications/tls-ad.asciidoc +++ b/docs/reference/security/securing-communications/tls-ad.asciidoc @@ -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. diff --git a/docs/reference/security/securing-communications/tls-ldap.asciidoc b/docs/reference/security/securing-communications/tls-ldap.asciidoc index 1ffc667cd33c1..2d7b2546becb7 100644 --- a/docs/reference/security/securing-communications/tls-ldap.asciidoc +++ b/docs/reference/security/securing-communications/tls-ldap.asciidoc @@ -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`. \ No newline at end of file + `ssl.verification_mode` property to `certificate`. diff --git a/docs/reference/settings/security-settings.asciidoc b/docs/reference/settings/security-settings.asciidoc index 8d5c832adcc86..c8e5895625c30 100644 --- a/docs/reference/settings/security-settings.asciidoc +++ b/docs/reference/settings/security-settings.asciidoc @@ -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 <>. 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 <>. 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 ... ... diff --git a/x-pack/docs/en/security/authentication/configuring-active-directory-realm.asciidoc b/x-pack/docs/en/security/authentication/configuring-active-directory-realm.asciidoc index ba554eb8595dd..ab8830a64f179 100644 --- a/x-pack/docs/en/security/authentication/configuring-active-directory-realm.asciidoc +++ b/x-pack/docs/en/security/authentication/configuring-active-directory-realm.asciidoc @@ -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. diff --git a/x-pack/docs/en/security/authentication/configuring-file-realm.asciidoc b/x-pack/docs/en/security/authentication/configuring-file-realm.asciidoc index fbf823dae7060..ac596c11e0e5a 100644 --- a/x-pack/docs/en/security/authentication/configuring-file-realm.asciidoc +++ b/x-pack/docs/en/security/authentication/configuring-file-realm.asciidoc @@ -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 <> 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 ------------------------------------------------------------ -- diff --git a/x-pack/docs/en/security/authentication/configuring-kerberos-realm.asciidoc b/x-pack/docs/en/security/authentication/configuring-kerberos-realm.asciidoc index cc0863112c7e4..25245b69cbea7 100644 --- a/x-pack/docs/en/security/authentication/configuring-kerberos-realm.asciidoc +++ b/x-pack/docs/en/security/authentication/configuring-kerberos-realm.asciidoc @@ -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 diff --git a/x-pack/docs/en/security/authentication/configuring-ldap-realm.asciidoc b/x-pack/docs/en/security/authentication/configuring-ldap-realm.asciidoc index a5f8c3e441205..9cc54effa1f78 100644 --- a/x-pack/docs/en/security/authentication/configuring-ldap-realm.asciidoc +++ b/x-pack/docs/en/security/authentication/configuring-ldap-realm.asciidoc @@ -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 <> 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 -<> 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 <> 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 -------------------------------------------------- -- diff --git a/x-pack/docs/en/security/authentication/configuring-native-realm.asciidoc b/x-pack/docs/en/security/authentication/configuring-native-realm.asciidoc index e9fb9cd0eb8a0..55d5f361132c9 100644 --- a/x-pack/docs/en/security/authentication/configuring-native-realm.asciidoc +++ b/x-pack/docs/en/security/authentication/configuring-native-realm.asciidoc @@ -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. - -. 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. +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 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 <> 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, diff --git a/x-pack/docs/en/security/authentication/configuring-pki-realm.asciidoc b/x-pack/docs/en/security/authentication/configuring-pki-realm.asciidoc index 9a4d5fcf18bf6..587592b9f2001 100644 --- a/x-pack/docs/en/security/authentication/configuring-pki-realm.asciidoc +++ b/x-pack/docs/en/security/authentication/configuring-pki-realm.asciidoc @@ -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 <> 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 diff --git a/x-pack/docs/en/security/authentication/configuring-saml-realm.asciidoc b/x-pack/docs/en/security/authentication/configuring-saml-realm.asciidoc index d16e13025509d..81859c4fd0490 100644 --- a/x-pack/docs/en/security/authentication/configuring-saml-realm.asciidoc +++ b/x-pack/docs/en/security/authentication/configuring-saml-realm.asciidoc @@ -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." diff --git a/x-pack/docs/en/security/authentication/custom-realm.asciidoc b/x-pack/docs/en/security/authentication/custom-realm.asciidoc index 0ae33d434a1f5..43a6195385559 100644 --- a/x-pack/docs/en/security/authentication/custom-realm.asciidoc +++ b/x-pack/docs/en/security/authentication/custom-realm.asciidoc @@ -85,13 +85,15 @@ bin/elasticsearch-plugin install file:////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 diff --git a/x-pack/docs/en/security/authentication/saml-guide.asciidoc b/x-pack/docs/en/security/authentication/saml-guide.asciidoc index b0077dc1ba9d4..97bbd483a0311 100644 --- a/x-pack/docs/en/security/authentication/saml-guide.asciidoc +++ b/x-pack/docs/en/security/authentication/saml-guide.asciidoc @@ -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 <> 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/" diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityExtension.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityExtension.java index f422d073cfeb5..82d31aa8a2993 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityExtension.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityExtension.java @@ -7,12 +7,10 @@ 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 @@ default Map getRealms(ResourceWatcherService resourceWatc return Collections.emptyMap(); } - /** - * Returns the set of {@link Setting settings} that may be configured for the each type of realm. - * - * Each setting key 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 all possible settings. - * - * The life-cycle of an extension dictates that this method will be called before {@link #getRealms(ResourceWatcherService)} - */ - default Map>> getRealmSettings() { return Collections.emptyMap(); } - /** * Returns a handler for authentication failures, or null to use the default handler. * diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/InternalRealmsSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/InternalRealmsSettings.java index 0570a2bdad23f..707912fb20268 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/InternalRealmsSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/InternalRealmsSettings.java @@ -13,26 +13,25 @@ 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 internal realm type. * This excludes the ReservedRealm, as it cannot be configured dynamically. - * @return A map from realm-type to a collection of Setting objects. */ - public static Map>> getSettings() { - Map>> 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> getSettings() { + Set> 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); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Realm.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Realm.java index 5ccd8bec1a53d..adc79279a70ee 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Realm.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Realm.java @@ -27,16 +27,10 @@ public abstract class Realm implements Comparable { 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 Realm(String type, RealmConfig config) { * @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 int compareTo(Realm other) { 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 void usageStats(ActionListener> listener) { @Override public String toString() { - return type + "/" + config.name; + return config.type() + "/" + config.name(); } /** diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmConfig.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmConfig.java index 759f938491e30..f6f370addba83 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmConfig.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmConfig.java @@ -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(identifier, globalSettings, env, threadContext); + } + + public RealmConfig(RealmIdentifier identifier, Settings globalSettings, Environment env, ThreadContext threadContext) { - this.name = name; - this.settings = settings; + 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 Environment env() { 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 + *
    + *
  • {@code type} is a fixed string (known at compile time) that identifies the type of the realm being configured.
  • + *
  • {@code (name)} is a variable string (known only at runtime) that uniquely names the realm.
  • + *
  • {@code key} is a fixed string (known at compile time) that identifies a specific setting within the realm.
  • + *
+ * 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 Setting getConcreteSetting(Setting.AffixSetting 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 Setting getConcreteSetting(Function> 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 concrete through {@link #getConcreteSetting(Setting.AffixSetting)}, which is then + * used to {@link Setting#get(Settings) retrieve} the setting value. + */ + public T getSetting(Setting.AffixSetting 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 concrete setting from the provided + * {@link Function}/{@link Setting.AffixSetting}, and this concrete setting is then used to + * {@link Setting#get(Settings) retrieve} the setting value. + */ + public T getSetting(Function> 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 concrete setting from the provided + * {@link Function}/{@link Setting.AffixSetting}. + * If this concrete setting {@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 getSetting(Function> settingFactory, Supplier 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 concrete setting from the provided + * {@link Setting.AffixSetting}. + * If this concrete setting {@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 getSetting(Setting.AffixSetting setting, Supplier orElse) { + final Setting 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 concrete setting from the provided + * {@link Function}/{@link Setting.AffixSetting}, and this concrete setting is then used to + * {@link Setting#exists(Settings) check} for a value. + */ + public boolean hasSetting(Function> 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 concrete setting from the provided + * {@link Setting.AffixSetting}, and this concrete setting is then used to {@link Setting#exists(Settings) check} for a value. + */ + public boolean hasSetting(Setting.AffixSetting 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; + } + } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmSettings.java index daf1775a80a52..913fcba3d33c8 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmSettings.java @@ -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. - *

- * 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). - *

- * Instead, realm configuration relies on the validator parameter to - * {@link Setting#groupSetting(String, Consumer, Setting.Property...)} in order to validate each realm in a way that respects the - * declared type. - * Internally, this validation delegates to {@link AbstractScopedSettings#validate(Settings, boolean)} so that validation is reasonably - * aligned - * with the way we validate settings globally. - *

- *

- * 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 type 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."); - - static final Setting TYPE_SETTING = Setting.simpleString("type", Setting.Property.NodeScope); - static final Setting ENABLED_SETTING = Setting.boolSetting("enabled", true, Setting.Property.NodeScope); - static final Setting ORDER_SETTING = Setting.intSetting("order", Integer.MAX_VALUE, Setting.Property.NodeScope); + public static final String PREFIX = "xpack.security.authc.realms."; - /** - * Add the {@link Setting} configuration for all realms to the provided list. - */ - public static void addSettings(List> settingsList, List extensions) { - settingsList.add(getGroupSetting(extensions)); - } + public static final Function> ENABLED_SETTING = affixSetting("enabled", + key -> Setting.boolSetting(key, true, Setting.Property.NodeScope)); + public static final Function> ORDER_SETTING = affixSetting("order", + key -> Setting.intSetting(key, Integer.MAX_VALUE, Setting.Property.NodeScope)); - public static Collection getSettingsFilter(List extensions) { - return getSettingsByRealm(extensions).values().stream() - .flatMap(Collection::stream) - .filter(Setting::isFiltered) - .map(setting -> PREFIX + "*." + setting.getKey()) - .collect(Collectors.toSet()); + public static String realmSettingPrefix(String type) { + return PREFIX + type + "."; } - /** - * Extract the child {@link Settings} for the {@link #PREFIX realms prefix}. - * The top level names in the returned Settings will be the names of the configured realms. - */ - public static Settings get(Settings settings) { - return settings.getByPrefix(RealmSettings.PREFIX); + public static String realmSettingPrefix(RealmConfig.RealmIdentifier identifier) { + return realmSettingPrefix(identifier.getType()) + identifier.getName() + "."; } - /** - * Extracts the realm settings from a global settings object. - * Returns a Map of realm-name to realm-settings. - */ - public static Map getRealmSettings(Settings globalSettings) { - Settings realmsSettings = RealmSettings.get(globalSettings); - return realmsSettings.names().stream() - .collect(Collectors.toMap(Function.identity(), realmsSettings::getAsSettings)); + public static String realmSslPrefix(RealmConfig.RealmIdentifier identifier) { + return realmSettingPrefix(identifier) + "ssl."; } /** - * Convert the child {@link Setting} for the provided realm into a fully scoped key for use in an error message. - * @see #PREFIX + * 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 String getFullSettingKey(RealmConfig realm, Setting setting) { - return getFullSettingKey(realm.name(), setting); + public static Setting.AffixSetting simpleString(String realmType, String suffix, Setting.Property... properties) { + return Setting.affixKeySetting(realmSettingPrefix(realmType), suffix, key -> Setting.simpleString(key, properties)); } /** - * @see #getFullSettingKey(RealmConfig, Setting) + * Create a {@link Function} that acts as a factory an {@link org.elasticsearch.common.settings.Setting.AffixSetting}. + * The {@code Function} takes the realm-type 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 String getFullSettingKey(RealmConfig realm, String subKey) { - return getFullSettingKey(realm.name(), subKey); - } - - private static String getFullSettingKey(String name, Setting setting) { - return getFullSettingKey(name, setting.getKey()); - } - - private static String getFullSettingKey(String name, String subKey) { - return PREFIX + name + "." + subKey; - } - - private static Setting getGroupSetting(List extensions) { - return Setting.groupSetting(PREFIX, getSettingsValidator(extensions), Setting.Property.NodeScope); - } - - private static Consumer getSettingsValidator(List extensions) { - final Map>> childSettings = getSettingsByRealm(extensions); - childSettings.forEach(RealmSettings::verify); - return validator(childSettings); + public static Function> affixSetting(String suffix, Function> delegateFactory) { + return realmType -> Setting.affixKeySetting(realmSettingPrefix(realmType), suffix, delegateFactory); } /** - * @return A map from realm-type to a collection of Setting objects. - * @see InternalRealmsSettings#getSettings() + * Extracts the realm settings from a global settings object. + * Returns a Map of realm-id to realm-settings. */ - private static Map>> getSettingsByRealm(List extensions) { - final Map>> settingsByRealm = new HashMap<>(InternalRealmsSettings.getSettings()); - if (extensions != null) { - extensions.forEach(ext -> { - final Map>> extSettings = ext.getRealmSettings(); - extSettings.keySet().stream().filter(settingsByRealm::containsKey).forEach(type -> { - throw new IllegalArgumentException("duplicate realm type " + type); - }); - settingsByRealm.putAll(extSettings); - }); - } - return settingsByRealm; + public static Map 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)); } - private static void verify(String type, Set> settings) { - Set 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"); - } - }); + public static String getFullSettingKey(String realmName, Setting.AffixSetting setting) { + return setting.getConcreteSettingForNamespace(realmName).getKey(); } - private static Consumer validator(Map>> validSettings) { - return (settings) -> settings.names().forEach(n -> validateRealm(n, settings.getAsSettings(n), validSettings)); + public static String getFullSettingKey(RealmConfig realm, Setting.AffixSetting setting) { + return setting.getConcreteSettingForNamespace(realm.name()).getKey(); } - private static void validateRealm(String name, Settings settings, Map>> 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 getFullSettingKey(RealmConfig.RealmIdentifier realmId, Function> setting) { + return getFullSettingKey(realmId.getName(), setting.apply(realmId.getType())); } - public static String getRealmType(Settings settings) { - return TYPE_SETTING.get(settings); + public static String getFullSettingKey(RealmConfig realm, Function> setting) { + return getFullSettingKey(realm.identifier, setting); } - private static void validateRealm(String name, String type, Settings settings, Set> 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> 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> getStandardSettings(String realmType) { + return Arrays.asList(ENABLED_SETTING.apply(realmType), ORDER_SETTING.apply(realmType)); } private RealmSettings() { } + } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/esnative/NativeRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/esnative/NativeRealmSettings.java index eebcb6db7af87..16c08413fb2a6 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/esnative/NativeRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/esnative/NativeRealmSettings.java @@ -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 @@ private NativeRealmSettings() {} /** * @return The {@link Setting setting configuration} for this realm type */ - public static Set> getSettings() { - return CachingUsernamePasswordRealmSettings.getSettings(); + public static Set> getSettings() { + final Set> set = new HashSet<>(CachingUsernamePasswordRealmSettings.getSettings(TYPE)); + set.addAll(RealmSettings.getStandardSettings(TYPE)); + return set; } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/file/FileRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/file/FileRealmSettings.java index ed81d07d4ccc9..1777e8bb6ecfd 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/file/FileRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/file/FileRealmSettings.java @@ -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 @@ private FileRealmSettings() {} /** * @return The {@link Setting setting configuration} for this realm type */ - public static Set> getSettings() { - return CachingUsernamePasswordRealmSettings.getSettings(); + public static Set> getSettings() { + final Set> set = new HashSet<>(CachingUsernamePasswordRealmSettings.getSettings(TYPE)); + set.addAll(RealmSettings.getStandardSettings(TYPE)); + return set; } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/kerberos/KerberosRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/kerberos/KerberosRealmSettings.java index 656632a2ec631..1b1d44d2d114d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/kerberos/KerberosRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/kerberos/KerberosRealmSettings.java @@ -10,6 +10,7 @@ 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
* Uses single key tab for multiple service accounts. */ - public static final Setting HTTP_SERVICE_KEYTAB_PATH = - Setting.simpleString("keytab.path", Property.NodeScope); - public static final Setting SETTING_KRB_DEBUG_ENABLE = - Setting.boolSetting("krb.debug", Boolean.FALSE, Property.NodeScope); - public static final Setting SETTING_REMOVE_REALM_NAME = - Setting.boolSetting("remove_realm_name", Boolean.FALSE, Property.NodeScope); + public static final Setting.AffixSetting HTTP_SERVICE_KEYTAB_PATH = RealmSettings.simpleString(TYPE, + "keytab.path", Property.NodeScope); + + public static final Setting.AffixSetting SETTING_KRB_DEBUG_ENABLE = Setting.affixKeySetting( + RealmSettings.realmSettingPrefix(TYPE), "krb.debug", key -> Setting.boolSetting(key, Boolean.FALSE, Property.NodeScope)); + + public static final Setting.AffixSetting 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 CACHE_TTL_SETTING = Setting.timeSetting("cache.ttl", DEFAULT_TTL, Setting.Property.NodeScope); - public static final Setting CACHE_MAX_USERS_SETTING = - Setting.intSetting("cache.max_users", DEFAULT_MAX_USERS, Property.NodeScope); + public static final Setting.AffixSetting CACHE_TTL_SETTING = Setting.affixKeySetting( + RealmSettings.realmSettingPrefix(TYPE), "cache.ttl", key -> Setting.timeSetting(key, DEFAULT_TTL, Setting.Property.NodeScope)); + + public static final Setting.AffixSetting 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 @@ private KerberosRealmSettings() { /** * @return the valid set of {@link Setting}s for a {@value #TYPE} realm */ - public static Set> getSettings() { - final Set> settings = Sets.newHashSet(HTTP_SERVICE_KEYTAB_PATH, CACHE_TTL_SETTING, CACHE_MAX_USERS_SETTING, + public static Set> getSettings() { + final Set> 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; } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/ActiveDirectorySessionFactorySettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/ActiveDirectorySessionFactorySettings.java index 691b43f24635e..3bd54316736c6 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/ActiveDirectorySessionFactorySettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/ActiveDirectorySessionFactorySettings.java @@ -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 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 AD_LDAP_PORT_SETTING = Setting.intSetting("port.ldap", 389, Setting.Property.NodeScope); - public static final Setting AD_LDAPS_PORT_SETTING = Setting.intSetting("port.ldaps", 636, Setting.Property.NodeScope); - public static final Setting AD_GC_LDAP_PORT_SETTING = Setting.intSetting("port.gc_ldap", 3268, Setting.Property.NodeScope); - public static final Setting AD_GC_LDAPS_PORT_SETTING = Setting.intSetting("port.gc_ldaps", 3269, Setting.Property.NodeScope); - public static final Setting POOL_ENABLED = Setting.boolSetting("user_search.pool.enabled", - settings -> Boolean.toString(PoolingSessionFactorySettings.BIND_DN.exists(settings)), Setting.Property.NodeScope); - - private ActiveDirectorySessionFactorySettings() {} - - public static Set> getSettings() { - Set> 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_BASEDN_SETTING_KEY = "user_search.base_dn"; + public static final Setting.AffixSetting AD_USER_SEARCH_BASEDN_SETTING + = RealmSettings.simpleString(AD_TYPE, AD_USER_SEARCH_BASEDN_SETTING_KEY, Setting.Property.NodeScope); + + private static final String AD_USER_SEARCH_FILTER_SETTING_KEY = "user_search.filter"; + public static final Setting.AffixSetting 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 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 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 AD_USER_SEARCH_SCOPE_SETTING + = RealmSettings.simpleString(AD_TYPE, AD_USER_SEARCH_SCOPE_SETTING_KEY, Setting.Property.NodeScope); + + public static final Setting.AffixSetting 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 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 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 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 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> getSettings() { + Set> 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; } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapRealmSettings.java index 272b4115b285e..4b746a7901613 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapRealmSettings.java @@ -7,6 +7,7 @@ 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 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 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> 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> getSettings(String type) { - Set> settings = new HashSet<>(); - settings.addAll(CachingUsernamePasswordRealmSettings.getSettings()); - settings.addAll(CompositeRoleMapperSettings.getSettings()); - settings.add(LdapRealmSettings.EXECUTION_TIMEOUT); + public static Set> getSettings(String type) { + Set> 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; } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapSessionFactorySettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapSessionFactorySettings.java index 4fb7e9a1d9346..0643bf9daa9d1 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapSessionFactorySettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapSessionFactorySettings.java @@ -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.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> USER_DN_TEMPLATES_SETTING = Setting.listSetting("user_dn_templates", - Collections.emptyList(), Function.identity(), Setting.Property.NodeScope); + public static final Setting.AffixSetting> 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> getSettings() { - Set> settings = new HashSet<>(); - settings.addAll(SessionFactorySettings.getSettings()); + public static Set> getSettings() { + Set> settings = new HashSet<>(); + settings.addAll(SessionFactorySettings.getSettings(LDAP_TYPE)); settings.add(USER_DN_TEMPLATES_SETTING); return settings; } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapUserSearchSessionFactorySettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapUserSearchSessionFactorySettings.java index 86f635e7427ff..89eadc962928a 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapUserSearchSessionFactorySettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapUserSearchSessionFactorySettings.java @@ -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.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 SEARCH_ATTRIBUTE = new Setting<>("user_search.attribute", - LdapUserSearchSessionFactorySettings.DEFAULT_USERNAME_ATTRIBUTE, - Function.identity(), Setting.Property.NodeScope, Setting.Property.Deprecated); - public static final Setting SEARCH_BASE_DN = Setting.simpleString("user_search.base_dn", Setting.Property.NodeScope); - public static final Setting SEARCH_FILTER = Setting.simpleString("user_search.filter", Setting.Property.NodeScope); - public static final Setting SEARCH_SCOPE = new Setting<>("user_search.scope", (String) null, - s -> LdapSearchScope.resolve(s, LdapSearchScope.SUB_TREE), Setting.Property.NodeScope); - public static final Setting POOL_ENABLED = Setting.boolSetting("user_search.pool.enabled", true, Setting.Property.NodeScope); + public static final Setting.AffixSetting 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 SEARCH_BASE_DN + = RealmSettings.simpleString(LDAP_TYPE, "user_search.base_dn", Setting.Property.NodeScope); + + public static final Setting.AffixSetting SEARCH_FILTER + = RealmSettings.simpleString(LDAP_TYPE, "user_search.filter", Setting.Property.NodeScope); + + public static final Setting.AffixSetting 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 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> getSettings() { - Set> settings = new HashSet<>(); - settings.addAll(SessionFactorySettings.getSettings()); - settings.addAll(PoolingSessionFactorySettings.getSettings()); + public static Set> getSettings() { + Set> 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; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/PoolingSessionFactorySettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/PoolingSessionFactorySettings.java index 88ff5485a5474..b7b0d529d33e3 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/PoolingSessionFactorySettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/PoolingSessionFactorySettings.java @@ -8,37 +8,62 @@ 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 BIND_DN = Setting.simpleString("bind_dn", Setting.Property.NodeScope, Setting.Property.Filtered); - public static final Setting LEGACY_BIND_PASSWORD = new Setting<>("bind_password", "", SecureString::new, - Setting.Property.NodeScope, Setting.Property.Filtered, Setting.Property.Deprecated); - public static final Setting SECURE_BIND_PASSWORD = secureString("secure_bind_password", LEGACY_BIND_PASSWORD); + + public static final String BIND_DN_SUFFIX = "bind_dn"; + public static final Function> BIND_DN = RealmSettings.affixSetting(BIND_DN_SUFFIX, + key -> Setting.simpleString(key, Setting.Property.NodeScope, Setting.Property.Filtered)); + + public static final Function> 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> 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 POOL_INITIAL_SIZE = Setting.intSetting("user_search.pool.initial_size", - DEFAULT_CONNECTION_POOL_INITIAL_SIZE, 0, Setting.Property.NodeScope); + public static final Function> 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 POOL_SIZE = Setting.intSetting("user_search.pool.size", - DEFAULT_CONNECTION_POOL_SIZE, 1, Setting.Property.NodeScope); - public static final Setting HEALTH_CHECK_INTERVAL = Setting.timeSetting("user_search.pool.health_check.interval", - DEFAULT_HEALTH_CHECK_INTERVAL, Setting.Property.NodeScope); - public static final Setting HEALTH_CHECK_ENABLED = Setting.boolSetting("user_search.pool.health_check.enabled", - true, Setting.Property.NodeScope); - public static final Setting> HEALTH_CHECK_DN = new Setting<>("user_search.pool.health_check.dn", (String) null, - Optional::ofNullable, Setting.Property.NodeScope); - - private PoolingSessionFactorySettings() {} - - public static Set> 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> POOL_SIZE = RealmSettings.affixSetting("user_search.pool.size", + key -> Setting.intSetting(key, DEFAULT_CONNECTION_POOL_SIZE, 1, Setting.Property.NodeScope)); + + public static final Function> HEALTH_CHECK_INTERVAL = RealmSettings.affixSetting( + "user_search.pool.health_check.interval", + key -> Setting.timeSetting(key, DEFAULT_HEALTH_CHECK_INTERVAL, Setting.Property.NodeScope)); + + public static final Function> HEALTH_CHECK_ENABLED = RealmSettings.affixSetting( + "user_search.pool.health_check.enabled", + key -> Setting.boolSetting(key, true, Setting.Property.NodeScope)); + + public static final Function>> 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> 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()); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/SearchGroupsResolverSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/SearchGroupsResolverSettings.java index 67ae3bcf24b2d..f9a8e697a2399 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/SearchGroupsResolverSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/SearchGroupsResolverSettings.java @@ -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 BASE_DN = Setting.simpleString("group_search.base_dn", + + public static final Function> BASE_DN = RealmSettings.affixSetting( + "group_search.base_dn", key -> Setting.simpleString(key, new Setting.Property[]{Setting.Property.NodeScope})); + + public static final Function> 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 USER_ATTRIBUTE = RealmSettings.simpleString(LDAP_TYPE, "group_search.user_attribute", Setting.Property.NodeScope); - public static final Setting SCOPE = new Setting<>("group_search.scope", (String) null, - s -> LdapSearchScope.resolve(s, LdapSearchScope.SUB_TREE), Setting.Property.NodeScope); - public static final Setting 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 FILTER = new Setting<>("group_search.filter", - GROUP_SEARCH_DEFAULT_FILTER, Function.identity(), Setting.Property.NodeScope); + public static final Setting.AffixSetting 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> getSettings() { - Set> settings = new HashSet<>(); - settings.add(BASE_DN); - settings.add(FILTER); - settings.add(USER_ATTRIBUTE); - settings.add(SCOPE); + public static Set> getSettings(String realmType) { + Set> 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; } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/UserAttributeGroupsResolverSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/UserAttributeGroupsResolverSettings.java index 88538a810a5dc..c6f36c3c3cd03 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/UserAttributeGroupsResolverSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/UserAttributeGroupsResolverSettings.java @@ -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 ATTRIBUTE = new Setting<>("user_group_attribute", "memberOf", - Function.identity(), Setting.Property.NodeScope); + public static final Setting.AffixSetting 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> getSettings() { + public static Set> getSettings() { return Collections.singleton(ATTRIBUTE); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapLoadBalancingSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapLoadBalancingSettings.java index 4d7aff0939754..325862a2c3c93 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapLoadBalancingSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapLoadBalancingSettings.java @@ -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> LOAD_BALANCE_TYPE_SETTING = RealmSettings.affixSetting( + "load_balance.type", key -> Setting.simpleString(key, Setting.Property.NodeScope)); - public static Set> getSettings() { - Set> 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> CACHE_TTL_SETTING = RealmSettings.affixSetting( + "load_balance.cache_ttl", key -> Setting.timeSetting(key, CACHE_TTL_DEFAULT, Setting.Property.NodeScope)); + + private LdapLoadBalancingSettings() { + } + + public static Set> getSettings(String realmType) { + Set> settings = new HashSet<>(); + settings.add(LOAD_BALANCE_TYPE_SETTING.apply(realmType)); + settings.add(CACHE_TTL_SETTING.apply(realmType)); return settings; } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapMetaDataResolverSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapMetaDataResolverSettings.java index e284de9c03c3d..878325f983786 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapMetaDataResolverSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapMetaDataResolverSettings.java @@ -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> ADDITIONAL_META_DATA_SETTING = Setting.listSetting( - "metadata", Collections.emptyList(), Function.identity(), Setting.Property.NodeScope); + public static final Setting.AffixSetting> 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> getSettings() { + public static List> getSettings() { return Collections.singletonList(ADDITIONAL_META_DATA_SETTING); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapSearchScope.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapSearchScope.java index 3c3d6bc8ab818..d951a7dbc65dd 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapSearchScope.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapSearchScope.java @@ -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 SearchScope scope() { } public static LdapSearchScope resolve(String scope, LdapSearchScope defaultScope) { - if (scope == null) { + if (Strings.isNullOrEmpty(scope)) { return defaultScope; } switch (scope.toLowerCase(Locale.ENGLISH)) { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/SessionFactorySettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/SessionFactorySettings.java index 42fc70f25176d..378cf5bd0e2a0 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/SessionFactorySettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/SessionFactorySettings.java @@ -7,38 +7,53 @@ 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 IGNORE_REFERRAL_ERRORS_SETTING = Setting.boolSetting( - "ignore_referral_errors", true, Setting.Property.NodeScope); + + public static final Function>> 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> TIMEOUT_TCP_CONNECTION_SETTING = RealmSettings.affixSetting( + "timeout.tcp_connect", key -> Setting.timeSetting(key, TIMEOUT_DEFAULT, Setting.Property.NodeScope)); + + public static final Function> TIMEOUT_TCP_READ_SETTING = RealmSettings.affixSetting( + "timeout.tcp_read", key -> Setting.timeSetting(key, TIMEOUT_DEFAULT, Setting.Property.NodeScope)); + + public static final Function> TIMEOUT_LDAP_SETTING = RealmSettings.affixSetting( + "timeout.ldap_search", key -> Setting.timeSetting(key, TIMEOUT_DEFAULT, Setting.Property.NodeScope)); + + public static final Function> HOSTNAME_VERIFICATION_SETTING = RealmSettings.affixSetting( + "hostname_verification", key -> Setting.boolSetting(key, true, Setting.Property.NodeScope, Setting.Property.Filtered)); + + public static final Function> FOLLOW_REFERRALS_SETTING = RealmSettings.affixSetting( + "follow_referrals", key -> Setting.boolSetting(key, true, Setting.Property.NodeScope)); + + public static final Function> IGNORE_REFERRAL_ERRORS_SETTING = RealmSettings.affixSetting( + "ignore_referral_errors", key -> Setting.boolSetting(key, true, Setting.Property.NodeScope)); + + private SessionFactorySettings() { + } - private SessionFactorySettings() {} - - public static Set> getSettings() { - Set> 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 Set> getSettings(String realmType) { + Set> 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; } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/pki/PkiRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/pki/PkiRealmSettings.java index 53af4938a8ff4..cd153c9009ed6 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/pki/PkiRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/pki/PkiRealmSettings.java @@ -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 USERNAME_PATTERN_SETTING = new Setting<>("username_pattern", DEFAULT_USERNAME_PATTERN, - s -> Pattern.compile(s, Pattern.CASE_INSENSITIVE), Setting.Property.NodeScope); + public static final Setting.AffixSetting 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 static final TimeValue DEFAULT_TTL = TimeValue.timeValueMinutes(20); - public static final Setting CACHE_TTL_SETTING = Setting.timeSetting("cache.ttl", DEFAULT_TTL, Setting.Property.NodeScope); + public static final Setting.AffixSetting 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 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 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> TRUST_STORE_PATH; + public static final Setting.AffixSetting> TRUST_STORE_TYPE; + public static final Setting.AffixSetting TRUST_STORE_PASSWORD; + public static final Setting.AffixSetting LEGACY_TRUST_STORE_PASSWORD; + public static final Setting.AffixSetting TRUST_STORE_ALGORITHM; + public static final Setting.AffixSetting> CAPATH_SETTING; - private PkiRealmSettings() {} + 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> getSettings() { - Set> settings = new HashSet<>(); + public static Set> getSettings() { + Set> 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; } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/saml/SamlRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/saml/SamlRealmSettings.java index e254cee124300..437dca0c60e76 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/saml/SamlRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/saml/SamlRealmSettings.java @@ -8,6 +8,8 @@ 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 IDP_ENTITY_ID = Setting.simpleString("idp.entity_id", Setting.Property.NodeScope); - public static final Setting IDP_METADATA_PATH - = Setting.simpleString(IDP_METADATA_SETTING_PREFIX + "path", Setting.Property.NodeScope); - public static final Setting IDP_METADATA_HTTP_REFRESH - = Setting.timeSetting(IDP_METADATA_SETTING_PREFIX + "http.refresh", TimeValue.timeValueHours(1), Setting.Property.NodeScope); - public static final Setting IDP_SINGLE_LOGOUT = Setting.boolSetting("idp.use_single_logout", true, Setting.Property.NodeScope); + public static final Setting.AffixSetting IDP_ENTITY_ID + = RealmSettings.simpleString(TYPE, "idp.entity_id", Setting.Property.NodeScope); - public static final Setting SP_ENTITY_ID = Setting.simpleString("sp.entity_id", Setting.Property.NodeScope); - public static final Setting SP_ACS = Setting.simpleString("sp.acs", Setting.Property.NodeScope); - public static final Setting SP_LOGOUT = Setting.simpleString("sp.logout", Setting.Property.NodeScope); + public static final Setting.AffixSetting IDP_METADATA_PATH + = RealmSettings.simpleString(TYPE, IDP_METADATA_SETTING_PREFIX + "path", Setting.Property.NodeScope); - public static final Setting NAMEID_FORMAT = new Setting<>("nameid_format", s -> TRANSIENT_NAMEID_FORMAT, Function.identity(), - Setting.Property.NodeScope); - public static final Setting NAMEID_ALLOW_CREATE = Setting.boolSetting("nameid.allow_create", false, - Setting.Property.NodeScope); - public static final Setting NAMEID_SP_QUALIFIER = Setting.simpleString("nameid.sp_qualifier", Setting.Property.NodeScope); + public static final Setting.AffixSetting 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 FORCE_AUTHN = Setting.boolSetting("force_authn", false, Setting.Property.NodeScope); - public static final Setting POPULATE_USER_METADATA = Setting.boolSetting("populate_user_metadata", true, - Setting.Property.NodeScope); + public static final Setting.AffixSetting 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 SP_ENTITY_ID + = RealmSettings.simpleString(TYPE, "sp.entity_id", Setting.Property.NodeScope); + + public static final Setting.AffixSetting SP_ACS = RealmSettings.simpleString(TYPE, "sp.acs", Setting.Property.NodeScope); + public static final Setting.AffixSetting SP_LOGOUT = RealmSettings.simpleString(TYPE, "sp.logout", Setting.Property.NodeScope); + + public static final Setting.AffixSetting 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 NAMEID_ALLOW_CREATE = Setting.affixKeySetting( + RealmSettings.realmSettingPrefix(TYPE), "nameid.allow_create", + key -> Setting.boolSetting(key, false, Setting.Property.NodeScope)); + public static final Setting.AffixSetting NAMEID_SP_QUALIFIER + = RealmSettings.simpleString(TYPE, "nameid.sp_qualifier", Setting.Property.NodeScope); + + public static final Setting.AffixSetting FORCE_AUTHN = Setting.affixKeySetting( + RealmSettings.realmSettingPrefix(TYPE), "force_authn", + key -> Setting.boolSetting(key, false, Setting.Property.NodeScope)); + + public static final Setting.AffixSetting 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 ENCRYPTION_KEY_ALIAS = - Setting.simpleString("encryption.keystore.alias", Setting.Property.NodeScope); + public static final String ENCRYPTION_SETTING_KEY = "encryption."; + public static final Setting.AffixSetting ENCRYPTION_KEY_ALIAS = RealmSettings.simpleString( + TYPE, ENCRYPTION_SETTING_KEY + "keystore.alias", Setting.Property.NodeScope); + + public static final String SIGNING_SETTING_KEY = "signing."; + public static final Setting.AffixSetting SIGNING_KEY_ALIAS = RealmSettings.simpleString( + TYPE, SIGNING_SETTING_KEY + "keystore.alias", Setting.Property.NodeScope); + + public static final Setting.AffixSetting> 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 X509KeyPairSettings SIGNING_SETTINGS = new X509KeyPairSettings("signing.", false); - public static final Setting SIGNING_KEY_ALIAS = - Setting.simpleString("signing.keystore.alias", Setting.Property.NodeScope); - public static final Setting> SIGNING_MESSAGE_TYPES = Setting.listSetting("signing.saml_messages", - Collections.singletonList("*"), Function.identity(), Setting.Property.NodeScope); - public static final Setting> REQUESTED_AUTHN_CONTEXT_CLASS_REF = Setting.listSetting("req_authn_context_class_ref", - Collections.emptyList(), Function.identity(),Setting.Property.NodeScope); - public static final Setting CLOCK_SKEW = Setting.positiveTimeSetting("allowed_clock_skew", TimeValue.timeValueMinutes(3), - Setting.Property.NodeScope); + public static final Setting.AffixSetting> 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 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 @@ private SamlRealmSettings() { /** * @return The {@link Setting setting configuration} for this realm type */ - public static Set> getSettings() { - final Set> set = Sets.newHashSet(IDP_ENTITY_ID, IDP_METADATA_PATH, IDP_SINGLE_LOGOUT, + public static Set> getSettings() { + final Set> 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 static final class AttributeSetting { public static final String ATTRIBUTES_PREFIX = "attributes."; public static final String ATTRIBUTE_PATTERNS_PREFIX = "attribute_patterns."; - private final Setting attribute; - private final Setting pattern; + private final Setting.AffixSetting attribute; + private final Setting.AffixSetting 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> settings() { + public Collection> 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 getAttribute() { + public Setting.AffixSetting getAttribute() { return attribute; } - public Setting getPattern() { + public Setting.AffixSetting getPattern() { return pattern; } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/CachingUsernamePasswordRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/CachingUsernamePasswordRealmSettings.java index 6b7867e421180..157a8edf5640d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/CachingUsernamePasswordRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/CachingUsernamePasswordRealmSettings.java @@ -7,29 +7,44 @@ 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 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> 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 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> 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 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> CACHE_MAX_USERS_SETTING = RealmSettings.affixSetting( + CACHE_MAX_USERS_SUFFIX, key -> Setting.intSetting(key, DEFAULT_MAX_USERS, Setting.Property.NodeScope)); - public static final Setting AUTHC_ENABLED_SETTING = Setting.boolSetting("authentication.enabled", true, - Setting.Property.NodeScope); + public static final Function> 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> getSettings() { - return new HashSet<>(Arrays.asList(CACHE_HASH_ALGO_SETTING, CACHE_TTL_SETTING, CACHE_MAX_USERS_SETTING, AUTHC_ENABLED_SETTING)); + public static Set> 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) + )); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/DelegatedAuthorizationSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/DelegatedAuthorizationSettings.java index b8384a76b41ad..969f6f0eb0d51 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/DelegatedAuthorizationSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/DelegatedAuthorizationSettings.java @@ -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 @@ */ public class DelegatedAuthorizationSettings { - public static final Setting> 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>> AUTHZ_REALMS = RealmSettings.affixSetting( + AUTHZ_REALMS_SUFFIX, key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(), Setting.Property.NodeScope)); - public static Collection> getSettings() { - return Collections.singleton(AUTHZ_REALMS); + public static Collection> getSettings(String realmType) { + return Collections.singleton(AUTHZ_REALMS.apply(realmType)); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/DnRoleMapperSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/DnRoleMapperSettings.java index 034f7a18dbee4..d2e22a7049110 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/DnRoleMapperSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/DnRoleMapperSettings.java @@ -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 ROLE_MAPPING_FILE_SETTING = new Setting<>("files.role_mapping", DEFAULT_FILE_NAME, - Function.identity(), Setting.Property.NodeScope); - public static final Setting 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> 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> 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> 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> getSettings(String realmType) { + return Arrays.asList(USE_UNMAPPED_GROUPS_AS_ROLES_SETTING.apply(realmType), ROLE_MAPPING_FILE_SETTING.apply(realmType)); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/mapper/CompositeRoleMapperSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/mapper/CompositeRoleMapperSettings.java index 54fa0c2ffbcd9..ee719580893f3 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/mapper/CompositeRoleMapperSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/mapper/CompositeRoleMapperSettings.java @@ -13,7 +13,7 @@ public final class CompositeRoleMapperSettings { private CompositeRoleMapperSettings() {} - public static Collection> getSettings() { - return DnRoleMapperSettings.getSettings(); + public static Collection> getSettings(String type) { + return DnRoleMapperSettings.getSettings(type); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLConfigurationSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLConfigurationSettings.java index 0cc01270ced53..c16035f1cabe3 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLConfigurationSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLConfigurationSettings.java @@ -13,7 +13,6 @@ 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>> CIPHERS_SETTING_TEMPLATE = key -> Setting.listSetting(key, Collections .emptyList(), Function.identity(), Property.NodeScope, Property.Filtered); - public static final Setting> CIPHERS_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.", + public static final Setting> CIPHERS_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.cipher_suites", CIPHERS_SETTING_TEMPLATE); + public static final Function>> CIPHERS_SETTING_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.cipher_suites", CIPHERS_SETTING_TEMPLATE); - private static final Function>> SUPPORTED_PROTOCOLS_TEMPLATE = key -> Setting.listSetting(key, + private static final Function>> SUPPORTED_PROTOCOLS_TEMPLATE = key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(), Property.NodeScope, Property.Filtered); public static final Setting> 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>> SUPPORTED_PROTOCOLS_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.supported_protocols", + SUPPORTED_PROTOCOLS_TEMPLATE); - public static final Setting> KEYSTORE_PATH_PROFILES = Setting.affixKeySetting("transport.profiles.", + static final Setting> KEYSTORE_PATH_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.keystore.path", X509KeyPairSettings.KEYSTORE_PATH_TEMPLATE); + static final Function>> KEYSTORE_PATH_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.path", + X509KeyPairSettings.KEYSTORE_PATH_TEMPLATE); public static final Setting LEGACY_KEYSTORE_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.keystore.password", X509KeyPairSettings.LEGACY_KEYSTORE_PASSWORD_TEMPLATE); + public static final Function> LEGACY_KEYSTORE_PASSWORD_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.password", + X509KeyPairSettings.LEGACY_KEYSTORE_PASSWORD_TEMPLATE); public static final Setting KEYSTORE_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.keystore.secure_password", X509KeyPairSettings.KEYSTORE_PASSWORD_TEMPLATE); + public static final Function> KEYSTORE_PASSWORD_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.secure_password", + X509KeyPairSettings.KEYSTORE_PASSWORD_TEMPLATE); public static final Setting 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> 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 KEYSTORE_KEY_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.keystore.secure_key_password", X509KeyPairSettings.KEYSTORE_KEY_PASSWORD_TEMPLATE); + public static final Function> 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>> TRUST_STORE_PATH_TEMPLATE = key -> new Setting<>(key, s -> null, + public static final Function>> TRUST_STORE_PATH_TEMPLATE = key -> new Setting<>(key, s -> null, Optional::ofNullable, Property.NodeScope, Property.Filtered); public static final Setting> TRUST_STORE_PATH_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.truststore.path", TRUST_STORE_PATH_TEMPLATE); + public static final Function>> TRUST_STORE_PATH_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.truststore.path", TRUST_STORE_PATH_TEMPLATE); public static final Setting> KEY_PATH_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.key", X509KeyPairSettings.KEY_PATH_TEMPLATE); + public static final Function>> KEY_PATH_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.key", X509KeyPairSettings.KEY_PATH_TEMPLATE); - private static final Function> LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE = key -> + public static final Function> LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE = key -> new Setting<>(key, "", SecureString::new, Property.Deprecated, Property.Filtered, Property.NodeScope); public static final Setting LEGACY_TRUSTSTORE_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.truststore.password", LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE); + public static final Function> LEGACY_TRUST_STORE_PASSWORD_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "truststore.password", + LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE); - private static final Function> TRUSTSTORE_PASSWORD_TEMPLATE = key -> + public static final Function> TRUSTSTORE_PASSWORD_TEMPLATE = key -> SecureSetting.secureString(key, LEGACY_TRUSTSTORE_PASSWORD_TEMPLATE.apply(key.replace("truststore.secure_password", "truststore.password"))); public static final Setting TRUSTSTORE_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.truststore.secure_password", TRUSTSTORE_PASSWORD_TEMPLATE); + public static final Function> TRUST_STORE_PASSWORD_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.truststore.secure_password", + TRUSTSTORE_PASSWORD_TEMPLATE); public static final Setting KEY_STORE_ALGORITHM_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.keystore.algorithm", X509KeyPairSettings.KEY_STORE_ALGORITHM_TEMPLATE); + public static final Function> KEY_STORE_ALGORITHM_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.algorithm", + X509KeyPairSettings.KEY_STORE_ALGORITHM_TEMPLATE); - private static final Function> TRUST_STORE_ALGORITHM_TEMPLATE = key -> + public static final Function> TRUST_STORE_ALGORITHM_TEMPLATE = key -> new Setting<>(key, s -> TrustManagerFactory.getDefaultAlgorithm(), Function.identity(), Property.NodeScope, Property.Filtered); public static final Setting TRUST_STORE_ALGORITHM_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.truststore.algorithm", TRUST_STORE_ALGORITHM_TEMPLATE); + public static final Function> TRUST_STORE_ALGORITHM_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.truststore.algorithm", + TRUST_STORE_ALGORITHM_TEMPLATE); public static final Setting> KEY_STORE_TYPE_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.keystore.type", X509KeyPairSettings.KEY_STORE_TYPE_TEMPLATE); + public static final Function>> KEY_STORE_TYPE_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.keystore.type", + X509KeyPairSettings.KEY_STORE_TYPE_TEMPLATE); - private static final Function>> TRUST_STORE_TYPE_TEMPLATE = + public static final Function>> TRUST_STORE_TYPE_TEMPLATE = X509KeyPairSettings.KEY_STORE_TYPE_TEMPLATE; public static final Setting> TRUST_STORE_TYPE_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.truststore.type", TRUST_STORE_TYPE_TEMPLATE); + public static final Function>> TRUST_STORE_TYPE_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.truststore.type", TRUST_STORE_TYPE_TEMPLATE); private static final Function>> TRUST_RESTRICTIONS_TEMPLATE = key -> new Setting<>(key, s -> null, Optional::ofNullable, Property.NodeScope, Property.Filtered); public static final Setting> TRUST_RESTRICTIONS_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.trust_restrictions", TRUST_RESTRICTIONS_TEMPLATE); + public static final Function>> TRUST_RESTRICTIONS_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.trust_restrictions", + TRUST_RESTRICTIONS_TEMPLATE); public static final Setting LEGACY_KEY_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.key_passphrase", X509KeyPairSettings.LEGACY_KEY_PASSWORD_TEMPLATE); + public static final Function> LEGACY_KEY_PASSWORD_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.key_passphrase", + X509KeyPairSettings.LEGACY_KEY_PASSWORD_TEMPLATE); public static final Setting KEY_PASSWORD_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.secure_key_passphrase", X509KeyPairSettings.KEY_PASSWORD_TEMPLATE); + public static final Function> KEY_PASSWORD_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.secure_key_passphrase", + X509KeyPairSettings.KEY_PASSWORD_TEMPLATE); public static final Setting> CERT_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.certificate", X509KeyPairSettings.CERT_TEMPLATE); + public static final Function>> CERT_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.certificate", + X509KeyPairSettings.CERT_TEMPLATE); - private static final Function>> CAPATH_SETTING_TEMPLATE = key -> Setting.listSetting(key, Collections + public static final Function>> CAPATH_SETTING_TEMPLATE = key -> Setting.listSetting(key, Collections .emptyList(), Function.identity(), Property.NodeScope, Property.Filtered); - public static final Setting> CAPATH_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.", + public static final Setting> CAPATH_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.certificate_authorities", CAPATH_SETTING_TEMPLATE); + public static final Function>> CAPATH_SETTING_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.certificate_authorities", + CAPATH_SETTING_TEMPLATE); private static final Function>> 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> CLIENT_AUTH_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.", + public static final Setting> CLIENT_AUTH_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.client_authentication", CLIENT_AUTH_SETTING_TEMPLATE); + public static final Function>> CLIENT_AUTH_SETTING_REALM = realmType -> + Setting.affixKeySetting("xpack.security.authc.realms." + realmType + ".", "ssl.client_authentication", + CLIENT_AUTH_SETTING_TEMPLATE); private static final Function>> 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> VERIFICATION_MODE_SETTING_PROFILES = Setting.affixKeySetting( "transport.profiles.", "xpack.security.ssl.verification_mode", VERIFICATION_MODE_SETTING_TEMPLATE); + public static final Function>> 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 ("") or a string * ending in "." + * @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 static SSLConfigurationSettings withoutPrefix() { /** * 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 Settings. + * * @param prefix A string that must end in "ssl." */ public static SSLConfigurationSettings withPrefix(String prefix) { @@ -212,17 +274,27 @@ public static SSLConfigurationSettings withPrefix(String prefix) { return new SSLConfigurationSettings(prefix); } - public static Collection> 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> 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> getSecureSettingsInUse(Settings settings) { return Stream.of(this.truststorePassword, this.x509KeyPair.keystorePassword, this.x509KeyPair.keystoreKeyPassword, this.x509KeyPair.keyPassword) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLService.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLService.java index 752d5aef3caae..428daf56059ca 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLService.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLService.java @@ -17,7 +17,6 @@ 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 @@ SSLParameters sslParameters(SSLContext sslContext) { * 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 SSLSocketFactory sslSocketFactory(SSLConfiguration configuration) { * 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 SSLEngine createSSLEngine(SSLConfiguration configuration, String host, in /** * 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 @@ SSLContext sslContext(SSLConfiguration configuration) { /** * Returns the existing {@link SSLContextHolder} for the configuration + * * @throws IllegalArgumentException if not found */ SSLContextHolder sslContextHolder(SSLConfiguration sslConfiguration) { @@ -287,6 +289,7 @@ SSLContextHolder sslContextHolder(SSLConfiguration sslConfiguration) { /** * 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 @@ Collection getLoadedSSLConfigurations() { /** * 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 requestedCiphers, boolean log) { @@ -351,6 +355,7 @@ String[] supportedCiphers(String[] supportedCiphers, List requestedCiphe /** * 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 @@ private SSLContextHolder createSslContext(SSLConfiguration sslConfiguration) { /** * 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 @@ private SSLContextHolder createSslContext(X509ExtendedKeyManager keyManager, X50 // 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 @@ private void storeSslConfiguration(String key, SSLConfiguration configuration) { * 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 getLoadedCertificates() throws GeneralSecurityException, IOException { @@ -499,14 +506,14 @@ public Socket createSocket(String host, int port) throws IOException { @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 @@ static void invalidateSessions(SSLSessionContext sslSessionContext) { * @return A map of Settings prefix to Settings object */ private static Map getRealmsSSLSettings(Settings settings) { - Map 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 sslSettings = new HashMap<>(); + final String prefix = "xpack.security.authc.realms."; + final Map 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; } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/X509KeyPairSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/X509KeyPairSettings.java index 33b78b2da8609..bf2209f213cd4 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/X509KeyPairSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/X509KeyPairSettings.java @@ -11,13 +11,13 @@ 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> keystorePath; final Setting keystorePassword; @@ -83,21 +81,24 @@ public class X509KeyPairSettings { private final List> 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 { + Setting apply(String keyPart, Function> template); + } + + 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); - keyPath = KEY_PATH_TEMPLATE.apply(prefix + "key"); - keyPassword = KEY_PASSWORD_TEMPLATE.apply(prefix + "secure_key_passphrase"); - certificatePath = CERT_TEMPLATE.apply(prefix + "certificate"); + keyPath = factory.apply("key", KEY_PATH_TEMPLATE); + keyPassword = factory.apply("secure_key_passphrase", KEY_PASSWORD_TEMPLATE); + certificatePath = factory.apply("certificate", CERT_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; + 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> settings = CollectionUtils.arrayAsArrayList( keystorePath, keystorePassword, keystoreAlgorithm, keystoreType, keystoreKeyPassword, @@ -110,12 +111,26 @@ public X509KeyPairSettings(String prefix, boolean acceptNonSecurePasswords) { allSettings = Collections.unmodifiableList(settings); } + public static X509KeyPairSettings withPrefix(String prefix, boolean acceptNonSecurePasswords) { + return new X509KeyPairSettings(acceptNonSecurePasswords, new SettingFactory() { + @Override + public Setting apply(String key, Function> template) { + return template.apply(prefix + key); + } + }); + } - public Collection> getAllSettings() { - return allSettings; + public static Collection> affix(String prefix, String suffixPart, boolean acceptNonSecurePasswords) { + final X509KeyPairSettings settings = new X509KeyPairSettings(acceptNonSecurePasswords, new SettingFactory() { + @Override + public Setting apply(String keyPart, Function> template) { + return Setting.affixKeySetting(prefix, suffixPart + keyPart, template); + } + }); + return settings.getAllSettings().stream().map(s -> (Setting.AffixSetting) s).collect(Collectors.toList()); } - public String getPrefix() { - return prefix; + public Collection> getAllSettings() { + return allSettings; } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ssl/SSLServiceTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ssl/SSLServiceTests.java index 88d10071e8543..545a8f91574a7 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ssl/SSLServiceTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ssl/SSLServiceTests.java @@ -496,8 +496,8 @@ public void testGetConfigurationByContextName() throws Exception { "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 void testGetConfigurationByContextName() throws Exception { 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 void testGetConfigurationByContextName() throws Exception { // 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 void testReadCertificateInformation() throws Exception { .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(); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheck.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheck.java index fc5962d705c94..b3a653c044de4 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheck.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheck.java @@ -9,6 +9,7 @@ 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 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 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)) { diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java index b0c1acba7e215..ae0b34dde8cdc 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -113,8 +113,8 @@ 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 static List> getSettings(boolean transportClientMode, List getRestHeaders() { public List getSettingsFilter() { List asArray = settings.getAsList(SecurityField.setting("hide_settings")); ArrayList 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; diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalRealms.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalRealms.java index d568a052a5e15..7cd4fa96aa4a3 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalRealms.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalRealms.java @@ -33,12 +33,13 @@ 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 static Map getFactories(ThreadPool threadPool, Res 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 @@ private InternalRealms() { } public static List getBootstrapChecks(final Settings globalSettings, final Environment env) { - final List checks = new ArrayList<>(); - final Map 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 realmTypes = Sets.newHashSet(LdapRealmSettings.AD_TYPE, LdapRealmSettings.LDAP_TYPE, PkiRealmSettings.TYPE); + final List 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; } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Realms.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Realms.java index 53f36f6417a52..925654fae8bbf 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Realms.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Realms.java @@ -22,6 +22,7 @@ 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.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 Realm.Factory realmFactory(String type) { } protected List initRealms() throws Exception { - Settings realmsSettings = RealmSettings.get(settings); + Map realmsSettings = RealmSettings.getRealmSettings(settings); Set internalTypes = new HashSet<>(); List realms = new ArrayList<>(); List 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 void usageStats(ActionListener> listener) { private void addNativeRealms(List 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))); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealm.java index a84b76beab8bb..53e171ff4f321 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealm.java @@ -9,7 +9,6 @@ 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; } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java index 2cf548eb4e1a9..a2d172215921b 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java @@ -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; diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/file/FileRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/file/FileRealm.java index e2586ea836dec..884cd5dbafb10 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/file/FileRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/file/FileRealm.java @@ -10,7 +10,6 @@ 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 FileRealm(RealmConfig config, ResourceWatcherService watcherService, Thre // 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; diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealm.java index 0f47b6032f5ab..56c65574980db 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealm.java @@ -79,22 +79,22 @@ public KerberosRealm(final RealmConfig config, final NativeRoleMappingStore nati KerberosRealm(final RealmConfig config, final NativeRoleMappingStore nativeRoleMappingStore, final KerberosTicketValidator kerberosTicketValidator, final ThreadPool threadPool, final Cache 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.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 KerberosRealm(final RealmConfig config, final NativeRoleMappingStore nati 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; } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolver.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolver.java index 8e009154cad12..a8bf30fa71357 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolver.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolver.java @@ -13,8 +13,10 @@ 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.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 diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java index 8107d7488188b..da258a99d0cb4 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java @@ -22,7 +22,7 @@ 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 getDefaultLdapUrls(Settings settings) { - return Collections.singletonList("ldap://" + settings.get(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING) + - ":" + ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING.get(settings)); + protected List 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 @@ void getUnauthenticatedSessionWithPool(LDAPConnectionPool connectionPool, String @Override void getUnauthenticatedSessionWithoutPool(String user, ActionListener listener) { - if (PoolingSessionFactorySettings.BIND_DN.exists(config.settings()) == false) { + if (config.hasSetting(PoolingSessionFactorySettings.BIND_DN) == false) { listener.onResponse(null); return; } @@ -188,10 +188,10 @@ static String buildDnFromDomain(String domain) { 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 @@ abstract static class ADAuthenticator { 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 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 listener) { @@ -324,7 +324,8 @@ static class DefaultADAuthenticator extends ADAuthenticator { 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 @@ static class DefaultADAuthenticator extends ADAuthenticator { } 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 @@ static class DownLevelADAuthenticator extends ADAuthenticator { Cache domainNameCache = CacheBuilder.builder().setMaximumWeight(100).build(); final String domainDN; - final Settings settings; final SSLService sslService; final RealmConfig config; private final int ldapPort; @@ -372,12 +372,12 @@ static class DownLevelADAuthenticator extends ADAuthenticator { 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 @@ protected void doRun() throws Exception { public void onFailure(Exception e) { IOUtils.closeWhileHandlingException(searchConnection); listener.onFailure(e); - }; + } }); } } catch (LDAPException e) { @@ -519,7 +519,7 @@ static class UpnADAuthenticator extends ADAuthenticator { 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}")) { diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealm.java index 193b33b7d8fe9..d9245e4e22813 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealm.java @@ -26,6 +26,7 @@ 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 @@ static SessionFactory sessionFactory(RealmConfig config, SSLService sslService, 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 void initialize(Iterable realms, XPackLicenseState licenseState) { public void usageStats(ActionListener> 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); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactory.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactory.java index 464a0cfc61cf8..df9a0a8326133 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactory.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactory.java @@ -8,12 +8,11 @@ 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 @@ String buildDnFromTemplate(String username, String template) { 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); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactory.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactory.java index a3541ec2759b3..64f3be516fa5d 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactory.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactory.java @@ -15,7 +15,6 @@ 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.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 @@ protected void doRun() throws Exception { /** * Sets up a LDAPSession using the following process: *

    - *
  1. Opening a new connection to the LDAP server
  2. - *
  3. Executes a bind request using the bind user
  4. - *
  5. Executes a search to find the DN of the user
  6. - *
  7. Closes the opened connection
  8. - *
  9. Opens a new connection to the LDAP server
  10. - *
  11. Executes a bind request using the found DN and provided password
  12. - *
  13. Creates a new LDAPSession with the bound connection
  14. + *
  15. Opening a new connection to the LDAP server
  16. + *
  17. Executes a bind request using the bind user
  18. + *
  19. Executes a search to find the DN of the user
  20. + *
  21. Closes the opened connection
  22. + *
  23. Opens a new connection to the LDAP server
  24. + *
  25. Executes a bind request using the found DN and provided password
  26. + *
  27. Creates a new LDAPSession with the bound connection
  28. *
*/ @Override @@ -151,6 +152,7 @@ public void onFailure(Exception e) { listener.onFailure(e); })); } + @Override public void onFailure(Exception e) { IOUtils.closeWhileHandlingException(connection); @@ -227,17 +229,16 @@ private void findUser(String user, LDAPInterface ldapInterface, ActionListener poolingEnabled, @Nullable String bindDn, Supplier healthCheckDNSupplier, + Setting.AffixSetting poolingEnabled, @Nullable String bindDn, Supplier 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 void getSessionWithPool(LDAPConnectionPool connectionPool, String user, static LDAPConnectionPool createConnectionPool(RealmConfig config, ServerSet serverSet, TimeValue timeout, Logger logger, BindRequest bindRequest, Supplier 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 diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolver.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolver.java index c641be947d8dd..7e7fcf319a083 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolver.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolver.java @@ -14,8 +14,8 @@ 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.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 diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/UserAttributeGroupsResolver.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/UserAttributeGroupsResolver.java index 6f5393d591e02..d2b2a346a9588 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/UserAttributeGroupsResolver.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/UserAttributeGroupsResolver.java @@ -10,8 +10,8 @@ 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.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) { diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapLoadBalancing.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapLoadBalancing.java index 3ac40eb374aef..287b67b21d3a1 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapLoadBalancing.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapLoadBalancing.java @@ -11,9 +11,11 @@ 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 @@ ServerSet buildServerSet(String[] addresses, int[] ports, Settings settings, @Nu 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 @@ ServerSet buildServerSet(String[] addresses, int[] ports, Settings settings, @Nu 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 @@ ServerSet buildServerSet(String[] addresses, int[] ports, Settings settings, @Nu 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 @@ ServerSet buildServerSet(String[] addresses, int[] ports, Settings settings, @Nu 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 @@ ServerSet buildServerSet(String[] addresses, int[] ports, Settings settings, @Nu 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 String toString() { 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); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapMetaDataResolver.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapMetaDataResolver.java index e957c29fe2ba2..ad5aa7927b68c 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapMetaDataResolver.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapMetaDataResolver.java @@ -5,24 +5,24 @@ */ package org.elasticsearch.xpack.security.authc.ldap.support; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -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.RealmConfig; 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.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + 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 attributeNames, boolean ignoreReferralErrors) { diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapUtils.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapUtils.java index d2d87db683ca3..0d6a94037ab18 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapUtils.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapUtils.java @@ -26,7 +26,6 @@ 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.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; diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java index 78f8c68f12459..193254c7a3963 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java @@ -16,7 +16,6 @@ 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 @@ protected SessionFactory(RealmConfig config, SSLService sslService, ThreadPool t 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 void unauthenticatedSession(String username, ActionListener 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 @@ protected static LDAPConnectionOptions connectionOptions(RealmConfig config, 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 @@ protected static LDAPConnectionOptions connectionOptions(RealmConfig config, return options; } - private LDAPServers ldapServers(Settings settings) { + private LDAPServers ldapServers(RealmConfig config) { // Parse LDAP urls - List ldapUrls = settings.getAsList(SessionFactorySettings.URLS_SETTING, getDefaultLdapUrls(settings)); + List 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 getDefaultLdapUrls(Settings settings) { + protected List 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 @@ private boolean secureUrls(String[] ldapUrls) { //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; diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java index 4d13f332ffe20..942e328824fc3 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java @@ -15,7 +15,6 @@ 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.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 X509AuthenticationToken token(ThreadContext context) { @Override public void authenticate(AuthenticationToken authToken, ActionListener 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 @@ static boolean isCertificateChainTrusted(X509TrustManager trustManager, X509Auth return true; } - static X509TrustManager trustManagers(RealmConfig realmConfig) { - final Settings settings = realmConfig.settings(); - final Environment env = realmConfig.env(); - List 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 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; + } + 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 trustManagersFromCAs(settings, env); + 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 @@ private static X509TrustManager trustManagersFromTruststore(String truststorePat } } - private static X509TrustManager trustManagersFromCAs(Settings settings, Environment env) { - List certificateAuthorities = settings.getAsList(PkiRealmSettings.SSL_SETTINGS.caPaths.getKey(), null); + private static X509TrustManager trustManagersFromCAs(List certificateAuthorities, Environment env) { assert certificateAuthorities != null; try { Certificate[] certificates = CertParsingUtils.readCertificates(certificateAuthorities, env); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlMetadataCommand.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlMetadataCommand.java index 2a77508ac446c..f5935b4477c76 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlMetadataCommand.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlMetadataCommand.java @@ -66,8 +66,6 @@ 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 @@ EntityDescriptor buildEntityDescriptor(Terminal terminal, OptionSet options, Env 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 @@ EntityDescriptor buildEntityDescriptor(Terminal terminal, OptionSet options, Env .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 attributes = getAttributeNames(options, realm); @@ -399,7 +398,8 @@ private Map getAttributeNames(OptionSet options, RealmConfig rea 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 @@ private SortedSet sorted(Set strings) { 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 @@ private RealmConfig findRealm(Terminal terminal, OptionSet options, Environment settings = env.settings(); } - final Map realms = RealmSettings.getRealmSettings(settings); + final Map 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> saml = realms.entrySet().stream() - .filter(entry -> isSamlRealm(getRealmType(entry.getValue()))) + final List> 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 entry = saml.get(0); + final Map.Entry 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 @@ private String optionName(OptionSpec spec) { 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) { diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlRealm.java index 7c982e6b1b396..b2a1001aef9c6 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlRealm.java @@ -28,7 +28,6 @@ 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.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 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.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 static SamlRealm create(RealmConfig config, SSLService sslService, Resour 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 static SamlRealm create(RealmConfig config, SSLService sslService, Resour // For testing SamlRealm(RealmConfig config, UserRoleMapper roleMapper, SamlAuthenticator authenticator, SamlLogoutRequestHandler logoutHandler, Supplier idpDescriptor, SpConfiguration spConfiguration) throws Exception { - super(TYPE, config); + super(config); this.roleMapper = roleMapper; this.authenticator = authenticator; @@ -222,10 +219,10 @@ public static SamlRealm create(RealmConfig config, SSLService sslService, Resour 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 void initialize(Iterable realms, XPackLicenseState licenseState) { delegatedRealms = new DelegatedAuthorizationSupport(realms, config, licenseState); } - static String require(RealmConfig config, Setting setting) { - final String value = setting.get(config.settings()); + static String require(RealmConfig config, Setting.AffixSetting 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 @@ private static IdpConfiguration getIdpConfiguration(RealmConfig config, Metadata 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 reqAuthnCtxClassRef = REQUESTED_AUTHN_CONTEXT_CLASS_REF.get(config.settings()); + final String logoutUrl = config.getSetting(SP_LOGOUT); + final List reqAuthnCtxClassRef = config.getSetting(REQUESTED_AUTHN_CONTEXT_CLASS_REF); return new SpConfiguration(serviceProviderId, assertionConsumerServiceURL, logoutUrl, buildSigningConfiguration(config), buildEncryptionCredential(config), reqAuthnCtxClassRef); } @@ -296,35 +293,37 @@ static SpConfiguration getSpConfiguration(RealmConfig config) throws IOException // Package-private for testing static List 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 credentials = buildCredential(config, SIGNING_SETTINGS, SIGNING_KEY_ALIAS, false); - + final List 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 types = SIGNING_MESSAGE_TYPES.get(config.settings()); + final List types = config.getSetting(SIGNING_MESSAGE_TYPES); return new SigningConfiguration(Sets.newHashSet(types), credentials.get(0)); } } - private static List buildCredential(RealmConfig config, X509KeyPairSettings keyPairSettings, - Setting aliasSetting, final boolean allowMultiple) { - final X509KeyManager keyManager = CertParsingUtils.getKeyManager(keyPairSettings, config.settings(), null, config.env()); - + private static List buildCredential(RealmConfig config, String prefix, Setting.AffixSetting 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 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 @@ private static List buildCredential(RealmConfig config, X509KeyP 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 @@ private static List buildCredential(RealmConfig config, X509KeyP 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 void authenticate(AuthenticationToken authenticationToken, ActionListener } private void buildUser(SamlAttributes attributes, ActionListener 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 @@ private void buildUser(SamlAttributes attributes, ActionListener 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 @@ private static Tuple attributes.getAttributeValues(attributeName).stream().map(s -> { final Matcher matcher = regex.matcher(s); if (matcher.find() == false) { @@ -768,17 +767,19 @@ static AttributeParser forSetting(Logger logger, SamlRealmSettings.AttributeSett ); } 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()); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealm.java index fdb2fd0f33db8..3924370fb33ec 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealm.java @@ -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.>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 boolean supports(AuthenticationToken token) { * 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 listener) { diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupport.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupport.java index 55266d9143774..8ce2805d23059 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupport.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupport.java @@ -10,6 +10,7 @@ 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.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 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 boolean hasDelegation() { public void resolve(String username, ActionListener 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> userListener = ActionListener.wrap(tuple -> { @@ -123,13 +123,12 @@ private List resolveRealms(Iterable allRealms, List delegatedRealms, Settings globalSettings) { - final Map 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> 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) + + "]"); } } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DnRoleMapper.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DnRoleMapper.java index bdabc690f76ff..78094f518c53c 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DnRoleMapper.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DnRoleMapper.java @@ -30,7 +30,6 @@ 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 @@ synchronized void addListener(Runnable listener) { 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); } /** diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/RoleMappingFileBootstrapCheck.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/RoleMappingFileBootstrapCheck.java index 81b0dc6ea4876..6a7609238b9d6 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/RoleMappingFileBootstrapCheck.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/RoleMappingFileBootstrapCheck.java @@ -43,8 +43,8 @@ public boolean alwaysEnforce() { } 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; diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/UsernamePasswordRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/UsernamePasswordRealm.java index b50cba349dc56..380515d010268 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/UsernamePasswordRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/UsernamePasswordRealm.java @@ -13,8 +13,8 @@ abstract class UsernamePasswordRealm extends Realm { - UsernamePasswordRealm(String type, RealmConfig config) { - super(type, config); + UsernamePasswordRealm(RealmConfig config) { + super(config); } @Override diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/CompositeRoleMapper.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/CompositeRoleMapper.java index 956060a65789c..1723473df05d7 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/CompositeRoleMapper.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/CompositeRoleMapper.java @@ -29,7 +29,7 @@ public class CompositeRoleMapper implements UserRoleMapper { private List delegates; - public CompositeRoleMapper(String realmType, RealmConfig realmConfig, + public CompositeRoleMapper(RealmConfig realmConfig, ResourceWatcherService watcherService, NativeRoleMappingStore nativeRoleMappingStore) { this(new DnRoleMapper(realmConfig, watcherService), nativeRoleMappingStore); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java index 6098562ec3a89..fa1cfbcba9993 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java @@ -135,10 +135,8 @@ public Settings nodeSettings(int nodeOrdinal) { .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(); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SettingsFilterTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SettingsFilterTests.java index 3bf3bb4dc8641..b4584200a4a33 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SettingsFilterTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SettingsFilterTests.java @@ -14,6 +14,7 @@ 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 void testFiltering() throws Exception { } if (useLegacyLdapBindPassword) { - assertSettingDeprecationsAndWarnings(new Setting[]{PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD}); + assertSettingDeprecationsAndWarnings(new Setting[]{PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD + .apply(LdapRealmSettings.LDAP_TYPE) + .getConcreteSettingForNamespace("ldap1")}); } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheckTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheckTests.java index 6966b7edf67d8..fdaa82c602194 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheckTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheckTests.java @@ -12,7 +12,6 @@ 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 void testPkiRealmBootstrapDefault() throws Exception { 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 @@ private BootstrapCheck.BootstrapCheckResult runCheck(Settings settings, Environm 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 void testBootstrapCheckWithClosedSecuredSetting() throws Exception { 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", diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java index 857b1694ac87a..ec0a20faf58c4 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java @@ -36,7 +36,6 @@ 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.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.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 getRealms(ResourceWatcherService resourceWatcherService) { return Collections.singletonMap(realmType, config -> null); @@ -153,7 +157,7 @@ public void testCustomRealmExtension() throws Exception { 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 void testDisabledByDefault() throws Exception { 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 components = createComponents(settings); AuditTrailService service = findComponent(AuditTrailService.class, components); assertNotNull(service); @@ -186,8 +190,8 @@ public void testIndexAuditTrail() throws Exception { 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 components = createComponents(settings); AuditTrailService service = findComponent(AuditTrailService.class, components); assertNotNull(service); @@ -198,8 +202,8 @@ public void testIndexAndLoggingAuditTrail() throws Exception { 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 void testHttpSettingDefaults() throws Exception { 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 void testTransportSettingValidation() { public void testSettingFilter() throws Exception { createComponents(Settings.EMPTY); final List 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> 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> 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 void testTLSJoinValidator() throws Exception { 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 void testIndexJoinValidator_Old_And_Rolling() throws Exception { 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 void testIndexJoinValidator_FullyCurrentCluster() throws Exception { 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 void testIndexUpgradeValidatorWithUpToDateIndex() throws Exception { 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 void testIndexUpgradeValidatorWithMissingIndex() throws Exception { 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); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java index 5edeb3d6e7e68..ea5bb6e9f97a7 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java @@ -54,6 +54,7 @@ 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.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 @@ void doExecute(Action action, Request request, ActionListener Stream.of(samlRealm)); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlLogoutActionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlLogoutActionTests.java index 88b9dd1d5e7fc..bb57b9a8583f1 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlLogoutActionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlLogoutActionTests.java @@ -45,6 +45,7 @@ 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.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 void setup() throws Exception { 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 void testLogoutInvalidatesToken() throws Exception { .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); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/InternalRealmsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/InternalRealmsTests.java index 2e91c40677ed6..7551517e23241 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/InternalRealmsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/InternalRealmsTests.java @@ -46,12 +46,12 @@ public void testNativeRealmRegistersIndexHealthChangeListener() throws Exception 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)); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java index b177d17793f89..7d7fd135349b1 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java @@ -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.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 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 void testFileRealmWithAllSettingsValidatesSuccessfully() throws Exception } 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 void testNativeRealmWithAllSettingsValidatesSuccessfully() throws Excepti } 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 void testPkiRealmWithTrustStoreValidatesSuccessfully() throws Exception { } 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 void testSettingsWithMultipleRealmsValidatesSuccessfully() throws Excepti } 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 @@ private Settings.Builder ldapSettings(boolean userSearch, boolean groupSearch) { .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 @@ private Settings.Builder ldapSettings(boolean userSearch, boolean groupSearch) { } 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 @@ private Settings.Builder activeDirectorySettings(boolean configureSSL) { } 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 @@ private Settings.Builder commonLdapSettings(String type, boolean configureSSL) { } 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 @@ private Settings.Builder configureSsl(String prefix, Settings.Builder builder, b } 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 @@ private Settings.Builder configureSsl(String prefix, Settings.Builder builder, b 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 @@ private Settings.Builder configureSsl(String prefix, Settings.Builder builder, b 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 @@ private Settings.Builder baseSettings(String type, boolean withCacheSettings) { 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 @@ private MockSecureSettings normaliseSecureSettingPrefix(String prefix, SecureSet } } - 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 @@ private void assertSuccess(Settings.Builder builder) { } 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> list = new ArrayList<>(); - final List noExtensions = Collections.emptyList(); - RealmSettings.addSettings(list, noExtensions); - assertThat(list, hasSize(1)); - return list.get(0); + private void validate(Settings settings) { + final Set> settingsSet = new HashSet<>(InternalRealmsSettings.getSettings()); + final AbstractScopedSettings validator = new AbstractScopedSettings(settings, settingsSet, Collections.emptySet(), + Setting.Property.NodeScope) { + }; + validator.validate(settings, false); } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmsTests.java index c5fbb39fee627..c37d6913d1fd2 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmsTests.java @@ -83,8 +83,7 @@ public void testWithSettings() throws Exception { Collections.shuffle(orders, random()); Map 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 void testWithSettingsWhereDifferentRealmsHaveSameOrder() throws Exception TreeMap 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 void testWithSettingsWhereDifferentRealmsHaveSameOrder() throws Exception 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 void testUnlicensedWithOnlyCustomRealms() throws Exception { Collections.shuffle(orders, random()); Map 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 void testUnlicensedWithInternalRealms() throws Exception { 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 iter = realms.iterator(); assertThat(iter.hasNext(), is(true)); Realm realm = iter.next(); @@ -282,7 +275,7 @@ public void testUnlicensedWithInternalRealms() throws Exception { 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 void testUnlicensedWithInternalRealms() throws Exception { 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 void testUnlicensedWithNonStandardRealms() throws Exception { 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 void testDisabledRealmsAreNotAdded() throws Exception { Collections.shuffle(orders, random()); Map 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 void testDisabledRealmsAreNotAdded() throws Exception { } 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 iterator = realms.iterator(); Realm realm = iterator.next(); assertThat(realm, is(reservedRealm)); @@ -438,11 +427,10 @@ public void testDisabledRealmsAreNotAdded() throws Exception { 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 void testUsageStats() throws Exception { // 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 void testUsageStats() throws Exception { 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 void testInitRealmsFailsForMultipleKerberosRealms() throws IOException { static class DummyRealm extends Realm { DummyRealm(String type, RealmConfig config) { - super(type, config); + super(config); } @Override diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmTests.java index 56131c87001d1..ff632b21995af 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmTests.java @@ -32,8 +32,8 @@ public void testCacheClearOnIndexHealthChange() { 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() { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileRealmTests.java index 1310980fc5f7c..ba6f918819aa0 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileRealmTests.java @@ -15,6 +15,7 @@ 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 @@ public class FileRealmTests extends ESTestCase { + private static final RealmConfig.RealmIdentifier REALM_IDENTIFIER = new RealmConfig.RealmIdentifier("file", "file-test"); + private static final Answer VERIFY_PASSWORD_ANSWER = inv -> { assertThat(inv.getArguments().length, is(3)); Supplier supplier = (Supplier) inv.getArguments()[2]; @@ -69,8 +72,7 @@ public void testAuthenticate() throws Exception { 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 future = new PlainActionFuture<>(); realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future); @@ -84,12 +86,17 @@ public void testAuthenticate() throws Exception { 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 void testAuthenticateCaching() throws Exception { } 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 void testAuthenticateCachingRefresh() throws Exception { } 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 void testToken() throws Exception { 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 future = new PlainActionFuture<>(); @@ -182,8 +186,7 @@ public void testLookup() throws Exception { 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 future = new PlainActionFuture<>(); @@ -198,8 +201,7 @@ public void testLookupCaching() throws Exception { } 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 void testUsageStats() throws Exception { 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> future = new PlainActionFuture<>(); realm.usageStats(future); Map 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 @@ static class UserRolesStore extends FileUserRolesStore { super(config, mock(ResourceWatcherService.class)); } } + + private Settings mergeSettings(Settings local, Settings global) { + return Settings.builder().put(global).put(local).build(); + } + } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileUserPasswdStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileUserPasswdStoreTests.java index 3acb4888d7834..29ee447ebae10 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileUserPasswdStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileUserPasswdStoreTests.java @@ -76,7 +76,7 @@ public void testStore_ConfiguredWithUnreadableFile() throws Exception { 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 void testStore_AutoReload() throws Exception { 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 void testStore_AutoReload() throws Exception { 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 void testStore_AutoReload_WithParseFailures() throws Exception { .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); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileUserRolesStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileUserRolesStoreTests.java index 8e4011b1159d5..f69416f5115ae 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileUserRolesStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/file/FileUserRolesStoreTests.java @@ -78,7 +78,8 @@ public void testStore_ConfiguredWithUnreadableFile() throws Exception { .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 void testStoreAutoReload() throws Exception { .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 void testStoreAutoReloadWithParseFailure() throws Exception { .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 void testParseFileEmptyRolesDoesNotCauseNPE() throws Exception { .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)); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmAuthenticateFailedTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmAuthenticateFailedTests.java index dcb087ff147c8..cccf590a8bd4c 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmAuthenticateFailedTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmAuthenticateFailedTests.java @@ -18,10 +18,11 @@ 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.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 void testAuthenticateDifferentFailureScenarios() throws LoginException, G 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 void testAuthenticateDifferentFailureScenarios() throws LoginException, G 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); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmCacheTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmCacheTests.java index 2bef16883bbbf..c3d6c5ae07e0e 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmCacheTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmCacheTests.java @@ -15,6 +15,7 @@ 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.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 void testAuthenticateWithCache() throws LoginException, GSSException { 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 void testCacheInvalidationScenarios() throws LoginException, GSSException 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 metadata = new HashMap<>(); @@ -110,9 +109,8 @@ public void testCacheInvalidationScenarios() throws LoginException, GSSException 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 void testAuthenticateWithValidTicketSucessAuthnWithUserDetailsWhenCacheDi 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); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmSettingsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmSettingsTests.java index 55687d5188842..eb1e32037d5ef 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmSettingsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmSettingsTests.java @@ -8,7 +8,11 @@ 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 void testKerberosRealmSettings() throws IOException { 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); - - assertThat(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(settings), equalTo(keytabPathConfig)); - assertThat(KerberosRealmSettings.CACHE_TTL_SETTING.get(settings), + 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(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)); } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTestCase.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTestCase.java index 4c0b77e320abd..43e5fb216399d 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTestCase.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTestCase.java @@ -22,6 +22,7 @@ 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 @@ 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 void setup() throws Exception { 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 void shutdown() throws InterruptedException { } protected void mockKerberosTicketValidator(final byte[] decodedTicket, final Path keytabPath, final boolean krbDebug, - final Tuple value, final Exception e) { + final Tuple value, final Exception e) { assert value != null || e != null; doAnswer((i) -> { ActionListener> listener = (ActionListener>) i.getArguments()[3]; @@ -109,7 +112,7 @@ protected void assertSuccessAuthenticationResult(final User expectedUser, final final Map> 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 @@ protected KerberosRealm createKerberosRealm(final String... userForRoleMapping) } protected KerberosRealm createKerberosRealm(final List 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 userNames) { final List expectedUserNames = userNames.stream().map(this::maybeRemoveRealmName).collect(Collectors.toList()); @@ -145,7 +156,7 @@ protected NativeRoleMappingStore roleMappingStore(final List userNames) 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 @@ protected String randomPrincipalName() { * @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 static Path writeKeyTab(final Path keytabPath, final String content) thro * @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(); } + } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTests.java index 3c7c3d3473f76..8d6869404bbaf 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTests.java @@ -15,16 +15,17 @@ 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.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 void testAuthenticateWithValidTicketSucessAuthnWithUserDetails() throws L 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 void testFailedAuthorization() throws LoginException, GSSException { 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 future = new PlainActionFuture<>(); @@ -160,9 +160,10 @@ public void testKerberosRealmThrowsErrorWhenKeytabFileHasNoReadPermissions() thr } 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 @@ private void assertKerberosRealmConstructorFails(final String keytabPath, final 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 void testDelegatedAuthorization() throws Exception { 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); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java index 2f5147ca2b17d..9fa731138b355 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java @@ -33,11 +33,13 @@ 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.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 @@ 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 boolean enableWarningsCheck() { * 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 future = new PlainActionFuture<>(); @@ -180,11 +183,12 @@ public void testAuthenticateUserPrincipleName() throws Exception { } 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 @@ protected String[] ldapUrls() throws LDAPException { } 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 void testAuthenticateCachesSuccessfulAuthentications() throws Exception { } 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 void testAuthenticateCachingCanBeDisabled() throws Exception { } 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 void testUnauthenticatedLookupWithoutConnectionPool() throws Exception { } 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 future = new PlainActionFuture<>(); @@ -308,13 +319,14 @@ private void doUnauthenticatedLookup(boolean pooled) throws Exception { } 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 future = new PlainActionFuture<>(); @@ -325,13 +337,14 @@ public void testRealmMapsGroupsToRoles() throws Exception { } 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 future = new PlainActionFuture<>(); @@ -342,15 +355,16 @@ public void testRealmMapsUsersToRoles() throws Exception { } 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> future = new PlainActionFuture<>(); @@ -365,8 +379,9 @@ public void testRealmUsageStats() throws Exception { } 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 void testDefaultSearchFilters() throws Exception { } 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 @@ private void assertSingleLdapServer(ActiveDirectorySessionFactory sessionFactory 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(); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java index 23010e400a52b..a4557171fe48b 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java @@ -10,7 +10,11 @@ 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(); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealmTests.java index fb20527575df9..3e63fe1f870f1 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealmTests.java @@ -9,7 +9,9 @@ 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.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.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 void testAuthenticateSubTreeGroupSearch() throws Exception { 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 void testAuthenticateSubTreeGroupSearch() throws Exception { 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 future = new PlainActionFuture<>(); @@ -150,13 +160,12 @@ public void testAuthenticateCaching() throws Exception { 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 future = new PlainActionFuture<>(); @@ -177,13 +186,12 @@ public void testAuthenticateCachingRefresh() throws Exception { 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 future = new PlainActionFuture<>(); @@ -211,15 +219,14 @@ public void testAuthenticateNoncaching() throws Exception { 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 future = new PlainActionFuture<>(); @@ -238,23 +245,23 @@ public void testDelegatedAuthorization() throws Exception { 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 void testDelegatedAuthorization() throws Exception { } 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 void testLdapRealmMapsUserDNToRole() throws Exception { 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 void testLdapConnectionFailureIsTreatedAsAuthenticationFailure() throws E 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 void testLdapConnectionFailureIsTreatedAsAuthenticationFailure() throws E } 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> future = new PlainActionFuture<>(); realm.usageStats(future); Map 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> settingFactory, + RealmConfig.RealmIdentifier identifier, String value) { + final MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString(getFullSettingKey(identifier, settingFactory), value); + return secureSettings; + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactoryTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactoryTests.java index a22cc9fba1779..e484af1b272a7 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactoryTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactoryTests.java @@ -9,7 +9,6 @@ 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.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 void testBindWithReadTimeout() throws Exception { 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 void testBindWithReadTimeout() throws Exception { 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 void testBindWithTemplates() throws Exception { 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 void testBindWithBogusTemplates() throws Exception { 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 void testGroupLookupSubtree() throws Exception { 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 void testGroupLookupOneLevel() throws Exception { 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); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapTestUtils.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapTestUtils.java index 966f2e3f5492d..c91f634c1a786 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapTestUtils.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapTestUtils.java @@ -36,18 +36,18 @@ public static LDAPConnection openConnection(String url, String bindDN, String bi 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 static LDAPConnection openConnection(String url, String bindDN, String bi 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)); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java index 19b0d4e71bb8a..73e5a3f2b6656 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java @@ -41,6 +41,7 @@ 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 void testSupportsUnauthenticatedSessions() throws Exception { 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 void testSupportsUnauthenticatedSessions() throws Exception { 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 void testUserSearchSubTree() throws Exception { 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 void testUserSearchSubTree() throws Exception { sessionFactory.close(); } - assertDeprecationWarnings(useAttribute, useLegacyBindPassword); + assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword); } public void testUserSearchBaseScopeFailsWithWrongBaseDN() throws Exception { @@ -160,18 +167,18 @@ public void testUserSearchBaseScopeFailsWithWrongBaseDN() throws Exception { 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 void testUserSearchBaseScopeFailsWithWrongBaseDN() throws Exception { sessionFactory.close(); } - assertDeprecationWarnings(useAttribute, useLegacyBindPassword); + assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword); } public void testUserSearchBaseScopePassesWithCorrectBaseDN() throws Exception { @@ -194,19 +201,19 @@ public void testUserSearchBaseScopePassesWithCorrectBaseDN() throws Exception { 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 void testUserSearchBaseScopePassesWithCorrectBaseDN() throws Exception { sessionFactory.close(); } - assertDeprecationWarnings(useAttribute, useLegacyBindPassword); + assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword); } public void testUserSearchOneLevelScopeFailsWithWrongBaseDN() throws Exception { @@ -240,19 +247,20 @@ public void testUserSearchOneLevelScopeFailsWithWrongBaseDN() throws Exception { 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 void testUserSearchOneLevelScopeFailsWithWrongBaseDN() throws Exception { sessionFactory.close(); } - assertDeprecationWarnings(useAttribute, useLegacyBindPassword); + assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword); } public void testUserSearchOneLevelScopePassesWithCorrectBaseDN() throws Exception { @@ -275,19 +283,20 @@ public void testUserSearchOneLevelScopePassesWithCorrectBaseDN() throws Exceptio 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 void testUserSearchOneLevelScopePassesWithCorrectBaseDN() throws Exceptio sessionFactory.close(); } - assertDeprecationWarnings(useAttribute, useLegacyBindPassword); + assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword); } public void testUserSearchWithBadAttributeFails() throws Exception { @@ -321,18 +330,18 @@ public void testUserSearchWithBadAttributeFails() throws Exception { 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 void testUserSearchWithBadAttributeFails() throws Exception { sessionFactory.close(); } - assertDeprecationWarnings(useAttribute, useLegacyBindPassword); + assertDeprecationWarnings(config.identifier(), useAttribute, useLegacyBindPassword); } public void testUserSearchWithoutAttributePasses() throws Exception { @@ -355,12 +364,12 @@ public void testUserSearchWithoutAttributePasses() throws Exception { 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 void testUserSearchWithoutAttributePasses() throws Exception { sessionFactory.close(); } - assertDeprecationWarnings(false, useLegacyBindPassword); + assertDeprecationWarnings(config.identifier(), false, useLegacyBindPassword); } public void testConnectionPoolDefaultSettings() throws Exception { @@ -393,11 +402,11 @@ public void testConnectionPoolDefaultSettings() throws Exception { 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 void testConnectionPoolSettings() throws Exception { 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 void testConnectionPoolSettings() throws Exception { 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 void testThatEmptyBindDNWithHealthCheckEnabledDoesNotThrow() throws Excep } } - 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 void testThatEmptyBindDNAndDisabledPoolingDoesNotThrow() throws Exception } } - assertDeprecationWarnings(false, true); + assertDeprecationWarnings(config.identifier(), false, true); } public void testEmptyBindDNReturnsAnonymousBindRequest() throws LDAPException { @@ -496,15 +503,16 @@ public void testEmptyBindDNReturnsAnonymousBindRequest() throws LDAPException { 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 void testThatBindRequestReturnsSimpleBindRequest() throws LDAPException { 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 void testThatConnectErrorIsNotThrownOnConstruction() throws Exception { 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 void testThatConnectErrorIsNotThrownOnConstruction() throws Exception { } } - 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> 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 @@ private void assertDeprecationWarnings(boolean useAttribute, boolean legacyBindP 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; } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolverInMemoryTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolverInMemoryTests.java index 122b486130e7c..a1bd0d59d6f89 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolverInMemoryTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolverInMemoryTests.java @@ -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 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 @@ 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 void testSearchTimeoutIsFailure() throws Exception { 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> future = new PlainActionFuture<>(); resolver.resolve(connection, WILLIAM_BUSH, TimeValue.timeValueSeconds(30), logger, null, future); @@ -74,8 +81,8 @@ public void testResolveWithDefaultUserAttribute() throws Exception { 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 groups = resolveGroups(settings, WILLIAM_BUSH); @@ -90,8 +97,8 @@ public void testResolveWithExplicitDnAttribute() throws Exception { 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 groups = resolveGroups(settings, WILLIAM_BUSH); @@ -106,8 +113,8 @@ public void testResolveWithMissingAttribute() throws Exception { 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 groups = resolveGroups(settings, WILLIAM_BUSH); @@ -122,13 +129,13 @@ public void testSearchWithConnectionPoolForOneResult() throws Exception { 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> future = new PlainActionFuture<>(); resolver.resolve(pool, "cn=Moultrie Crystal,ou=people,o=sevenSeas", @@ -150,10 +157,17 @@ private void connect(LDAPConnectionOptions options) throws LDAPException { } private List resolveGroups(Settings settings, String userDn) { - final SearchGroupsResolver resolver = new SearchGroupsResolver(settings); + final SearchGroupsResolver resolver = new SearchGroupsResolver(getConfig(settings)); final PlainActionFuture> 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)); + } + } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapLoadBalancingTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapLoadBalancingTests.java index 00e111fa9d8f6..f0420339dc75c 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapLoadBalancingTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapLoadBalancingTests.java @@ -10,61 +10,72 @@ 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 void testDnsFailoverBadArgs() { } 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)); + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapMetaDataResolverTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapMetaDataResolverTests.java index 74502b4e2b33b..bb54d6972bfe6 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapMetaDataResolverTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapMetaDataResolverTests.java @@ -5,17 +5,23 @@ */ package org.elasticsearch.xpack.security.authc.ldap.support; -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.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 static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.contains; @@ -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")); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java index 38f5c7871dc2b..cf3840fb4ce99 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java @@ -13,7 +13,6 @@ 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.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.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 @@ protected String[] ldapUrls() throws LDAPException { } 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 static Settings buildLdapSettings(String[] ldapUrl, String[] userTemplate 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 Void run() { 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 Void run() { } }); } + + 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(); + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java index f8bfa241736b9..11d1e4889b823 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java @@ -237,8 +237,8 @@ private TestSessionFactory createSessionFactory(LdapLoadBalancing loadBalancing) 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); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryTests.java index 6540be6a5eb14..eb91fe04e057b 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryTests.java @@ -19,15 +19,16 @@ 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.SessionFactorySettings; +import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings; import org.elasticsearch.xpack.core.ssl.SSLService; import org.elasticsearch.xpack.core.ssl.VerificationMode; import org.junit.After; import org.junit.Before; -import java.util.function.Function; +import java.nio.file.Path; +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; @@ -49,8 +50,8 @@ public void shutdown() throws InterruptedException { public void testConnectionFactoryReturnsCorrectLDAPConnectionOptionsWithDefaultSettings() throws Exception { final Environment environment = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build()); - RealmConfig realmConfig = new RealmConfig("conn settings", Settings.EMPTY, environment.settings(), environment, - new ThreadContext(Settings.EMPTY)); + RealmConfig realmConfig = new RealmConfig(new RealmConfig.RealmIdentifier("ldap", "conn_settings"), + environment.settings(), environment, new ThreadContext(Settings.EMPTY)); LDAPConnectionOptions options = SessionFactory.connectionOptions(realmConfig, new SSLService(environment.settings(), environment), logger); assertThat(options.followReferrals(), is(equalTo(true))); @@ -61,49 +62,52 @@ public void testConnectionFactoryReturnsCorrectLDAPConnectionOptionsWithDefaultS } public void testConnectionFactoryReturnsCorrectLDAPConnectionOptions() throws Exception { + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "conn_settings"); + final Path pathHome = createTempDir(); Settings settings = Settings.builder() - .put(SessionFactorySettings.TIMEOUT_TCP_CONNECTION_SETTING, "10ms") - .put(SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING, "false") - .put(SessionFactorySettings.TIMEOUT_TCP_READ_SETTING, "20ms") - .put(SessionFactorySettings.FOLLOW_REFERRALS_SETTING, "false") + .put(getFullSettingKey(realmId, SessionFactorySettings.TIMEOUT_TCP_CONNECTION_SETTING), "10ms") + .put(getFullSettingKey(realmId, SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING), "false") + .put(getFullSettingKey(realmId, SessionFactorySettings.TIMEOUT_TCP_READ_SETTING), "20ms") + .put(getFullSettingKey(realmId, SessionFactorySettings.FOLLOW_REFERRALS_SETTING), "false") + .put("path.home", pathHome) .build(); - final String realmName = "conn_settings"; - final Function globalSettings = realmSettings -> Settings.builder() - .put(realmSettings) - .normalizePrefix(RealmSettings.PREFIX + realmName + ".") - .put("path.home", createTempDir()) - .build(); - final Environment environment = TestEnvironment.newEnvironment(globalSettings.apply(settings)); - final Function sslService = realmSettings -> new SSLService(globalSettings.apply(realmSettings), environment); - - final ThreadContext threadContext = new ThreadContext(environment.settings()); - RealmConfig realmConfig = new RealmConfig(realmName, settings, environment.settings(), environment, threadContext); - LDAPConnectionOptions options = SessionFactory.connectionOptions(realmConfig, sslService.apply(settings), logger); + final Environment environment = TestEnvironment.newEnvironment(settings); + RealmConfig realmConfig = new RealmConfig(realmId, settings, environment, new ThreadContext(settings)); + LDAPConnectionOptions options = SessionFactory.connectionOptions(realmConfig, new SSLService(settings, environment), logger); assertThat(options.followReferrals(), is(equalTo(false))); assertThat(options.allowConcurrentSocketFactoryUse(), is(equalTo(true))); assertThat(options.getConnectTimeoutMillis(), is(equalTo(10))); assertThat(options.getResponseTimeoutMillis(), is(equalTo(20L))); assertThat(options.getSSLSocketVerifier(), is(instanceOf(TrustAllSSLSocketVerifier.class))); - assertWarnings("the setting [xpack.security.authc.realms." + realmName + ".hostname_verification] has been deprecated" + - " and will be removed in a future version. use [xpack.security.authc.realms." + realmName + ".ssl.verification_mode] instead"); + assertWarnings("the setting [xpack.security.authc.realms.ldap.conn_settings.hostname_verification] has been deprecated and will be " + + "removed in a future version. use [xpack.security.authc.realms.ldap.conn_settings.ssl.verification_mode] instead"); - settings = Settings.builder().put("ssl.verification_mode", VerificationMode.CERTIFICATE).build(); - realmConfig = new RealmConfig(realmName, settings, globalSettings.apply(settings), environment, threadContext); - options = SessionFactory.connectionOptions(realmConfig, sslService.apply(settings), logger); + settings = Settings.builder() + .put(getFullSettingKey(realmId, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), VerificationMode.CERTIFICATE) + .put("path.home", pathHome) + .build(); + realmConfig = new RealmConfig(realmId, settings, environment, new ThreadContext(settings)); + options = SessionFactory.connectionOptions(realmConfig, new SSLService(settings, environment), logger); assertThat(options.getSSLSocketVerifier(), is(instanceOf(TrustAllSSLSocketVerifier.class))); // Can't run in FIPS with verification_mode none, disable this check instead of duplicating the test case if (inFipsJvm() == false) { - settings = Settings.builder().put("ssl.verification_mode", VerificationMode.NONE).build(); - realmConfig = new RealmConfig(realmName, settings, environment.settings(), environment, threadContext); - options = SessionFactory.connectionOptions(realmConfig, sslService.apply(settings), logger); + settings = Settings.builder() + .put(getFullSettingKey(realmId, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), VerificationMode.NONE) + .put("path.home", pathHome) + .build(); + realmConfig = new RealmConfig(realmId, settings, environment, new ThreadContext(settings)); + options = SessionFactory.connectionOptions(realmConfig, new SSLService(settings, environment), logger); assertThat(options.getSSLSocketVerifier(), is(instanceOf(TrustAllSSLSocketVerifier.class))); } - settings = Settings.builder().put("ssl.verification_mode", VerificationMode.FULL).build(); - realmConfig = new RealmConfig(realmName, settings, environment.settings(), environment, threadContext); - options = SessionFactory.connectionOptions(realmConfig, sslService.apply(settings), logger); + settings = Settings.builder() + .put(getFullSettingKey(realmId, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), VerificationMode.FULL) + .put("path.home", pathHome) + .build(); + realmConfig = new RealmConfig(realmId, settings, environment, new ThreadContext(settings)); + options = SessionFactory.connectionOptions(realmConfig, new SSLService(settings, environment), logger); assertThat(options.getSSLSocketVerifier(), is(instanceOf(HostNameSSLSocketVerifier.class))); } @@ -119,8 +123,12 @@ public void testUnauthenticatedSessionThrowsUnsupportedOperationException() thro private SessionFactory createSessionFactory() { Settings global = Settings.builder().put("path.home", createTempDir()).build(); - final RealmConfig realmConfig = new RealmConfig("_name", Settings.builder().put("url", "ldap://localhost:389").build(), - global, TestEnvironment.newEnvironment(global), new ThreadContext(Settings.EMPTY)); + final RealmConfig.RealmIdentifier realmIdentifier = new RealmConfig.RealmIdentifier("ldap", "_name"); + final RealmConfig realmConfig = new RealmConfig(realmIdentifier, mergeSettings( + Settings.builder() + .put(getFullSettingKey(realmIdentifier, SessionFactorySettings.URLS_SETTING), "ldap://localhost:389") + .build(), global), + TestEnvironment.newEnvironment(global), new ThreadContext(Settings.EMPTY)); return new SessionFactory(realmConfig, null, threadPool) { @Override @@ -129,4 +137,8 @@ public void session(String user, SecureString password, ActionListener - secureSettings.setString("xpack.security.authc.realms.pki1.truststore.secure_password", "truststore-testnode-only")); + secureSettings.setString("xpack.security.authc.realms.pki.pki1.truststore.secure_password", "truststore-testnode-only")); return builder.build(); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java index 4fb94c7494971..6e1a2480d2bcb 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java @@ -52,19 +52,17 @@ protected Settings nodeSettings() { .put(super.nodeSettings()) .put("xpack.security.http.ssl.enabled", true) .put("xpack.security.http.ssl.client_authentication", SSLClientAuth.OPTIONAL) - .put("xpack.security.authc.realms.file.type", "file") - .put("xpack.security.authc.realms.file.order", "0") - .put("xpack.security.authc.realms.pki1.type", "pki") - .put("xpack.security.authc.realms.pki1.order", "1") - .put("xpack.security.authc.realms.pki1.truststore.path", + .put("xpack.security.authc.realms.file.file.order", "0") + .put("xpack.security.authc.realms.pki.pki1.order", "1") + .put("xpack.security.authc.realms.pki.pki1.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) - .put("xpack.security.authc.realms.pki1.files.role_mapping", getDataPath("role_mapping.yml")) + .put("xpack.security.authc.realms.pki.pki1.files.role_mapping", getDataPath("role_mapping.yml")) .put("transport.profiles.want_client_auth.port", randomClientPortRange) .put("transport.profiles.want_client_auth.bind_host", "localhost") .put("transport.profiles.want_client_auth.xpack.security.ssl.client_authentication", SSLClientAuth.OPTIONAL); SecuritySettingsSource.addSecureSettings(builder, secureSettings -> - secureSettings.setString("xpack.security.authc.realms.pki1.truststore.secure_password", "truststore-testnode-only")); + secureSettings.setString("xpack.security.authc.realms.pki.pki1.truststore.secure_password", "truststore-testnode-only")); return builder.build(); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java index 45ccaf6a14725..4027c50a4feae 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java @@ -18,21 +18,19 @@ import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; +import org.elasticsearch.xpack.core.security.authc.InternalRealmsSettings; 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.pki.PkiRealmSettings; import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.core.security.support.NoOpLogger; import org.elasticsearch.xpack.core.security.user.User; -import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings; import org.elasticsearch.xpack.security.authc.support.MockLookupRealm; import org.elasticsearch.xpack.security.authc.support.UserRoleMapper; import org.junit.Before; import org.mockito.Mockito; import javax.security.auth.x500.X500Principal; - import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; @@ -61,6 +59,7 @@ public class PkiRealmTests extends ESTestCase { + public static final String REALM_NAME = "my_pki"; private Settings globalSettings; private XPackLicenseState licenseState; @@ -74,7 +73,7 @@ public void setup() throws Exception { } public void testTokenSupport() { - RealmConfig config = new RealmConfig("", Settings.EMPTY, globalSettings, + RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("pki", "my_pki"), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)); PkiRealm realm = new PkiRealm(config, mock(UserRoleMapper.class)); @@ -86,9 +85,9 @@ public void testTokenSupport() { public void testExtractToken() throws Exception { X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); - PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(globalSettings)), mock(UserRoleMapper.class)); + threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[]{certificate}); + PkiRealm realm = new PkiRealm(new RealmConfig(new RealmConfig.RealmIdentifier("pki", "my_pki"), globalSettings, + TestEnvironment.newEnvironment(globalSettings), threadContext), mock(UserRoleMapper.class)); X509AuthenticationToken token = realm.token(threadContext); assertThat(token, is(notNullValue())); @@ -161,8 +160,10 @@ private UserRoleMapper buildRoleMapper(Set roles, String dn) { } private PkiRealm buildRealm(UserRoleMapper roleMapper, Settings realmSettings, Realm... otherRealms) { - PkiRealm realm = new PkiRealm(new RealmConfig("", realmSettings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(globalSettings)), roleMapper); + final Settings settings = mergeSettings(realmSettings, globalSettings); + final RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("pki", REALM_NAME), settings, + TestEnvironment.newEnvironment(settings), new ThreadContext(settings)); + PkiRealm realm = new PkiRealm(config, roleMapper); List allRealms = CollectionUtils.arrayAsArrayList(otherRealms); allRealms.add(realm); Collections.shuffle(allRealms, random()); @@ -185,8 +186,12 @@ public void testCustomUsernamePattern() throws Exception { ThreadContext threadContext = new ThreadContext(globalSettings); X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); UserRoleMapper roleMapper = mock(UserRoleMapper.class); - PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.builder().put("username_pattern", "OU=(.*?),").build(), globalSettings, - TestEnvironment.newEnvironment(globalSettings), threadContext), roleMapper); + final Settings realmSettings = Settings.builder() + .put("xpack.security.authc.realms.pki.my_pki.username_pattern", "OU=(.*?),") + .build(); + PkiRealm realm = new PkiRealm(new RealmConfig(new RealmConfig.RealmIdentifier("pki", "my_pki"), + mergeSettings(realmSettings, globalSettings), + TestEnvironment.newEnvironment(globalSettings), threadContext), roleMapper); realm.initialize(Collections.emptyList(), licenseState); Mockito.doAnswer(invocation -> { ActionListener> listener = (ActionListener>) invocation.getArguments()[1]; @@ -210,14 +215,16 @@ public void testVerificationUsingATruststore() throws Exception { UserRoleMapper roleMapper = mock(UserRoleMapper.class); MockSecureSettings secureSettings = new MockSecureSettings(); - secureSettings.setString("truststore.secure_password", "testnode"); + secureSettings.setString("xpack.security.authc.realms.pki.my_pki.truststore.secure_password", "testnode"); Settings settings = Settings.builder() - .put("truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) + .put("xpack.security.authc.realms.pki.my_pki.truststore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) .setSecureSettings(secureSettings) .build(); ThreadContext threadContext = new ThreadContext(globalSettings); - PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - threadContext), roleMapper); + PkiRealm realm = new PkiRealm(new RealmConfig(new RealmConfig.RealmIdentifier("pki", "my_pki"), + mergeSettings(settings, globalSettings), + TestEnvironment.newEnvironment(globalSettings), threadContext), roleMapper); realm.initialize(Collections.emptyList(), licenseState); Mockito.doAnswer(invocation -> { ActionListener> listener = (ActionListener>) invocation.getArguments()[1]; @@ -241,15 +248,16 @@ public void testVerificationFailsUsingADifferentTruststore() throws Exception { X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); UserRoleMapper roleMapper = mock(UserRoleMapper.class); MockSecureSettings secureSettings = new MockSecureSettings(); - secureSettings.setString("truststore.secure_password", "testnode-client-profile"); + secureSettings.setString("xpack.security.authc.realms.pki.mypki.truststore.secure_password", "testnode-client-profile"); Settings settings = Settings.builder() - .put("truststore.path", + .put("xpack.security.authc.realms.pki.mypki.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.jks")) .setSecureSettings(secureSettings) .build(); final ThreadContext threadContext = new ThreadContext(globalSettings); - PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - threadContext), roleMapper); + PkiRealm realm = new PkiRealm(new RealmConfig(new RealmConfig.RealmIdentifier("pki", "mypki"), + mergeSettings(settings, globalSettings), + TestEnvironment.newEnvironment(globalSettings), threadContext), roleMapper); realm.initialize(Collections.emptyList(), licenseState); Mockito.doAnswer(invocation -> { ActionListener> listener = (ActionListener>) invocation.getArguments()[1]; @@ -268,28 +276,30 @@ public void testVerificationFailsUsingADifferentTruststore() throws Exception { public void testTruststorePathWithoutPasswordThrowsException() throws Exception { Settings settings = Settings.builder() - .put("truststore.path", + .put("xpack.security.authc.realms.pki.mypki.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.jks")) .build(); - try { - new PkiRealm(new RealmConfig("mypki", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(globalSettings)), mock(UserRoleMapper.class)); - fail("exception should have been thrown"); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), containsString("Neither [xpack.security.authc.realms.mypki.truststore.secure_password] or [" + - "xpack.security.authc.realms.mypki.truststore.password] is configured")); - } + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> + new PkiRealm(new RealmConfig(new RealmConfig.RealmIdentifier("pki", "mypki"), + mergeSettings(settings, globalSettings), + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)), mock(UserRoleMapper.class)) + ); + assertThat(e.getMessage(), containsString("Neither [xpack.security.authc.realms.pki.mypki.truststore.secure_password] or [" + + "xpack.security.authc.realms.pki.mypki.truststore.password] is configured")); } public void testTruststorePathWithLegacyPasswordDoesNotThrow() throws Exception { Settings settings = Settings.builder() - .put("truststore.path", + .put("xpack.security.authc.realms.pki.mypki.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.jks")) - .put("truststore.password", "testnode-client-profile") + .put("xpack.security.authc.realms.pki.mypki.truststore.password", "testnode-client-profile") .build(); - new PkiRealm(new RealmConfig("mypki", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(globalSettings)), mock(UserRoleMapper.class)); - assertSettingDeprecationsAndWarnings(new Setting[] { SSLConfigurationSettings.withoutPrefix().legacyTruststorePassword }); + new PkiRealm(new RealmConfig(new RealmConfig.RealmIdentifier("pki", "mypki"), + mergeSettings(settings, globalSettings), + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)), mock(UserRoleMapper.class)); + assertSettingDeprecationsAndWarnings(new Setting[]{ + PkiRealmSettings.LEGACY_TRUST_STORE_PASSWORD.getConcreteSettingForNamespace("mypki") + }); } public void testCertificateWithOnlyCnExtractsProperly() throws Exception { @@ -297,7 +307,7 @@ public void testCertificateWithOnlyCnExtractsProperly() throws Exception { X500Principal principal = new X500Principal("CN=PKI Client"); when(certificate.getSubjectX500Principal()).thenReturn(principal); - X509AuthenticationToken token = PkiRealm.token(new X509Certificate[] { certificate }, + X509AuthenticationToken token = PkiRealm.token(new X509Certificate[]{certificate}, Pattern.compile(PkiRealmSettings.DEFAULT_USERNAME_PATTERN), NoOpLogger.INSTANCE); assertThat(token, notNullValue()); assertThat(token.principal(), is("PKI Client")); @@ -309,7 +319,7 @@ public void testCertificateWithCnAndOuExtractsProperly() throws Exception { X500Principal principal = new X500Principal("CN=PKI Client, OU=Security"); when(certificate.getSubjectX500Principal()).thenReturn(principal); - X509AuthenticationToken token = PkiRealm.token(new X509Certificate[] { certificate }, + X509AuthenticationToken token = PkiRealm.token(new X509Certificate[]{certificate}, Pattern.compile(PkiRealmSettings.DEFAULT_USERNAME_PATTERN), NoOpLogger.INSTANCE); assertThat(token, notNullValue()); assertThat(token.principal(), is("PKI Client")); @@ -321,7 +331,7 @@ public void testCertificateWithCnInMiddle() throws Exception { X500Principal principal = new X500Principal("EMAILADDRESS=pki@elastic.co, CN=PKI Client, OU=Security"); when(certificate.getSubjectX500Principal()).thenReturn(principal); - X509AuthenticationToken token = PkiRealm.token(new X509Certificate[] { certificate }, + X509AuthenticationToken token = PkiRealm.token(new X509Certificate[]{certificate}, Pattern.compile(PkiRealmSettings.DEFAULT_USERNAME_PATTERN), NoOpLogger.INSTANCE); assertThat(token, notNullValue()); assertThat(token.principal(), is("PKI Client")); @@ -330,28 +340,30 @@ public void testCertificateWithCnInMiddle() throws Exception { public void testPKIRealmSettingsPassValidation() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.authc.realms.pki1.type", "pki") - .put("xpack.security.authc.realms.pki1.truststore.path", "/foo/bar") - .put("xpack.security.authc.realms.pki1.truststore.password", "supersecret") + .put("xpack.security.authc.realms.pki.pki1.order", "1") + .put("xpack.security.authc.realms.pki.pki1.truststore.path", "/foo/bar") + .put("xpack.security.authc.realms.pki.pki1.truststore.password", "supersecret") .build(); List> settingList = new ArrayList<>(); - RealmSettings.addSettings(settingList, Collections.emptyList()); + settingList.addAll(InternalRealmsSettings.getSettings()); ClusterSettings clusterSettings = new ClusterSettings(settings, new HashSet<>(settingList)); clusterSettings.validate(settings, false); - assertSettingDeprecationsAndWarnings(new Setting[] { SSLConfigurationSettings.withoutPrefix().legacyTruststorePassword }); + assertSettingDeprecationsAndWarnings(new Setting[]{ + PkiRealmSettings.LEGACY_TRUST_STORE_PASSWORD.getConcreteSettingForNamespace("pki1") + }); } public void testDelegatedAuthorization() throws Exception { final X509AuthenticationToken token = buildToken(); - 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"), + globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings))); final User lookupUser = new User(token.principal()); otherRealm.registerUser(lookupUser); final Settings realmSettings = Settings.builder() - .putList("authorization_realms", "other_realm") + .putList("xpack.security.authc.realms.pki." + REALM_NAME + ".authorization_realms", "other_realm") .build(); final UserRoleMapper roleMapper = buildRoleMapper(Collections.emptySet(), token.dn()); final PkiRealm pkiRealm = buildRealm(roleMapper, realmSettings, otherRealm); @@ -375,4 +387,9 @@ static X509Certificate readCert(Path path) throws Exception { return (X509Certificate) factory.generateCertificate(in); } } + + private static Settings mergeSettings(Settings local, Settings global) { + return Settings.builder().put(global).put(local).build(); + } + } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlLogoutRequestHandlerTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlLogoutRequestHandlerTests.java index 542bbbbdf3dc7..ad707bc028e54 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlLogoutRequestHandlerTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlLogoutRequestHandlerTests.java @@ -5,15 +5,6 @@ */ package org.elasticsearch.xpack.security.authc.saml; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.time.Clock; -import java.util.Arrays; -import java.util.Collections; - import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.set.Sets; @@ -28,6 +19,15 @@ import org.opensaml.security.x509.X509Credential; import org.opensaml.xmlsec.signature.support.SignatureConstants; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.time.Clock; +import java.util.Arrays; +import java.util.Collections; + import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.notNullValue; @@ -208,10 +208,10 @@ private SamlLogoutRequestHandler buildHandler() throws Exception { final SpConfiguration sp = new SpConfiguration("https://sp.test/", "https://sp.test/saml/asc", LOGOUT_URL, signingConfiguration, Arrays.asList(spCredential), Collections.emptyList()); return new SamlLogoutRequestHandler( - clock, - idp, - sp, - TimeValue.timeValueSeconds(1) + clock, + idp, + sp, + TimeValue.timeValueSeconds(1) ); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlMetadataCommandTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlMetadataCommandTests.java index f2c91437c3e02..367921ad7635a 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlMetadataCommandTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlMetadataCommandTests.java @@ -6,7 +6,6 @@ package org.elasticsearch.xpack.security.authc.saml; import joptsimple.OptionSet; - import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.cli.MockTerminal; import org.elasticsearch.cli.UserException; @@ -79,16 +78,15 @@ public void testDefaultOptions() throws Exception { final boolean useSigningCredentials = randomBoolean(); final Settings.Builder settingsBuilder = Settings.builder() .put("path.home", createTempDir()) - .put(RealmSettings.PREFIX + "my_saml.type", "saml") - .put(RealmSettings.PREFIX + "my_saml.order", 1) - .put(RealmSettings.PREFIX + "my_saml.idp.entity_id", "https://okta.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.entity_id", "https://kibana.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.acs", "https://kibana.my.corp/saml/login") - .put(RealmSettings.PREFIX + "my_saml.sp.logout", "https://kibana.my.corp/saml/logout") - .put(RealmSettings.PREFIX + "my_saml.attributes.principal", "urn:oid:0.9.2342.19200300.100.1.1"); + .put(RealmSettings.PREFIX + "saml.my_saml.order", 1) + .put(RealmSettings.PREFIX + "saml.my_saml.idp.entity_id", "https://okta.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.entity_id", "https://kibana.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.acs", "https://kibana.my.corp/saml/login") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.logout", "https://kibana.my.corp/saml/logout") + .put(RealmSettings.PREFIX + "saml.my_saml.attributes.principal", "urn:oid:0.9.2342.19200300.100.1.1"); if (useSigningCredentials) { - settingsBuilder.put(RealmSettings.PREFIX + "my_saml.signing.certificate", certPath.toString()) - .put(RealmSettings.PREFIX + "my_saml.signing.key", keyPath.toString()); + settingsBuilder.put(RealmSettings.PREFIX + "saml.my_saml.signing.certificate", certPath.toString()) + .put(RealmSettings.PREFIX + "saml.my_saml.signing.key", keyPath.toString()); } final Settings settings = settingsBuilder.build(); final Environment env = TestEnvironment.newEnvironment(settings); @@ -151,12 +149,12 @@ public void testDefaultOptions() throws Exception { public void testFailIfMultipleRealmsExist() throws Exception { final Settings settings = Settings.builder() .put("path.home", createTempDir()) - .put(RealmSettings.PREFIX + "saml_a.type", "saml") - .put(RealmSettings.PREFIX + "saml_a.sp.entity_id", "https://saml.a/") - .put(RealmSettings.PREFIX + "saml_a.sp.acs", "https://saml.a/") - .put(RealmSettings.PREFIX + "saml_b.type", "saml") - .put(RealmSettings.PREFIX + "saml_b.sp.entity_id", "https://saml.b/") - .put(RealmSettings.PREFIX + "saml_b.sp.acs", "https://saml.b/") + .put(RealmSettings.PREFIX + "saml.saml_a.type", "saml") + .put(RealmSettings.PREFIX + "saml.saml_a.sp.entity_id", "https://saml.a/") + .put(RealmSettings.PREFIX + "saml.saml_a.sp.acs", "https://saml.a/") + .put(RealmSettings.PREFIX + "saml.saml_b.type", "saml") + .put(RealmSettings.PREFIX + "saml.saml_b.sp.entity_id", "https://saml.b/") + .put(RealmSettings.PREFIX + "saml.saml_b.sp.acs", "https://saml.b/") .build(); final Environment env = TestEnvironment.newEnvironment(settings); @@ -175,12 +173,12 @@ public void testFailIfMultipleRealmsExist() throws Exception { public void testSpecifyRealmNameAsParameter() throws Exception { final Settings settings = Settings.builder() .put("path.home", createTempDir()) - .put(RealmSettings.PREFIX + "saml_a.type", "saml") - .put(RealmSettings.PREFIX + "saml_a.sp.entity_id", "https://saml.a/") - .put(RealmSettings.PREFIX + "saml_a.sp.acs", "https://saml.a/acs") - .put(RealmSettings.PREFIX + "saml_b.type", "saml") - .put(RealmSettings.PREFIX + "saml_b.sp.entity_id", "https://saml.b/") - .put(RealmSettings.PREFIX + "saml_b.sp.acs", "https://saml.b/acs") + .put(RealmSettings.PREFIX + "saml.saml_a.type", "saml") + .put(RealmSettings.PREFIX + "saml.saml_a.sp.entity_id", "https://saml.a/") + .put(RealmSettings.PREFIX + "saml.saml_a.sp.acs", "https://saml.a/acs") + .put(RealmSettings.PREFIX + "saml.saml_b.type", "saml") + .put(RealmSettings.PREFIX + "saml.saml_b.sp.entity_id", "https://saml.b/") + .put(RealmSettings.PREFIX + "saml.saml_b.sp.acs", "https://saml.b/acs") .build(); final Environment env = TestEnvironment.newEnvironment(settings); @@ -206,11 +204,11 @@ public void testSpecifyRealmNameAsParameter() throws Exception { public void testHandleAttributes() throws Exception { final Settings settings = Settings.builder() .put("path.home", createTempDir()) - .put(RealmSettings.PREFIX + "saml1.type", "saml") - .put(RealmSettings.PREFIX + "saml1.sp.entity_id", "https://saml.example.com/") - .put(RealmSettings.PREFIX + "saml1.sp.acs", "https://saml.example.com/") - .put(RealmSettings.PREFIX + "saml1.attributes.principal", "urn:oid:0.9.2342.19200300.100.1.1") - .put(RealmSettings.PREFIX + "saml1.attributes.name", "displayName") + .put(RealmSettings.PREFIX + "saml.saml1.type", "saml") + .put(RealmSettings.PREFIX + "saml.saml1.sp.entity_id", "https://saml.example.com/") + .put(RealmSettings.PREFIX + "saml.saml1.sp.acs", "https://saml.example.com/") + .put(RealmSettings.PREFIX + "saml.saml1.attributes.principal", "urn:oid:0.9.2342.19200300.100.1.1") + .put(RealmSettings.PREFIX + "saml.saml1.attributes.name", "displayName") .build(); final Environment env = TestEnvironment.newEnvironment(settings); @@ -260,10 +258,10 @@ public void testHandleAttributes() throws Exception { public void testHandleAttributesInBatchMode() throws Exception { final Settings settings = Settings.builder() .put("path.home", createTempDir()) - .put(RealmSettings.PREFIX + "saml1.type", "saml") - .put(RealmSettings.PREFIX + "saml1.sp.entity_id", "https://saml.example.com/") - .put(RealmSettings.PREFIX + "saml1.sp.acs", "https://saml.example.com/") - .put(RealmSettings.PREFIX + "saml1.attributes.principal", "urn:oid:0.9.2342.19200300.100.1.1") + .put(RealmSettings.PREFIX + "saml.saml1.type", "saml") + .put(RealmSettings.PREFIX + "saml.saml1.sp.entity_id", "https://saml.example.com/") + .put(RealmSettings.PREFIX + "saml.saml1.sp.acs", "https://saml.example.com/") + .put(RealmSettings.PREFIX + "saml.saml1.attributes.principal", "urn:oid:0.9.2342.19200300.100.1.1") .build(); final Environment env = TestEnvironment.newEnvironment(settings); @@ -307,16 +305,16 @@ public void testSigningMetadataWithPfx() throws Exception { final boolean useSigningCredentials = randomBoolean(); final Settings.Builder settingsBuilder = Settings.builder() .put("path.home", createTempDir()) - .put(RealmSettings.PREFIX + "my_saml.type", "saml") - .put(RealmSettings.PREFIX + "my_saml.order", 1) - .put(RealmSettings.PREFIX + "my_saml.idp.entity_id", "https://okta.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.entity_id", "https://kibana.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.acs", "https://kibana.my.corp/saml/login") - .put(RealmSettings.PREFIX + "my_saml.sp.logout", "https://kibana.my.corp/saml/logout") - .put(RealmSettings.PREFIX + "my_saml.attributes.principal", "urn:oid:0.9.2342.19200300.100.1.1"); + .put(RealmSettings.PREFIX + "saml.my_saml.type", "saml") + .put(RealmSettings.PREFIX + "saml.my_saml.order", 1) + .put(RealmSettings.PREFIX + "saml.my_saml.idp.entity_id", "https://okta.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.entity_id", "https://kibana.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.acs", "https://kibana.my.corp/saml/login") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.logout", "https://kibana.my.corp/saml/logout") + .put(RealmSettings.PREFIX + "saml.my_saml.attributes.principal", "urn:oid:0.9.2342.19200300.100.1.1"); if (useSigningCredentials) { - settingsBuilder.put(RealmSettings.PREFIX + "my_saml.signing.certificate", certPath.toString()) - .put(RealmSettings.PREFIX + "my_saml.signing.key", keyPath.toString()); + settingsBuilder.put(RealmSettings.PREFIX + "saml.my_saml.signing.certificate", certPath.toString()) + .put(RealmSettings.PREFIX + "saml.my_saml.signing.key", keyPath.toString()); } final Settings settings = settingsBuilder.build(); final Environment env = TestEnvironment.newEnvironment(settings); @@ -368,15 +366,15 @@ public void testSigningMetadataWithPasswordProtectedPfx() throws Exception { final boolean useSigningCredentials = randomBoolean(); final Settings.Builder settingsBuilder = Settings.builder() .put("path.home", createTempDir()) - .put(RealmSettings.PREFIX + "my_saml.type", "saml") - .put(RealmSettings.PREFIX + "my_saml.order", 1) - .put(RealmSettings.PREFIX + "my_saml.idp.entity_id", "https://okta.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.entity_id", "https://kibana.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.acs", "https://kibana.my.corp/saml/login") - .put(RealmSettings.PREFIX + "my_saml.sp.logout", "https://kibana.my.corp/saml/logout"); + .put(RealmSettings.PREFIX + "saml.my_saml.type", "saml") + .put(RealmSettings.PREFIX + "saml.my_saml.order", 1) + .put(RealmSettings.PREFIX + "saml.my_saml.idp.entity_id", "https://okta.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.entity_id", "https://kibana.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.acs", "https://kibana.my.corp/saml/login") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.logout", "https://kibana.my.corp/saml/logout"); if (useSigningCredentials) { - settingsBuilder.put(RealmSettings.PREFIX + "my_saml.signing.certificate", certPath.toString()) - .put(RealmSettings.PREFIX + "my_saml.signing.key", keyPath.toString()); + settingsBuilder.put(RealmSettings.PREFIX + "saml.my_saml.signing.certificate", certPath.toString()) + .put(RealmSettings.PREFIX + "saml.my_saml.signing.key", keyPath.toString()); } final Settings settings = settingsBuilder.build(); final Environment env = TestEnvironment.newEnvironment(settings); @@ -406,15 +404,15 @@ public void testErrorSigningMetadataWithWrongPassword() throws Exception { final boolean useSigningCredentials = randomBoolean(); final Settings.Builder settingsBuilder = Settings.builder() .put("path.home", createTempDir()) - .put(RealmSettings.PREFIX + "my_saml.type", "saml") - .put(RealmSettings.PREFIX + "my_saml.order", 1) - .put(RealmSettings.PREFIX + "my_saml.idp.entity_id", "https://okta.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.entity_id", "https://kibana.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.acs", "https://kibana.my.corp/saml/login") - .put(RealmSettings.PREFIX + "my_saml.sp.logout", "https://kibana.my.corp/saml/logout"); + .put(RealmSettings.PREFIX + "saml.my_saml.type", "saml") + .put(RealmSettings.PREFIX + "saml.my_saml.order", 1) + .put(RealmSettings.PREFIX + "saml.my_saml.idp.entity_id", "https://okta.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.entity_id", "https://kibana.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.acs", "https://kibana.my.corp/saml/login") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.logout", "https://kibana.my.corp/saml/logout"); if (useSigningCredentials) { - settingsBuilder.put(RealmSettings.PREFIX + "my_saml.signing.certificate", certPath.toString()) - .put(RealmSettings.PREFIX + "my_saml.signing.key", keyPath.toString()); + settingsBuilder.put(RealmSettings.PREFIX + "saml.my_saml.signing.certificate", certPath.toString()) + .put(RealmSettings.PREFIX + "saml.my_saml.signing.key", keyPath.toString()); } final Settings settings = settingsBuilder.build(); final Environment env = TestEnvironment.newEnvironment(settings); @@ -442,15 +440,15 @@ public void testSigningMetadataWithPem() throws Exception { final boolean useSigningCredentials = randomBoolean(); final Settings.Builder settingsBuilder = Settings.builder() .put("path.home", createTempDir()) - .put(RealmSettings.PREFIX + "my_saml.type", "saml") - .put(RealmSettings.PREFIX + "my_saml.order", 1) - .put(RealmSettings.PREFIX + "my_saml.idp.entity_id", "https://okta.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.entity_id", "https://kibana.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.acs", "https://kibana.my.corp/saml/login") - .put(RealmSettings.PREFIX + "my_saml.sp.logout", "https://kibana.my.corp/saml/logout"); + .put(RealmSettings.PREFIX + "saml.my_saml.type", "saml") + .put(RealmSettings.PREFIX + "saml.my_saml.order", 1) + .put(RealmSettings.PREFIX + "saml.my_saml.idp.entity_id", "https://okta.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.entity_id", "https://kibana.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.acs", "https://kibana.my.corp/saml/login") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.logout", "https://kibana.my.corp/saml/logout"); if (useSigningCredentials) { - settingsBuilder.put(RealmSettings.PREFIX + "my_saml.signing.certificate", certPath.toString()) - .put(RealmSettings.PREFIX + "my_saml.signing.key", keyPath.toString()); + settingsBuilder.put(RealmSettings.PREFIX + "saml.my_saml.signing.certificate", certPath.toString()) + .put(RealmSettings.PREFIX + "saml.my_saml.signing.key", keyPath.toString()); } final Settings settings = settingsBuilder.build(); final Environment env = TestEnvironment.newEnvironment(settings); @@ -483,15 +481,15 @@ public void testSigningMetadataWithPasswordProtectedPem() throws Exception { final boolean useSigningCredentials = randomBoolean(); final Settings.Builder settingsBuilder = Settings.builder() .put("path.home", createTempDir()) - .put(RealmSettings.PREFIX + "my_saml.type", "saml") - .put(RealmSettings.PREFIX + "my_saml.order", 1) - .put(RealmSettings.PREFIX + "my_saml.idp.entity_id", "https://okta.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.entity_id", "https://kibana.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.acs", "https://kibana.my.corp/saml/login") - .put(RealmSettings.PREFIX + "my_saml.sp.logout", "https://kibana.my.corp/saml/logout"); + .put(RealmSettings.PREFIX + "saml.my_saml.type", "saml") + .put(RealmSettings.PREFIX + "saml.my_saml.order", 1) + .put(RealmSettings.PREFIX + "saml.my_saml.idp.entity_id", "https://okta.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.entity_id", "https://kibana.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.acs", "https://kibana.my.corp/saml/login") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.logout", "https://kibana.my.corp/saml/logout"); if (useSigningCredentials) { - settingsBuilder.put(RealmSettings.PREFIX + "my_saml.signing.certificate", certPath.toString()) - .put(RealmSettings.PREFIX + "my_saml.signing.key", keyPath.toString()); + settingsBuilder.put(RealmSettings.PREFIX + "saml.my_saml.signing.certificate", certPath.toString()) + .put(RealmSettings.PREFIX + "saml.my_saml.signing.key", keyPath.toString()); } final Settings settings = settingsBuilder.build(); final Environment env = TestEnvironment.newEnvironment(settings); @@ -523,15 +521,15 @@ public void testSigningMetadataWithPasswordProtectedPemInTerminal() throws Excep final boolean useSigningCredentials = randomBoolean(); final Settings.Builder settingsBuilder = Settings.builder() .put("path.home", createTempDir()) - .put(RealmSettings.PREFIX + "my_saml.type", "saml") - .put(RealmSettings.PREFIX + "my_saml.order", 1) - .put(RealmSettings.PREFIX + "my_saml.idp.entity_id", "https://okta.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.entity_id", "https://kibana.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.acs", "https://kibana.my.corp/saml/login") - .put(RealmSettings.PREFIX + "my_saml.sp.logout", "https://kibana.my.corp/saml/logout"); + .put(RealmSettings.PREFIX + "saml.my_saml.type", "saml") + .put(RealmSettings.PREFIX + "saml.my_saml.order", 1) + .put(RealmSettings.PREFIX + "saml.my_saml.idp.entity_id", "https://okta.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.entity_id", "https://kibana.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.acs", "https://kibana.my.corp/saml/login") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.logout", "https://kibana.my.corp/saml/logout"); if (useSigningCredentials) { - settingsBuilder.put(RealmSettings.PREFIX + "my_saml.signing.certificate", certPath.toString()) - .put(RealmSettings.PREFIX + "my_saml.signing.key", keyPath.toString()); + settingsBuilder.put(RealmSettings.PREFIX + "saml.my_saml.signing.certificate", certPath.toString()) + .put(RealmSettings.PREFIX + "saml.my_saml.signing.key", keyPath.toString()); } final Settings settings = settingsBuilder.build(); final Environment env = TestEnvironment.newEnvironment(settings); @@ -575,30 +573,32 @@ public void testDefaultOptionsWithSigningAndMultipleEncryptionKeys() throws Exce } final MockSecureSettings secureSettings = new MockSecureSettings(); - secureSettings.setString(RealmSettings.PREFIX + "my_saml.signing.keystore.secure_password", "ks-password"); - secureSettings.setString(RealmSettings.PREFIX + "my_saml.signing.keystore.secure_key_password", "key-password"); - secureSettings.setString(RealmSettings.PREFIX + "my_saml.encryption.keystore.secure_password", "ks-password"); - secureSettings.setString(RealmSettings.PREFIX + "my_saml.encryption.keystore.secure_key_password", "key-password"); + secureSettings.setString(RealmSettings.PREFIX + "saml.my_saml.signing.keystore.secure_password", "ks-password"); + secureSettings.setString(RealmSettings.PREFIX + "saml.my_saml.signing.keystore.secure_key_password", "key-password"); + secureSettings.setString(RealmSettings.PREFIX + "saml.my_saml.encryption.keystore.secure_password", "ks-password"); + secureSettings.setString(RealmSettings.PREFIX + "saml.my_saml.encryption.keystore.secure_key_password", "key-password"); final SamlMetadataCommand command = new SamlMetadataCommand((e) -> keyStore); final OptionSet options = command.getParser().parse(new String[0]); final boolean useSigningCredentials = randomBoolean(); final boolean useEncryptionCredentials = randomBoolean(); - final Settings.Builder settingsBuilder = Settings.builder().put("path.home", dir).put(RealmSettings.PREFIX + "my_saml.type", "saml") - .put(RealmSettings.PREFIX + "my_saml.order", 1).put(RealmSettings.PREFIX + "my_saml.idp.entity_id", "https://okta.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.entity_id", "https://kibana.my.corp/") - .put(RealmSettings.PREFIX + "my_saml.sp.acs", "https://kibana.my.corp/saml/login") - .put(RealmSettings.PREFIX + "my_saml.sp.logout", "https://kibana.my.corp/saml/logout") - .put(RealmSettings.PREFIX + "my_saml.attributes.principal", "urn:oid:0.9.2342.19200300.100.1.1"); + final Settings.Builder settingsBuilder = Settings.builder().put("path.home", dir) + .put(RealmSettings.PREFIX + "saml.my_saml.type", "saml") + .put(RealmSettings.PREFIX + "saml.my_saml.order", 1) + .put(RealmSettings.PREFIX + "saml.my_saml.idp.entity_id", "https://okta.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.entity_id", "https://kibana.my.corp/") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.acs", "https://kibana.my.corp/saml/login") + .put(RealmSettings.PREFIX + "saml.my_saml.sp.logout", "https://kibana.my.corp/saml/logout") + .put(RealmSettings.PREFIX + "saml.my_saml.attributes.principal", "urn:oid:0.9.2342.19200300.100.1.1"); settingsBuilder.setSecureSettings(secureSettings); if (useSigningCredentials) { - settingsBuilder.put(RealmSettings.PREFIX + "my_saml.signing.keystore.path", ksSigningFile.toString()); - settingsBuilder.put(RealmSettings.PREFIX + "my_saml.signing.keystore.type", "PKCS12"); + settingsBuilder.put(RealmSettings.PREFIX + "saml.my_saml.signing.keystore.path", ksSigningFile.toString()); + settingsBuilder.put(RealmSettings.PREFIX + "saml.my_saml.signing.keystore.type", "PKCS12"); } if (useEncryptionCredentials) { - settingsBuilder.put(RealmSettings.PREFIX + "my_saml.encryption.keystore.path", ksEncryptionFile.toString()); - settingsBuilder.put(RealmSettings.PREFIX + "my_saml.encryption.keystore.type", "PKCS12"); + settingsBuilder.put(RealmSettings.PREFIX + "saml.my_saml.encryption.keystore.path", ksEncryptionFile.toString()); + settingsBuilder.put(RealmSettings.PREFIX + "saml.my_saml.encryption.keystore.type", "PKCS12"); } final Settings settings = settingsBuilder.build(); final Environment env = TestEnvironment.newEnvironment(settings); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlRealmTests.java index 2ecfdb50230bf..817cda5b0f0f5 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlRealmTests.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.xpack.security.authc.saml; +import org.apache.logging.log4j.message.ParameterizedMessage; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.common.collect.Tuple; @@ -64,6 +65,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; +import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey; import static org.hamcrest.Matchers.arrayContainingInAnyOrder; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -88,7 +90,7 @@ public class SamlRealmTests extends SamlTestCase { private static final int METADATA_REFRESH = 3000; private static final String REALM_NAME = "my-saml"; - private static final String REALM_SETTINGS_PREFIX = "xpack.security.authc.realms." + REALM_NAME; + private static final String REALM_SETTINGS_PREFIX = "xpack.security.authc.realms.saml." + REALM_NAME; private Settings globalSettings; private Environment env; @@ -138,6 +140,7 @@ public void testReadIdpMetadataFromHttps() throws Exception { assertEquals(0, proxyServer.requests().size()); Tuple config = buildConfig("https://localhost:" + proxyServer.getPort()); + logger.info("Settings\n{}", config.v1().globalSettings().toDelimitedString('\n')); final ResourceWatcherService watcherService = mock(ResourceWatcherService.class); Tuple> tuple = SamlRealm.initializeResolver(logger, config.v1(), config.v2(), watcherService); @@ -216,30 +219,31 @@ private AuthenticationResult performAuthentication(UserRoleMapper roleMapper, bo final String uidValue = principalIsEmailAddress ? "cbarton@shield.gov" : "cbarton"; final MockLookupRealm lookupRealm = new MockLookupRealm( - new RealmConfig("mock_lookup", Settings.EMPTY,globalSettings, env, threadContext)); + new RealmConfig(new RealmConfig.RealmIdentifier("mock","mock_lookup"), globalSettings, env, threadContext)); final Settings.Builder settingsBuilder = Settings.builder() - .put(SamlRealmSettings.PRINCIPAL_ATTRIBUTE.name(), useNameId ? "nameid" : "uid") - .put(SamlRealmSettings.GROUPS_ATTRIBUTE.name(), "groups") - .put(SamlRealmSettings.MAIL_ATTRIBUTE.name(), "mail"); + .put(getFullSettingKey(REALM_NAME, SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getAttribute()), useNameId ? "nameid" : "uid") + .put(getFullSettingKey(REALM_NAME, SamlRealmSettings.GROUPS_ATTRIBUTE.getAttribute()), "groups") + .put(getFullSettingKey(REALM_NAME, SamlRealmSettings.MAIL_ATTRIBUTE.getAttribute()), "mail"); if (principalIsEmailAddress) { final boolean anchoredMatch = randomBoolean(); - settingsBuilder.put(SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getPattern().getKey(), + settingsBuilder.put(getFullSettingKey(REALM_NAME, SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getPattern()), anchoredMatch ? "^([^@]+)@shield.gov$" : "^([^@]+)@"); } if (populateUserMetadata != null) { - settingsBuilder.put(SamlRealmSettings.POPULATE_USER_METADATA.getKey(), populateUserMetadata.booleanValue()); + settingsBuilder.put(getFullSettingKey(REALM_NAME, SamlRealmSettings.POPULATE_USER_METADATA), + populateUserMetadata.booleanValue()); } if (useAuthorizingRealm) { - settingsBuilder.putList(DelegatedAuthorizationSettings.AUTHZ_REALMS.getKey(), lookupRealm.name()); + settingsBuilder.putList(getFullSettingKey(new RealmConfig.RealmIdentifier("saml", REALM_NAME), + DelegatedAuthorizationSettings.AUTHZ_REALMS), lookupRealm.name()); lookupRealm.registerUser(new User(userPrincipal, new String[]{ "lookup_user_role" }, "Clinton Barton", "cbarton@shield.gov", Collections.singletonMap("is_lookup", true), true)); } final Settings realmSettings = settingsBuilder.build(); - final RealmConfig config = realmConfigFromRealmSettings(realmSettings); - final SamlRealm realm = new SamlRealm(config, roleMapper, authenticator, logoutHandler, () -> idp, sp); - + final RealmConfig config = buildConfig(realmSettings); + final SamlRealm realm = buildRealm(config, roleMapper, authenticator, logoutHandler, idp, sp); initializeRealms(realm, lookupRealm); final SamlToken token = new SamlToken(new byte[0], Collections.singletonList("")); @@ -275,14 +279,24 @@ private void initializeRealms(Realm... realms) { } } + public SamlRealm buildRealm(RealmConfig config, UserRoleMapper roleMapper, SamlAuthenticator authenticator, + SamlLogoutRequestHandler logoutHandler, EntityDescriptor idp, SpConfiguration sp) throws Exception { + try { + return new SamlRealm(config, roleMapper, authenticator, logoutHandler, () -> idp, sp); + } catch (SettingsException e) { + logger.info(new ParameterizedMessage("Settings are invalid:\n{}", config.globalSettings().toDelimitedString('\n')), e); + throw e; + } + } + public void testAttributeSelectionWithRegex() throws Exception { final boolean useFriendlyName = randomBoolean(); final Settings settings = Settings.builder() - .put("attributes.principal", useFriendlyName ? "mail" : "urn:oid:0.9.2342.19200300.100.1.3") - .put("attribute_patterns.principal", "^(.+)@\\w+.example.com$") + .put(REALM_SETTINGS_PREFIX + ".attributes.principal", useFriendlyName ? "mail" : "urn:oid:0.9.2342.19200300.100.1.3") + .put(REALM_SETTINGS_PREFIX + ".attribute_patterns.principal", "^(.+)@\\w+.example.com$") .build(); - final RealmConfig config = realmConfigFromRealmSettings(settings); + final RealmConfig config = buildConfig(settings); final SamlRealmSettings.AttributeSetting principalSetting = new SamlRealmSettings.AttributeSetting("principal"); final SamlRealm.AttributeParser parser = SamlRealm.AttributeParser.forSetting(logger, principalSetting, config, false); @@ -295,15 +309,15 @@ public void testAttributeSelectionWithRegex() throws Exception { ))); final List strings = parser.getAttribute(attributes); - assertThat(strings, contains("john.smith", "jsmith")); + assertThat("For attributes: " + strings, strings, contains("john.smith", "jsmith")); } public void testSettingPatternWithoutAttributeThrowsSettingsException() throws Exception { final Settings realmSettings = Settings.builder() - .put(SamlRealmSettings.PRINCIPAL_ATTRIBUTE.name(), "nameid") - .put(SamlRealmSettings.NAME_ATTRIBUTE.getPattern().getKey(), "^\\s*(\\S.*\\S)\\s*$") + .put(getFullSettingKey(REALM_NAME, SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getAttribute()), "nameid") + .put(getFullSettingKey(REALM_NAME, SamlRealmSettings.NAME_ATTRIBUTE.getPattern()), "^\\s*(\\S.*\\S)\\s*$") .build(); - final RealmConfig config = realmConfigFromRealmSettings(realmSettings); + final RealmConfig config = buildConfig(realmSettings); final UserRoleMapper roleMapper = mock(UserRoleMapper.class); final SamlAuthenticator authenticator = mock(SamlAuthenticator.class); @@ -312,14 +326,14 @@ public void testSettingPatternWithoutAttributeThrowsSettingsException() throws E final SpConfiguration sp = new SpConfiguration("", "https://saml/", null, null, null, Collections.emptyList()); final SettingsException settingsException = expectThrows(SettingsException.class, - () -> new SamlRealm(config, roleMapper, authenticator, logoutHandler, () -> idp, sp)); + () -> buildRealm(config, roleMapper, authenticator, logoutHandler, idp, sp)); assertThat(settingsException.getMessage(), containsString(REALM_SETTINGS_PREFIX + ".attribute_patterns.name")); assertThat(settingsException.getMessage(), containsString(REALM_SETTINGS_PREFIX + ".attributes.name")); } public void testMissingPrincipalSettingThrowsSettingsException() throws Exception { final Settings realmSettings = Settings.EMPTY; - final RealmConfig config = realmConfigFromRealmSettings(realmSettings); + final RealmConfig config = buildConfig(realmSettings); final UserRoleMapper roleMapper = mock(UserRoleMapper.class); final SamlAuthenticator authenticator = mock(SamlAuthenticator.class); @@ -328,7 +342,7 @@ public void testMissingPrincipalSettingThrowsSettingsException() throws Exceptio final SpConfiguration sp = new SpConfiguration("", "https://saml/", null, null, null, Collections.emptyList()); final SettingsException settingsException = expectThrows(SettingsException.class, - () -> new SamlRealm(config, roleMapper, authenticator, logoutHandler, () -> idp, sp)); + () -> buildRealm(config, roleMapper, authenticator, logoutHandler, idp, sp)); assertThat(settingsException.getMessage(), containsString(REALM_SETTINGS_PREFIX + ".attributes.principal")); } @@ -340,13 +354,13 @@ public void testNonMatchingPrincipalPatternThrowsSamlException() throws Exceptio final SamlLogoutRequestHandler logoutHandler = mock(SamlLogoutRequestHandler.class); final Settings realmSettings = Settings.builder() - .put(SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getAttribute().getKey(), "mail") - .put(SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getPattern().getKey(), "^([^@]+)@mycorp\\.example\\.com$") + .put(getFullSettingKey(REALM_NAME, SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getAttribute()), "mail") + .put(getFullSettingKey(REALM_NAME, SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getPattern()), "^([^@]+)@mycorp\\.example\\.com$") .build(); - final RealmConfig config = realmConfigFromRealmSettings(realmSettings); + final RealmConfig config = buildConfig(realmSettings); - final SamlRealm realm = new SamlRealm(config, roleMapper, authenticator, logoutHandler, () -> idp, sp); + final SamlRealm realm = buildRealm(config, roleMapper, authenticator, logoutHandler, idp, sp); final SamlToken token = new SamlToken(new byte[0], Collections.singletonList("")); for (String mail : Arrays.asList("john@your-corp.example.com", "john@mycorp.example.com.example.net", "john")) { @@ -531,7 +545,7 @@ public void testCreateSigningCredentialFromKeyStoreFailureScenarios() throws Exc final IllegalArgumentException illegalArgumentException = expectThrows(IllegalArgumentException.class, () -> SamlRealm.buildSigningConfiguration(realmConfig)); final String expectedErrorMessage = "The configured key store for " - + RealmSettings.getFullSettingKey(realmConfig, SamlRealmSettings.SIGNING_SETTINGS.getPrefix()) + + RealmSettings.realmSettingPrefix(realmConfig.identifier()) + "signing." + " does not have a key associated with alias [" + unknownAlias + "] " + "(from setting " + RealmSettings.getFullSettingKey(realmConfig, SamlRealmSettings.SIGNING_KEY_ALIAS) + ")"; assertEquals(expectedErrorMessage, illegalArgumentException.getLocalizedMessage()); @@ -552,7 +566,7 @@ public void testCreateSigningCredentialFromKeyStoreFailureScenarios() throws Exc final IllegalArgumentException illegalArgumentException = expectThrows(IllegalArgumentException.class, () -> SamlRealm.buildSigningConfiguration(realmConfig)); final String expectedErrorMessage = "The configured key store for " - + RealmSettings.getFullSettingKey(realmConfig, SamlRealmSettings.SIGNING_SETTINGS.getPrefix()) + + RealmSettings.realmSettingPrefix(realmConfig.identifier()) + "signing." + " does not contain any RSA key pairs"; assertEquals(expectedErrorMessage, illegalArgumentException.getLocalizedMessage()); } else { @@ -560,7 +574,7 @@ public void testCreateSigningCredentialFromKeyStoreFailureScenarios() throws Exc final IllegalArgumentException illegalArgumentException = expectThrows(IllegalArgumentException.class, () -> SamlRealm.buildSigningConfiguration(realmConfig)); final String expectedErrorMessage = "The configured key store for " - + RealmSettings.getFullSettingKey(realmConfig, SamlRealmSettings.SIGNING_SETTINGS.getPrefix()) + + RealmSettings.realmSettingPrefix(realmConfig.identifier()) + "signing." + " has multiple keys but no alias has been specified (from setting " + RealmSettings.getFullSettingKey(realmConfig, SamlRealmSettings.SIGNING_KEY_ALIAS) + ")"; assertEquals(expectedErrorMessage, illegalArgumentException.getLocalizedMessage()); @@ -590,14 +604,14 @@ public void testBuildLogoutRequest() throws Exception { final SamlLogoutRequestHandler logoutHandler = mock(SamlLogoutRequestHandler.class); final Settings.Builder realmSettings = Settings.builder() - .put(SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getAttribute().getKey(), "uid"); + .put(getFullSettingKey(REALM_NAME, SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getAttribute()), "uid"); if (useSingleLogout != null) { - realmSettings.put(SamlRealmSettings.IDP_SINGLE_LOGOUT.getKey(), useSingleLogout.booleanValue()); + realmSettings.put(getFullSettingKey(REALM_NAME, SamlRealmSettings.IDP_SINGLE_LOGOUT), useSingleLogout.booleanValue()); } - final RealmConfig config = realmConfigFromRealmSettings(realmSettings.build()); + final RealmConfig config = buildConfig(realmSettings.build()); - final SamlRealm realm = new SamlRealm(config, roleMapper, authenticator, logoutHandler, () -> idp, sp); + final SamlRealm realm = buildRealm(config, roleMapper, authenticator, logoutHandler, idp, sp); final NameID nameId = SamlUtils.buildObject(NameID.class, NameID.DEFAULT_ELEMENT_NAME); nameId.setFormat(NameID.TRANSIENT); @@ -622,8 +636,8 @@ private EntityDescriptor mockIdp() { return descriptor; } - private Tuple buildConfig(String path) throws Exception { - Settings globalSettings = buildSettings(path).build(); + private Tuple buildConfig(String idpMetaDataPath) throws Exception { + Settings globalSettings = buildSettings(idpMetaDataPath).build(); final Environment env = TestEnvironment.newEnvironment(globalSettings); final RealmConfig config = realmConfigFromGlobalSettings(globalSettings); final SSLService sslService = new SSLService(globalSettings, env); @@ -641,22 +655,24 @@ private Settings.Builder buildSettings(String idpMetaDataPath) { getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) .put(REALM_SETTINGS_PREFIX + ".ssl.certificate_authorities", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) - .put(REALM_SETTINGS_PREFIX + ".type", "saml") - .put(REALM_SETTINGS_PREFIX + "." + SamlRealmSettings.IDP_METADATA_PATH.getKey(), idpMetaDataPath) - .put(REALM_SETTINGS_PREFIX + "." + SamlRealmSettings.IDP_ENTITY_ID.getKey(), TEST_IDP_ENTITY_ID) - .put(REALM_SETTINGS_PREFIX + "." + SamlRealmSettings.IDP_METADATA_HTTP_REFRESH.getKey(), METADATA_REFRESH + "ms") + .put(getFullSettingKey(REALM_NAME, SamlRealmSettings.IDP_METADATA_PATH), idpMetaDataPath) + .put(getFullSettingKey(REALM_NAME, SamlRealmSettings.IDP_ENTITY_ID), TEST_IDP_ENTITY_ID) + .put(getFullSettingKey(REALM_NAME, SamlRealmSettings.IDP_METADATA_HTTP_REFRESH), METADATA_REFRESH + "ms") .put("path.home", createTempDir()) .setSecureSettings(secureSettings); } - private RealmConfig realmConfigFromRealmSettings(Settings realmSettings) { - return new RealmConfig(REALM_NAME, realmSettings, globalSettings, env, threadContext); + private RealmConfig buildConfig(Settings realmSettings) { + final Settings settings = Settings.builder() + .put("path.home", createTempDir()) + .put(realmSettings).build(); + final Environment env = TestEnvironment.newEnvironment(settings); + return new RealmConfig(new RealmConfig.RealmIdentifier("saml", REALM_NAME), settings, env, threadContext); } private RealmConfig realmConfigFromGlobalSettings(Settings globalSettings) { - final Settings realmSettings = globalSettings.getByPrefix(REALM_SETTINGS_PREFIX + "."); final Environment env = TestEnvironment.newEnvironment(globalSettings); - return new RealmConfig(REALM_NAME, realmSettings, globalSettings, env, new ThreadContext(globalSettings)); + return new RealmConfig(new RealmConfig.RealmIdentifier("saml", REALM_NAME), globalSettings, env, new ThreadContext(globalSettings)); } private void assertIdp1MetadataParsedCorrectly(EntityDescriptor descriptor) { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlTestCase.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlTestCase.java index 7bf13e8be265c..73982c5dfd01c 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlTestCase.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlTestCase.java @@ -11,6 +11,7 @@ import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.io.PathUtils; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.ssl.CertParsingUtils; import org.elasticsearch.xpack.core.ssl.PemUtils; @@ -135,4 +136,8 @@ protected ElasticsearchSecurityException expectSamlException(ThrowingRunnable ru assertThat("Exception " + exception + " should be a SAML exception", SamlUtils.isSamlException(exception), is(true)); return exception; } + + protected Settings mergeSettings(Settings local, Settings global) { + return Settings.builder().put(global).put(local).build(); + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealmTests.java index 6230c637b89b0..d5ed8f0dd9b82 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealmTests.java @@ -20,6 +20,7 @@ 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.CachingUsernamePasswordRealmSettings; import org.elasticsearch.xpack.core.security.authc.support.Hasher; import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken; @@ -67,15 +68,17 @@ public void testCacheSettings() throws Exception { String cachingHashAlgo = Hasher.values()[randomIntBetween(0, Hasher.values().length - 1)].name().toLowerCase(Locale.ROOT); int maxUsers = randomIntBetween(10, 100); TimeValue ttl = TimeValue.timeValueMinutes(randomIntBetween(10, 20)); + final RealmConfig.RealmIdentifier identifier = new RealmConfig.RealmIdentifier("caching", "test_realm"); Settings settings = Settings.builder() - .put(CachingUsernamePasswordRealmSettings.CACHE_HASH_ALGO_SETTING.getKey(), cachingHashAlgo) - .put(CachingUsernamePasswordRealmSettings.CACHE_MAX_USERS_SETTING.getKey(), maxUsers) - .put(CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING.getKey(), ttl) - .build(); + .put(globalSettings) + .put(RealmSettings.getFullSettingKey(identifier, CachingUsernamePasswordRealmSettings.CACHE_HASH_ALGO_SETTING), cachingHashAlgo) + .put(RealmSettings.getFullSettingKey(identifier, CachingUsernamePasswordRealmSettings.CACHE_MAX_USERS_SETTING), maxUsers) + .put(RealmSettings.getFullSettingKey(identifier, CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING), ttl) + .build(); - RealmConfig config = new RealmConfig("test_realm", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(Settings.EMPTY)); - CachingUsernamePasswordRealm realm = new CachingUsernamePasswordRealm("test", config, threadPool) { + RealmConfig config = new RealmConfig(identifier, settings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); + CachingUsernamePasswordRealm realm = new CachingUsernamePasswordRealm(config, threadPool) { @Override protected void doAuthenticate(UsernamePasswordToken token, ActionListener listener) { listener.onResponse(AuthenticationResult.success(new User("username", new String[]{"r1", "r2", "r3"}))); @@ -241,11 +244,13 @@ public void testCacheDisabledUser() { public void testCacheWithVeryLowTtlExpiresBetweenAuthenticateCalls() throws InterruptedException { TimeValue ttl = TimeValue.timeValueNanos(randomIntBetween(10, 100)); + final RealmConfig.RealmIdentifier identifier = new RealmConfig.RealmIdentifier("caching", "test_cache_ttl"); Settings settings = Settings.builder() - .put(CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING.getKey(), ttl) + .put(globalSettings) + .put(RealmSettings.getFullSettingKey(identifier, CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING), ttl) .build(); - RealmConfig config = new RealmConfig("test_cache_ttl", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = new RealmConfig(identifier, settings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); AlwaysAuthenticateCachingRealm realm = new AlwaysAuthenticateCachingRealm(config, threadPool); final UsernamePasswordToken authToken = new UsernamePasswordToken("the-user", new SecureString("the-password")); @@ -270,11 +275,13 @@ public void testCacheWithVeryLowTtlExpiresBetweenAuthenticateCalls() throws Inte public void testReadsDoNotPreventCacheExpiry() throws InterruptedException { TimeValue ttl = TimeValue.timeValueMillis(250); + final RealmConfig.RealmIdentifier identifier = new RealmConfig.RealmIdentifier("caching", "test_cache_ttl"); Settings settings = Settings.builder() - .put(CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING.getKey(), ttl) + .put(globalSettings) + .put(RealmSettings.getFullSettingKey(identifier, CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING), ttl) .build(); - RealmConfig config = new RealmConfig("test_cache_ttl", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = new RealmConfig(identifier, settings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); AlwaysAuthenticateCachingRealm realm = new AlwaysAuthenticateCachingRealm(config, threadPool); final UsernamePasswordToken authToken = new UsernamePasswordToken("the-user", new SecureString("the-password")); @@ -377,9 +384,9 @@ public void testSingleAuthPerUserLimit() throws Exception { final AtomicInteger authCounter = new AtomicInteger(0); final Hasher pwdHasher = Hasher.resolve(randomFrom("pbkdf2", "pbkdf2_1000", "bcrypt", "bcrypt9")); final String passwordHash = new String(pwdHasher.hash(password)); - RealmConfig config = new RealmConfig("test_realm", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(Settings.EMPTY)); - final CachingUsernamePasswordRealm realm = new CachingUsernamePasswordRealm("test", config, threadPool) { + RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("caching", "test_realm"), Settings.EMPTY, globalSettings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); + final CachingUsernamePasswordRealm realm = new CachingUsernamePasswordRealm(config, threadPool) { @Override protected void doAuthenticate(UsernamePasswordToken token, ActionListener listener) { authCounter.incrementAndGet(); @@ -443,9 +450,9 @@ public void testCacheConcurrency() throws Exception { final SecureString randomPassword = new SecureString(randomAlphaOfLength(password.length()).toCharArray()); final Hasher localHasher = Hasher.resolve(randomFrom("pbkdf2", "pbkdf2_1000", "bcrypt", "bcrypt9")); final String passwordHash = new String(localHasher.hash(password)); - RealmConfig config = new RealmConfig("test_realm", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(Settings.EMPTY)); - final CachingUsernamePasswordRealm realm = new CachingUsernamePasswordRealm("test", config, threadPool) { + RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("caching", "test_realm"), Settings.EMPTY, globalSettings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); + final CachingUsernamePasswordRealm realm = new CachingUsernamePasswordRealm(config, threadPool) { @Override protected void doAuthenticate(UsernamePasswordToken token, ActionListener listener) { // do something slow @@ -511,9 +518,9 @@ public void testUserLookupConcurrency() throws Exception { final String username = "username"; final AtomicInteger lookupCounter = new AtomicInteger(0); - RealmConfig config = new RealmConfig("test_realm", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(Settings.EMPTY)); - final CachingUsernamePasswordRealm realm = new CachingUsernamePasswordRealm("test", config, threadPool) { + RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("caching", "test_realm"), Settings.EMPTY, globalSettings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); + final CachingUsernamePasswordRealm realm = new CachingUsernamePasswordRealm(config, threadPool) { @Override protected void doAuthenticate(UsernamePasswordToken token, ActionListener listener) { listener.onFailure(new UnsupportedOperationException("authenticate should not be called!")); @@ -568,12 +575,14 @@ protected void doLookupUser(String username, ActionListener listener) { } public void testAuthenticateDisabled() throws Exception { + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("caching", "test_authentication_disabled"); final Settings settings = Settings.builder() - .put(CachingUsernamePasswordRealmSettings.AUTHC_ENABLED_SETTING.getKey(), false) + .put(RealmSettings.getFullSettingKey(realmId, CachingUsernamePasswordRealmSettings.AUTHC_ENABLED_SETTING), false) + .put(globalSettings) .build(); - final Environment env = TestEnvironment.newEnvironment(globalSettings); - final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - final RealmConfig config = new RealmConfig("test_authentication_disabled", settings, globalSettings, env, threadContext); + final Environment env = TestEnvironment.newEnvironment(settings); + final ThreadContext threadContext = new ThreadContext(settings); + final RealmConfig config = new RealmConfig(realmId, settings, env, threadContext); final AlwaysAuthenticateCachingRealm realm = new AlwaysAuthenticateCachingRealm(config, threadPool); final UsernamePasswordToken token = new UsernamePasswordToken("phil", new SecureString("tahiti")); @@ -597,7 +606,8 @@ public void testAuthenticateDisabled() throws Exception { static class FailingAuthenticationRealm extends CachingUsernamePasswordRealm { FailingAuthenticationRealm(Settings settings, Settings global, ThreadPool threadPool) { - super("failing", new RealmConfig("failing-test", settings, global, TestEnvironment.newEnvironment(global), + super(new RealmConfig(new RealmConfig.RealmIdentifier("caching", "failing-test"), settings, global, + TestEnvironment.newEnvironment(global), threadPool.getThreadContext()), threadPool); } @@ -615,7 +625,8 @@ protected void doLookupUser(String username, ActionListener listener) { static class ThrowingAuthenticationRealm extends CachingUsernamePasswordRealm { ThrowingAuthenticationRealm(Settings settings, Settings globalSettings, ThreadPool threadPool) { - super("throwing", new RealmConfig("throwing-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), + super(new RealmConfig(new RealmConfig.RealmIdentifier("caching", "throwing-test"), settings, globalSettings, + TestEnvironment.newEnvironment(globalSettings), threadPool.getThreadContext()), threadPool); } @@ -638,12 +649,13 @@ static class AlwaysAuthenticateCachingRealm extends CachingUsernamePasswordRealm private boolean usersEnabled = true; AlwaysAuthenticateCachingRealm(Settings globalSettings, ThreadPool threadPool) { - this(new RealmConfig("always-test", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings), + this(new RealmConfig(new RealmConfig.RealmIdentifier("caching", "always-test"), Settings.EMPTY, globalSettings, + TestEnvironment.newEnvironment(globalSettings), threadPool.getThreadContext()), threadPool); } AlwaysAuthenticateCachingRealm(RealmConfig config, ThreadPool threadPool) { - super("always", config, threadPool); + super(config, threadPool); } void setUsersEnabled(boolean usersEnabled) { @@ -670,7 +682,7 @@ static class LookupNotSupportedRealm extends CachingUsernamePasswordRealm { public final AtomicInteger lookupInvocationCounter = new AtomicInteger(0); LookupNotSupportedRealm(Settings globalSettings, ThreadPool threadPool) { - super("lookup", new RealmConfig("lookup-notsupported-test", Settings.EMPTY, globalSettings, + super(new RealmConfig(new RealmConfig.RealmIdentifier("caching", "lookup-notsupported-test"), Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings), threadPool.getThreadContext()), threadPool); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupportTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupportTests.java index 8f0d360b75975..20a8d8b27c3d1 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupportTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupportTests.java @@ -63,7 +63,12 @@ private List shuffle(List list) { } private RealmConfig buildRealmConfig(String name, Settings settings) { - return new RealmConfig(name, settings, globalSettings, env, threadContext); + return new RealmConfig(new RealmConfig.RealmIdentifier("test", name), + Settings.builder().put(settings) + .normalizePrefix("xpack.security.authc.realms.test." + name + ".") + .put(globalSettings) + .build(), + env, threadContext); } public void testEmptyDelegationList() throws ExecutionException, InterruptedException { @@ -96,13 +101,13 @@ public void testDelegationChainsAreRejected() { .build(); globalSettings = Settings.builder() .put(globalSettings) - .putList("xpack.security.authc.realms.lookup-2.authorization_realms", "lookup-1") + .putList("xpack.security.authc.realms.test.lookup-2.authorization_realms", "lookup-1") .build(); final IllegalArgumentException ex = expectThrows(IllegalArgumentException.class, () -> new DelegatedAuthorizationSupport(realms, buildRealmConfig("realm1", settings), license) ); assertThat(ex.getMessage(), - equalTo("cannot use realm [mock/lookup-2] as an authorization realm - it is already delegating authorization to [[lookup-1]]")); + equalTo("cannot use realm [test/lookup-2] as an authorization realm - it is already delegating authorization to [[lookup-1]]")); } public void testMatchInDelegationList() throws Exception { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DnRoleMapperTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DnRoleMapperTests.java index 83110c7a10a14..48465641eb4b2 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DnRoleMapperTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DnRoleMapperTests.java @@ -38,6 +38,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; @@ -50,11 +51,7 @@ public class DnRoleMapperTests extends ESTestCase { - private static final String ROLE_MAPPING_FILE_SETTING = DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING.getKey(); - private static final String USE_UNMAPPED_GROUPS_AS_ROLES_SETTING_KEY = - DnRoleMapperSettings.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING.getKey(); - - private static final String[] STARK_GROUP_DNS = new String[] { + private static final String[] STARK_GROUP_DNS = new String[]{ //groups can be named by different attributes, depending on the directory, //we don't care what it is named by "cn=shield,ou=marvel,o=superheros", @@ -181,7 +178,7 @@ public void testMapperAutoReloadWithoutListener() throws Exception { assertBusy(() -> { Set resolvedRoles = mapper.resolveRoles("", - Collections.singletonList("cn=fantastic_four,ou=marvel,o=superheros")); + Collections.singletonList("cn=fantastic_four,ou=marvel,o=superheros")); assertThat(resolvedRoles, notNullValue()); assertThat(resolvedRoles.size(), is(1)); assertThat(resolvedRoles, contains("fantastic_four")); @@ -283,11 +280,12 @@ public void testParseFileLenient_WhenCannotReadFile() throws Exception { public void testYaml() throws Exception { Path file = getDataPath("role_mapping.yml"); + final RealmConfig.RealmIdentifier realmIdentifier = new RealmConfig.RealmIdentifier("ldap", "ldap1"); Settings ldapSettings = Settings.builder() - .put(ROLE_MAPPING_FILE_SETTING, file.toAbsolutePath()) + .put(getFullSettingKey(realmIdentifier, DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING), file.toAbsolutePath()) .build(); - RealmConfig config = new RealmConfig("ldap1", ldapSettings, settings, TestEnvironment.newEnvironment(settings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = new RealmConfig(realmIdentifier, mergeSettings(ldapSettings, settings), + TestEnvironment.newEnvironment(settings), new ThreadContext(Settings.EMPTY)); DnRoleMapper mapper = new DnRoleMapper(config, new ResourceWatcherService(settings, threadPool)); @@ -298,11 +296,13 @@ public void testYaml() throws Exception { } public void testRelativeDN() { + final RealmConfig.RealmIdentifier realmIdentifier = new RealmConfig.RealmIdentifier("ldap", "ldap1"); Settings ldapSettings = Settings.builder() - .put(USE_UNMAPPED_GROUPS_AS_ROLES_SETTING_KEY, true) + .put(getFullSettingKey(realmIdentifier, DnRoleMapperSettings.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING), true) .build(); - RealmConfig config = new RealmConfig("ldap1", ldapSettings, settings, TestEnvironment.newEnvironment(settings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = new RealmConfig(realmIdentifier, + mergeSettings(ldapSettings, settings), + TestEnvironment.newEnvironment(settings), new ThreadContext(Settings.EMPTY)); DnRoleMapper mapper = new DnRoleMapper(config, new ResourceWatcherService(settings, threadPool)); @@ -311,25 +311,33 @@ public void testRelativeDN() { } public void testUserDNMapping() throws Exception { + final RealmConfig.RealmIdentifier realmIdentifier = new RealmConfig.RealmIdentifier("ldap", "ldap-userdn-role"); Path file = getDataPath("role_mapping.yml"); Settings ldapSettings = Settings.builder() - .put(ROLE_MAPPING_FILE_SETTING, file.toAbsolutePath()) - .put(USE_UNMAPPED_GROUPS_AS_ROLES_SETTING_KEY, false) + .put(getFullSettingKey(realmIdentifier, DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING), file.toAbsolutePath()) + .put(getFullSettingKey(realmIdentifier, DnRoleMapperSettings.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING), false) .build(); - RealmConfig config = new RealmConfig("ldap-userdn-role", ldapSettings, settings, TestEnvironment.newEnvironment(settings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = new RealmConfig(realmIdentifier, mergeSettings(ldapSettings, settings), + TestEnvironment.newEnvironment(settings), new ThreadContext(Settings.EMPTY)); DnRoleMapper mapper = new DnRoleMapper(config, new ResourceWatcherService(settings, threadPool)); - Set roles = mapper.resolveRoles("cn=Horatio Hornblower,ou=people,o=sevenSeas", Collections.emptyList()); + Set roles = mapper.resolveRoles("cn=Horatio Hornblower,ou=people,o=sevenSeas", Collections.emptyList()); assertThat(roles, hasItem("avenger")); } protected DnRoleMapper createMapper(Path file, ResourceWatcherService watcherService) { - Settings realmSettings = Settings.builder() - .put("files.role_mapping", file.toAbsolutePath()) + final RealmConfig.RealmIdentifier identifier = new RealmConfig.RealmIdentifier("ldap", "ad-group-mapper-test"); + Settings mergedSettings = Settings.builder() + .put(settings) + .put(getFullSettingKey(identifier, DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING), file.toAbsolutePath()) .build(); - RealmConfig config = new RealmConfig("ad-group-mapper-test", realmSettings, settings, env, new ThreadContext(Settings.EMPTY)); + RealmConfig config = new RealmConfig(identifier, mergedSettings, env, new ThreadContext(Settings.EMPTY)); return new DnRoleMapper(config, watcherService); } + + private Settings mergeSettings(Settings local, Settings global) { + return Settings.builder().put(global).put(local).build(); + } + } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/MockLookupRealm.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/MockLookupRealm.java index 01700347f5091..ddc805288d687 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/MockLookupRealm.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/MockLookupRealm.java @@ -22,7 +22,7 @@ public class MockLookupRealm extends Realm { private final Map lookup; public MockLookupRealm(RealmConfig config) { - super("mock", config); + super(config); lookup = new HashMap<>(); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/RealmUserLookupTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/RealmUserLookupTests.java index 78be4b3ddf4c7..7e0ade512bf5f 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/RealmUserLookupTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/RealmUserLookupTests.java @@ -18,6 +18,7 @@ import org.elasticsearch.xpack.core.security.authc.AuthenticationToken; import org.elasticsearch.xpack.core.security.authc.Realm; import org.elasticsearch.xpack.core.security.authc.RealmConfig; +import org.elasticsearch.xpack.core.security.authc.RealmConfig.RealmIdentifier; import org.elasticsearch.xpack.core.security.user.User; import org.junit.Before; @@ -84,7 +85,7 @@ public void testUserNotFound() throws Exception { } public void testRealmException() { - final Realm realm = new Realm("test", new RealmConfig("test", Settings.EMPTY, globalSettings, env, threadContext)) { + final Realm realm = new Realm(new RealmConfig(new RealmIdentifier("test", "test"), globalSettings, env, threadContext)) { @Override public boolean supports(AuthenticationToken token) { return false; @@ -115,7 +116,7 @@ public void lookupUser(String username, ActionListener listener) { private List buildRealms(int realmCount) { final List realms = new ArrayList<>(realmCount); for (int i = 1; i <= realmCount; i++) { - final RealmConfig config = new RealmConfig("lookup-" + i, Settings.EMPTY, globalSettings, env, threadContext); + final RealmConfig config = new RealmConfig(new RealmIdentifier("mock","lookup-" + i), globalSettings, env, threadContext); final MockLookupRealm realm = new MockLookupRealm(config); for (int j = 0; j < 5; j++) { realm.registerUser(new User(randomAlphaOfLengthBetween(6, 12))); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/RoleMappingFileBootstrapCheckTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/RoleMappingFileBootstrapCheckTests.java index e0f71c40607ee..d84213726381d 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/RoleMappingFileBootstrapCheckTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/RoleMappingFileBootstrapCheckTests.java @@ -5,12 +5,6 @@ */ package org.elasticsearch.xpack.security.authc.support; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; - import org.elasticsearch.bootstrap.BootstrapCheck; import org.elasticsearch.bootstrap.BootstrapContext; import org.elasticsearch.common.settings.Settings; @@ -18,16 +12,25 @@ 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.support.DnRoleMapperSettings; import org.junit.Before; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; + import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.notNullValue; public class RoleMappingFileBootstrapCheckTests extends ESTestCase { - private static final String ROLE_MAPPING_FILE_SETTING = DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING.getKey(); + private static final RealmConfig.RealmIdentifier REALM_ID = new RealmConfig.RealmIdentifier("ldap", "ldap-realm-name"); + private static final String ROLE_MAPPING_FILE_SETTING = RealmSettings.getFullSettingKey( + REALM_ID, DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING); protected Settings settings; @@ -44,28 +47,31 @@ public void testBootstrapCheckOfValidFile() { Settings ldapSettings = Settings.builder() .put(ROLE_MAPPING_FILE_SETTING, file.toAbsolutePath()) .build(); - RealmConfig config = new RealmConfig("ldap1", ldapSettings, settings, TestEnvironment.newEnvironment(settings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = getRealmConfig(ldapSettings); final BootstrapCheck check = RoleMappingFileBootstrapCheck.create(config); assertThat(check, notNullValue()); assertThat(check.alwaysEnforce(), equalTo(true)); assertFalse(check.check(new BootstrapContext(settings, null)).isFailure()); } + private RealmConfig getRealmConfig(Settings realmSettings) { + return new RealmConfig(REALM_ID, mergeSettings(realmSettings, settings), + TestEnvironment.newEnvironment(settings), new ThreadContext(Settings.EMPTY)); + } + public void testBootstrapCheckOfMissingFile() { final String fileName = randomAlphaOfLength(10); Path file = createTempDir().resolve(fileName); Settings ldapSettings = Settings.builder() .put(ROLE_MAPPING_FILE_SETTING, file.toAbsolutePath()) .build(); - RealmConfig config = new RealmConfig("the-realm-name", ldapSettings, settings, TestEnvironment.newEnvironment(settings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = getRealmConfig(ldapSettings); final BootstrapCheck check = RoleMappingFileBootstrapCheck.create(config); assertThat(check, notNullValue()); assertThat(check.alwaysEnforce(), equalTo(true)); final BootstrapCheck.BootstrapCheckResult result = check.check(new BootstrapContext(settings, null)); assertTrue(result.isFailure()); - assertThat(result.getMessage(), containsString("the-realm-name")); + assertThat(result.getMessage(), containsString(REALM_ID.getName())); assertThat(result.getMessage(), containsString(fileName)); assertThat(result.getMessage(), containsString("does not exist")); } @@ -78,14 +84,13 @@ public void testBootstrapCheckWithInvalidYaml() throws IOException { Settings ldapSettings = Settings.builder() .put(ROLE_MAPPING_FILE_SETTING, file.toAbsolutePath()) .build(); - RealmConfig config = new RealmConfig("the-realm-name", ldapSettings, settings, TestEnvironment.newEnvironment(settings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = getRealmConfig(ldapSettings); final BootstrapCheck check = RoleMappingFileBootstrapCheck.create(config); assertThat(check, notNullValue()); assertThat(check.alwaysEnforce(), equalTo(true)); final BootstrapCheck.BootstrapCheckResult result = check.check(new BootstrapContext(settings, null)); assertTrue(result.isFailure()); - assertThat(result.getMessage(), containsString("the-realm-name")); + assertThat(result.getMessage(), containsString(REALM_ID.getName())); assertThat(result.getMessage(), containsString(file.toString())); assertThat(result.getMessage(), containsString("could not read")); } @@ -98,16 +103,19 @@ public void testBootstrapCheckWithInvalidDn() throws IOException { Settings ldapSettings = Settings.builder() .put(ROLE_MAPPING_FILE_SETTING, file.toAbsolutePath()) .build(); - RealmConfig config = new RealmConfig("the-realm-name", ldapSettings, settings, TestEnvironment.newEnvironment(settings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = getRealmConfig(ldapSettings); final BootstrapCheck check = RoleMappingFileBootstrapCheck.create(config); assertThat(check, notNullValue()); assertThat(check.alwaysEnforce(), equalTo(true)); final BootstrapCheck.BootstrapCheckResult result = check.check(new BootstrapContext(settings, null)); assertTrue(result.isFailure()); - assertThat(result.getMessage(), containsString("the-realm-name")); + assertThat(result.getMessage(), containsString(REALM_ID.getName())); assertThat(result.getMessage(), containsString(file.toString())); assertThat(result.getMessage(), containsString("invalid DN")); assertThat(result.getMessage(), containsString("not-a-dn")); } + + private Settings mergeSettings(Settings local, Settings global) { + return Settings.builder().put(global).put(local).build(); + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/ExpressionRoleMappingTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/ExpressionRoleMappingTests.java index 2ac82c8d7c063..d8785b8a72fa6 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/ExpressionRoleMappingTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/ExpressionRoleMappingTests.java @@ -38,8 +38,8 @@ public class ExpressionRoleMappingTests extends ESTestCase { @Before public void setupMapping() throws Exception { - realm = new RealmConfig("ldap1", Settings.EMPTY, Settings.EMPTY, Mockito.mock(Environment.class), - new ThreadContext(Settings.EMPTY)); + realm = new RealmConfig(new RealmConfig.RealmIdentifier("ldap", "ldap1"), + Settings.EMPTY, Settings.EMPTY, Mockito.mock(Environment.class), new ThreadContext(Settings.EMPTY)); } public void testParseValidJson() throws Exception { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java index 052ba38551021..0c9ea5c6de28f 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java @@ -84,8 +84,8 @@ protected void loadMappings(ActionListener> listener } }; - final RealmConfig realm = new RealmConfig("ldap1", Settings.EMPTY, Settings.EMPTY, mock(Environment.class), - new ThreadContext(Settings.EMPTY)); + final RealmConfig realm = new RealmConfig(new RealmConfig.RealmIdentifier("ldap", "ldap1"), Settings.EMPTY, Settings.EMPTY, + mock(Environment.class), new ThreadContext(Settings.EMPTY)); final PlainActionFuture> future = new PlainActionFuture<>(); final UserRoleMapper.UserData user = new UserRoleMapper.UserData("sasquatch", @@ -197,8 +197,9 @@ private NativeRoleMappingStore buildRoleMappingStoreForInvalidationTesting(Atomi }).when(client).execute(eq(ClearRealmCacheAction.INSTANCE), any(ClearRealmCacheRequest.class), any(ActionListener.class)); final Environment env = TestEnvironment.newEnvironment(settings); - final RealmConfig realmConfig = new RealmConfig(getTestName(), Settings.EMPTY, settings, env, threadContext); - final CachingUsernamePasswordRealm mockRealm = new CachingUsernamePasswordRealm("test", realmConfig, threadPool) { + final RealmConfig realmConfig = new RealmConfig(new RealmConfig.RealmIdentifier("ldap", getTestName()), Settings.EMPTY, + settings, env, threadContext); + final CachingUsernamePasswordRealm mockRealm = new CachingUsernamePasswordRealm(realmConfig, threadPool) { @Override protected void doAuthenticate(UsernamePasswordToken token, ActionListener listener) { listener.onResponse(AuthenticationResult.notHandled()); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java index 6ff18cc77a1e2..3e4fbee5197b5 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java @@ -32,7 +32,6 @@ import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.security.SecurityField; -import org.elasticsearch.xpack.core.security.authc.file.FileRealmSettings; import org.elasticsearch.xpack.core.ssl.SSLClientAuth; import org.elasticsearch.xpack.security.LocalStateSecurity; import org.junit.BeforeClass; @@ -139,8 +138,7 @@ public void testThatConnectionToClientTypeConnectionIsRejected() throws IOExcept // test that starting up a node works Settings.Builder nodeSettings = Settings.builder() - .put("xpack.security.authc.realms.file.type", FileRealmSettings.TYPE) - .put("xpack.security.authc.realms.file.order", 0) + .put("xpack.security.authc.realms.file.file.order", 0) .put("node.name", "my-test-node") .put(SecurityField.USER_SETTING.getKey(), "test_user:" + SecuritySettingsSourceField.TEST_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) diff --git a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTestCase.java b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTestCase.java index e2a34f8ed0919..5011aa1d307f1 100644 --- a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTestCase.java +++ b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTestCase.java @@ -10,13 +10,17 @@ import org.apache.logging.log4j.Logger; import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.common.Randomness; +import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import javax.security.auth.Subject; import java.io.IOException; import java.nio.file.Path; import java.security.AccessController; @@ -28,8 +32,6 @@ import java.util.Locale; import java.util.Set; -import javax.security.auth.Subject; - /** * Base Test class for Kerberos. *

@@ -41,6 +43,8 @@ */ public abstract class KerberosTestCase extends ESTestCase { + protected static final String REALM_NAME = "test-kerb-realm"; + protected Settings globalSettings; protected Settings settings; protected List serviceUserNames; @@ -51,6 +55,7 @@ public abstract class KerberosTestCase extends ESTestCase { private static Locale restoreLocale; private static Set unsupportedLocaleLanguages; + static { unsupportedLocaleLanguages = new HashSet<>(); /* @@ -84,7 +89,7 @@ public static void setupKerberos() throws Exception { if (isLocaleUnsupported()) { Logger logger = LogManager.getLogger(KerberosTestCase.class); logger.warn("Attempting to run Kerberos test on {} locale, but that breaks SimpleKdcServer. Switching to English.", - Locale.getDefault()); + Locale.getDefault()); restoreLocale = Locale.getDefault(); Locale.setDefault(Locale.ENGLISH); } @@ -126,7 +131,7 @@ public void startSimpleKdcLdapServer() throws Exception { throw ExceptionsHelper.convertToRuntime(e); } }); - settings = KerberosRealmTestCase.buildKerberosRealmSettings(ktabPathForService.toString()); + settings = KerberosRealmTestCase.buildKerberosRealmSettings(REALM_NAME, ktabPathForService.toString()); } @After @@ -136,10 +141,15 @@ public void tearDownMiniKdc() throws IOException, PrivilegedActionException { } } + protected Path getKeytabPath(Environment env) { + final Setting setting = KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.getConcreteSettingForNamespace(REALM_NAME); + return env.configFile().resolve(setting.get(settings)); + } + /** * Creates principals and exports them to the keytab created in the directory. * - * @param dir Directory where the key tab would be created. + * @param dir Directory where the key tab would be created. * @param princNames principal names to be created * @return {@link Path} to key tab file. * @throws Exception thrown if principal or keytab could not be created @@ -154,7 +164,7 @@ protected Path createPrincipalKeyTab(final Path dir, final String... princNames) * Creates principal with given name and password. * * @param principalName Principal name - * @param password Password + * @param password Password * @throws Exception thrown if principal could not be created */ protected void createPrincipal(final String principalName, final char[] password) throws Exception { @@ -175,8 +185,8 @@ protected String principalName(final String user) { * Invokes Subject.doAs inside a doPrivileged block * * @param subject {@link Subject} - * @param action {@link PrivilegedExceptionAction} action for performing inside - * Subject.doAs + * @param action {@link PrivilegedExceptionAction} action for performing inside + * Subject.doAs * @return T Type of value as returned by PrivilegedAction * @throws PrivilegedActionException when privileged action threw exception */ diff --git a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidatorTests.java b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidatorTests.java index 340d05ce35e0f..53d7b38a33986 100644 --- a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidatorTests.java +++ b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidatorTests.java @@ -13,17 +13,15 @@ import org.elasticsearch.common.util.concurrent.UncategorizedExecutionException; import org.elasticsearch.env.Environment; import org.elasticsearch.env.TestEnvironment; -import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings; import org.ietf.jgss.GSSException; +import javax.security.auth.login.LoginException; import java.io.IOException; import java.nio.file.Path; import java.security.PrivilegedActionException; import java.util.Base64; import java.util.concurrent.ExecutionException; -import javax.security.auth.login.LoginException; - import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; @@ -40,12 +38,12 @@ public void testKerbTicketGeneratedForDifferentServerFailsValidation() throws Ex // Client login and init token preparation final String clientUserName = randomFrom(clientUserNames); try (SpnegoClient spnegoClient = - new SpnegoClient(principalName(clientUserName), new SecureString("pwd".toCharArray()), principalName("differentServer"));) { + new SpnegoClient(principalName(clientUserName), new SecureString("pwd".toCharArray()), principalName("differentServer"))) { final String base64KerbToken = spnegoClient.getBase64EncodedTokenForSpnegoHeader(); assertThat(base64KerbToken, is(notNullValue())); final Environment env = TestEnvironment.newEnvironment(globalSettings); - final Path keytabPath = env.configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(settings)); + final Path keytabPath = getKeytabPath(env); final PlainActionFuture> future = new PlainActionFuture<>(); kerberosTicketValidator.validateTicket(Base64.getDecoder().decode(base64KerbToken), keytabPath, true, future); final GSSException gssException = expectThrows(GSSException.class, () -> unwrapExpectedExceptionFromFutureAndThrow(future)); @@ -57,7 +55,7 @@ public void testInvalidKerbTicketFailsValidation() throws Exception { final String base64KerbToken = Base64.getEncoder().encodeToString(randomByteArrayOfLength(5)); final Environment env = TestEnvironment.newEnvironment(globalSettings); - final Path keytabPath = env.configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(settings)); + final Path keytabPath = getKeytabPath(env); kerberosTicketValidator.validateTicket(Base64.getDecoder().decode(base64KerbToken), keytabPath, true, new ActionListener>() { boolean exceptionHandled = false; @@ -87,9 +85,9 @@ public void testWhenKeyTabWithInvalidContentFailsValidation() assertThat(base64KerbToken, is(notNullValue())); final Path ktabPath = KerberosRealmTestCase.writeKeyTab(workDir.resolve("invalid.keytab"), "not - a - valid - key - tab"); - settings = KerberosRealmTestCase.buildKerberosRealmSettings(ktabPath.toString()); + settings = KerberosRealmTestCase.buildKerberosRealmSettings(REALM_NAME, ktabPath.toString()); final Environment env = TestEnvironment.newEnvironment(globalSettings); - final Path keytabPath = env.configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(settings)); + final Path keytabPath = getKeytabPath(env); final PlainActionFuture> future = new PlainActionFuture<>(); kerberosTicketValidator.validateTicket(Base64.getDecoder().decode(base64KerbToken), keytabPath, true, future); final GSSException gssException = expectThrows(GSSException.class, () -> unwrapExpectedExceptionFromFutureAndThrow(future)); @@ -100,13 +98,14 @@ public void testWhenKeyTabWithInvalidContentFailsValidation() public void testValidKebrerosTicket() throws PrivilegedActionException, GSSException, LoginException { // Client login and init token preparation final String clientUserName = randomFrom(clientUserNames); - try (SpnegoClient spnegoClient = new SpnegoClient(principalName(clientUserName), new SecureString("pwd".toCharArray()), - principalName(randomFrom(serviceUserNames)));) { + final SecureString password = new SecureString("pwd".toCharArray()); + final String servicePrincipalName = principalName(randomFrom(serviceUserNames)); + try (SpnegoClient spnegoClient = new SpnegoClient(principalName(clientUserName), password, servicePrincipalName)) { final String base64KerbToken = spnegoClient.getBase64EncodedTokenForSpnegoHeader(); assertThat(base64KerbToken, is(notNullValue())); final Environment env = TestEnvironment.newEnvironment(globalSettings); - final Path keytabPath = env.configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(settings)); + final Path keytabPath = getKeytabPath(env); final PlainActionFuture> future = new PlainActionFuture<>(); kerberosTicketValidator.validateTicket(Base64.getDecoder().decode(base64KerbToken), keytabPath, true, future); assertThat(future.actionGet(), is(notNullValue())); diff --git a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SimpleKdcLdapServerTests.java b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SimpleKdcLdapServerTests.java index b1c75d957a7c8..6d9aae49a483d 100644 --- a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SimpleKdcLdapServerTests.java +++ b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SimpleKdcLdapServerTests.java @@ -15,9 +15,6 @@ import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.env.Environment; import org.elasticsearch.env.TestEnvironment; -import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings; -import org.elasticsearch.xpack.security.authc.kerberos.KerberosAuthenticationToken; -import org.elasticsearch.xpack.security.authc.kerberos.KerberosTicketValidator; import org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils; import org.ietf.jgss.GSSException; @@ -61,7 +58,7 @@ public void testClientServiceMutualAuthentication() throws PrivilegedActionExcep // Service Login final Environment env = TestEnvironment.newEnvironment(globalSettings); - final Path keytabPath = env.configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(settings)); + final Path keytabPath = getKeytabPath(env); // Handle Authz header which contains base64 token final PlainActionFuture> future = new PlainActionFuture<>(); new KerberosTicketValidator().validateTicket((byte[]) kerbAuthnToken.credentials(), keytabPath, true, future); diff --git a/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/test/OpenLdapTests.java b/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/test/OpenLdapTests.java index f96823df019a5..9abac404cea14 100644 --- a/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/test/OpenLdapTests.java +++ b/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/test/OpenLdapTests.java @@ -19,8 +19,11 @@ 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.ldap.SearchGroupsResolverSettings; +import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapMetaDataResolverSettings; 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.SSLConfigurationSettings; import org.elasticsearch.xpack.core.ssl.SSLService; import org.elasticsearch.xpack.core.ssl.VerificationMode; import org.elasticsearch.xpack.security.authc.ldap.LdapSessionFactory; @@ -37,6 +40,7 @@ import java.util.Map; import java.util.concurrent.ExecutionException; +import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsString; @@ -93,23 +97,23 @@ public void initializeSslSocketFactory() throws Exception { mockSecureSettings.setString("xpack.ssl.truststore.secure_password", "changeit"); // configure realm to load config with certificate verification mode - builder.put("xpack.security.authc.realms." + REALM_NAME + ".ssl.truststore.path", truststore); - mockSecureSettings.setString("xpack.security.authc.realms." + REALM_NAME + ".ssl.truststore.secure_password", "changeit"); - builder.put("xpack.security.authc.realms." + REALM_NAME + ".ssl.verification_mode", VerificationMode.CERTIFICATE); + builder.put("xpack.security.authc.realms.ldap." + REALM_NAME + ".ssl.truststore.path", truststore); + mockSecureSettings.setString("xpack.security.authc.realms.ldap." + REALM_NAME + ".ssl.truststore.secure_password", "changeit"); + builder.put("xpack.security.authc.realms.ldap." + REALM_NAME + ".ssl.verification_mode", VerificationMode.CERTIFICATE); } else { // fake realms so ssl will get loaded - builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", truststore); - mockSecureSettings.setString("xpack.security.authc.realms.foo.ssl.truststore.secure_password", "changeit"); - builder.put("xpack.security.authc.realms.foo.ssl.verification_mode", VerificationMode.FULL); - builder.put("xpack.security.authc.realms." + REALM_NAME + ".ssl.truststore.path", truststore); - mockSecureSettings.setString("xpack.security.authc.realms." + REALM_NAME + ".ssl.truststore.secure_password", "changeit"); - builder.put("xpack.security.authc.realms." + REALM_NAME + ".ssl.verification_mode", VerificationMode.CERTIFICATE); + builder.put("xpack.security.authc.realms.ldap.foo.ssl.truststore.path", truststore); + mockSecureSettings.setString("xpack.security.authc.realms.ldap.foo.ssl.truststore.secure_password", "changeit"); + builder.put("xpack.security.authc.realms.ldap.foo.ssl.verification_mode", VerificationMode.FULL); + builder.put("xpack.security.authc.realms.ldap." + REALM_NAME + ".ssl.truststore.path", truststore); + mockSecureSettings.setString("xpack.security.authc.realms.ldap." + REALM_NAME + ".ssl.truststore.secure_password", "changeit"); + builder.put("xpack.security.authc.realms.ldap." + REALM_NAME + ".ssl.verification_mode", VerificationMode.CERTIFICATE); // If not using global ssl, need to set the truststore for the "full verification" realm - builder.put("xpack.security.authc.realms.vmode_full.ssl.truststore.path", truststore); - mockSecureSettings.setString("xpack.security.authc.realms.vmode_full.ssl.truststore.secure_password", "changeit"); + builder.put("xpack.security.authc.realms.ldap.vmode_full.ssl.truststore.path", truststore); + mockSecureSettings.setString("xpack.security.authc.realms.ldap.vmode_full.ssl.truststore.secure_password", "changeit"); } - builder.put("xpack.security.authc.realms.vmode_full.ssl.verification_mode", VerificationMode.FULL); + builder.put("xpack.security.authc.realms.ldap.vmode_full.ssl.verification_mode", VerificationMode.FULL); globalSettings = builder.setSecureSettings(mockSecureSettings).build(); Environment environment = TestEnvironment.newEnvironment(globalSettings); @@ -120,12 +124,13 @@ public void testConnect() throws Exception { //openldap does not use cn as naming attributes by default String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; - RealmConfig config = new RealmConfig("oldap-test", buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, - LdapSearchScope.ONE_LEVEL), globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(Settings.EMPTY)); + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "oldap-test"); + RealmConfig config = new RealmConfig(realmId, + buildLdapSettings(realmId, OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL), + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool); - String[] users = new String[] { "blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor" }; + String[] users = new String[]{"blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor"}; for (String user : users) { logger.info("testing connect as user [{}]", user); try (LdapSession ldap = session(sessionFactory, user, PASSWORD_SECURE_STRING)) { @@ -139,11 +144,13 @@ public void testGroupSearchScopeBase() throws Exception { String groupSearchBase = "cn=Avengers,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; - RealmConfig config = new RealmConfig(REALM_NAME, buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, - LdapSearchScope.BASE), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", REALM_NAME); + RealmConfig config = new RealmConfig(realmId, + buildLdapSettings(realmId, OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.BASE), + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool); - String[] users = new String[] { "blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor" }; + String[] users = new String[]{"blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor"}; for (String user : users) { try (LdapSession ldap = session(sessionFactory, user, PASSWORD_SECURE_STRING)) { assertThat(groups(ldap), hasItem(containsString("Avengers"))); @@ -154,13 +161,14 @@ public void testGroupSearchScopeBase() throws Exception { public void testCustomFilter() throws Exception { String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "oldap-test"); Settings settings = Settings.builder() - .put(buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL)) - .put("group_search.filter", "(&(objectclass=posixGroup)(memberUid={0}))") - .put("group_search.user_attribute", "uid") + .put(buildLdapSettings(realmId, OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL)) + .put(getFullSettingKey(realmId.getName(), SearchGroupsResolverSettings.FILTER), "(&(objectclass=posixGroup)(memberUid={0}))") + .put(getFullSettingKey(realmId.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "uid") .build(); - RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = new RealmConfig(realmId, settings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool); try (LdapSession ldap = session(sessionFactory, "selvig", PASSWORD_SECURE_STRING)) { @@ -170,16 +178,17 @@ public void testCustomFilter() throws Exception { @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/29758") public void testTcpTimeout() throws Exception { + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "oldap-test"); String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; Settings settings = Settings.builder() - .put(buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE)) - .put("group_search.filter", "(objectClass=*)") - .put("ssl.verification_mode", VerificationMode.CERTIFICATE) - .put(SessionFactorySettings.TIMEOUT_TCP_READ_SETTING, "1ms") //1 millisecond + .put(buildLdapSettings(realmId, OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE)) + .put(getFullSettingKey(realmId.getName(), SearchGroupsResolverSettings.FILTER), "(objectClass=*)") + .put(getFullSettingKey(realmId, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), VerificationMode.CERTIFICATE) + .put(getFullSettingKey(realmId, SessionFactorySettings.TIMEOUT_TCP_READ_SETTING), "1ms") .build(); - RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = new RealmConfig(realmId, settings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool); LDAPException expected = expectThrows(LDAPException.class, @@ -191,14 +200,13 @@ public void testStandardLdapConnectionHostnameVerificationFailure() throws Excep //openldap does not use cn as naming attributes by default String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "vmode_full"); Settings settings = Settings.builder() // The certificate used in the vagrant box is valid for "localhost", but not for "127.0.0.1" - .put(buildLdapSettings(OPEN_LDAP_IP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL)) + .put(buildLdapSettings(realmId, OPEN_LDAP_IP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL)) .build(); - - // Pick up the "full" verification mode config - RealmConfig config = new RealmConfig("vmode_full", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(Settings.EMPTY)); + final Environment env = TestEnvironment.newEnvironment(globalSettings); + RealmConfig config = new RealmConfig(realmId, settings, env, new ThreadContext(Settings.EMPTY)); LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool); String user = "blackwidow"; @@ -214,14 +222,14 @@ public void testStandardLdapConnectionHostnameVerificationSuccess() throws Excep //openldap does not use cn as naming attributes by default String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "vmode_full"); Settings settings = Settings.builder() // The certificate used in the vagrant box is valid for "localhost" (but not for "127.0.0.1") - .put(buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL)) + .put(buildLdapSettings(realmId, OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL)) .build(); - // Pick up the "full" verification mode config - RealmConfig config = new RealmConfig("vmode_full", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(Settings.EMPTY)); + RealmConfig config = new RealmConfig(realmId, settings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool); final String user = "blackwidow"; @@ -232,7 +240,13 @@ public void testStandardLdapConnectionHostnameVerificationSuccess() throws Excep } public void testResolveSingleValuedAttributeFromConnection() throws Exception { - LdapMetaDataResolver resolver = new LdapMetaDataResolver(Settings.builder().putList("metadata", "cn", "sn").build(), true); + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "oldap-test"); + final Settings settings = Settings.builder() + .putList(getFullSettingKey(realmId.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING), "cn", "sn") + .build(); + final RealmConfig config = new RealmConfig(realmId, settings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); + LdapMetaDataResolver resolver = new LdapMetaDataResolver(config, true); try (LDAPConnection ldapConnection = setupOpenLdapConnection()) { final Map map = resolve(ldapConnection, resolver); assertThat(map.size(), equalTo(2)); @@ -242,7 +256,13 @@ public void testResolveSingleValuedAttributeFromConnection() throws Exception { } public void testResolveMultiValuedAttributeFromConnection() throws Exception { - LdapMetaDataResolver resolver = new LdapMetaDataResolver(Settings.builder().putList("metadata", "objectClass").build(), true); + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "oldap-test"); + final Settings settings = Settings.builder() + .putList(getFullSettingKey(realmId.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING), "objectClass") + .build(); + final RealmConfig config = new RealmConfig(realmId, settings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); + LdapMetaDataResolver resolver = new LdapMetaDataResolver(config, true); try (LDAPConnection ldapConnection = setupOpenLdapConnection()) { final Map map = resolve(ldapConnection, resolver); assertThat(map.size(), equalTo(1)); @@ -252,23 +272,33 @@ public void testResolveMultiValuedAttributeFromConnection() throws Exception { } public void testResolveMissingAttributeFromConnection() throws Exception { - LdapMetaDataResolver resolver = new LdapMetaDataResolver(Settings.builder().putList("metadata", "alias").build(), true); + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "oldap-test"); + final Settings settings = Settings.builder() + .putList(getFullSettingKey(realmId.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING), "alias") + .build(); + final RealmConfig config = new RealmConfig(realmId, settings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY)); + LdapMetaDataResolver resolver = new LdapMetaDataResolver(config, true); try (LDAPConnection ldapConnection = setupOpenLdapConnection()) { final Map map = resolve(ldapConnection, resolver); assertThat(map.size(), equalTo(0)); } } - private Settings buildLdapSettings(String ldapUrl, String userTemplate, String groupSearchBase, LdapSearchScope scope) { + private Settings buildLdapSettings(RealmConfig.RealmIdentifier realmId, String ldapUrl, String userTemplate, + String groupSearchBase, LdapSearchScope scope) { + final String[] urls = {ldapUrl}; + final String[] templates = {userTemplate}; Settings.Builder builder = Settings.builder() - .put(LdapTestCase.buildLdapSettings(ldapUrl, userTemplate, groupSearchBase, scope)); - builder.put("group_search.user_attribute", "uid"); + .put(LdapTestCase.buildLdapSettings(realmId, urls, templates, groupSearchBase, scope, null, false)); + builder.put(getFullSettingKey(realmId.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "uid"); if (useGlobalSSL) { return builder.build(); } return builder - .put("ssl.truststore.path", getDataPath(LDAPTRUST_PATH)) - .put("ssl.truststore.password", "changeit") + .put(getFullSettingKey(realmId, SSLConfigurationSettings.TRUST_STORE_PATH_REALM), getDataPath(LDAPTRUST_PATH)) + .put(getFullSettingKey(realmId, SSLConfigurationSettings.LEGACY_TRUST_STORE_PASSWORD_REALM), "changeit") + .put(globalSettings) .build(); } diff --git a/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapUserSearchSessionFactoryTests.java b/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapUserSearchSessionFactoryTests.java index 42c2d9cd07e7f..5030fdecadf64 100644 --- a/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapUserSearchSessionFactoryTests.java +++ b/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapUserSearchSessionFactoryTests.java @@ -19,8 +19,11 @@ 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.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.ssl.SSLConfigurationSettings; import org.elasticsearch.xpack.core.ssl.SSLService; import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession; import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase; @@ -34,6 +37,7 @@ import java.util.Locale; import java.util.Objects; +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.hasItem; @@ -70,34 +74,29 @@ public void testUserSearchWithBindUserOpenLDAP() throws Exception { final boolean useSecureBindPassword = randomBoolean(); String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; String userSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; + final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "oldap-test"); final Settings.Builder realmSettings = Settings.builder() - .put(LdapTestCase.buildLdapSettings(new String[]{OpenLdapTests.OPEN_LDAP_DNS_URL}, Strings.EMPTY_ARRAY, groupSearchBase, - LdapSearchScope.ONE_LEVEL)) - .put("user_search.base_dn", userSearchBase) - .put("group_search.user_attribute", "uid") - .put("bind_dn", "uid=blackwidow,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com") - .put("user_search.pool.enabled", randomBoolean()) - .put("ssl.verification_mode", "full"); + .put(LdapTestCase.buildLdapSettings(realmId, new String[]{OpenLdapTests.OPEN_LDAP_DNS_URL}, Strings.EMPTY_ARRAY, + groupSearchBase, LdapSearchScope.ONE_LEVEL, null, false)) + .put(getFullSettingKey(realmId.getName(), LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN), userSearchBase) + .put(getFullSettingKey(realmId.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "uid") + .put(getFullSettingKey(realmId, PoolingSessionFactorySettings.BIND_DN), + "uid=blackwidow,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com") + .put(getFullSettingKey(realmId.getName(), LdapUserSearchSessionFactorySettings.POOL_ENABLED), randomBoolean()) + .put(getFullSettingKey(realmId, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), "full"); if (useSecureBindPassword) { final MockSecureSettings secureSettings = new MockSecureSettings(); - secureSettings.setString("secure_bind_password", OpenLdapTests.PASSWORD); + secureSettings.setString(getFullSettingKey(realmId, PoolingSessionFactorySettings.SECURE_BIND_PASSWORD), + OpenLdapTests.PASSWORD); realmSettings.setSecureSettings(secureSettings); } else { - realmSettings.put("bind_password", OpenLdapTests.PASSWORD); + realmSettings.put(getFullSettingKey(realmId, PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD), OpenLdapTests.PASSWORD); } - RealmConfig config = new RealmConfig("oldap-test", realmSettings.build(), globalSettings, + final Settings settings = realmSettings.put(globalSettings).build(); + RealmConfig config = new RealmConfig(realmId, settings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)); - Settings.Builder builder = Settings.builder() - .put(globalSettings, false); - builder.put(Settings.builder().put(config.settings(), false).normalizePrefix("xpack.security.authc.realms.oldap-test.").build()); - final MockSecureSettings secureSettings = new MockSecureSettings(); - if (useSecureBindPassword) { - secureSettings.setString("xpack.security.authc.realms.oldap-test.secure_bind_password", OpenLdapTests.PASSWORD); - } - builder.setSecureSettings(secureSettings); - Settings settings = builder.build(); - SSLService sslService = new SSLService(settings, TestEnvironment.newEnvironment(settings)); + SSLService sslService = new SSLService(settings, TestEnvironment.newEnvironment(settings)); String[] users = new String[]{"cap", "hawkeye", "hulk", "ironman", "thor"}; try (LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService, threadPool)) { @@ -119,7 +118,9 @@ public void testUserSearchWithBindUserOpenLDAP() throws Exception { } if (useSecureBindPassword == false) { - assertSettingDeprecationsAndWarnings(new Setting[]{PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD}); + assertSettingDeprecationsAndWarnings(new Setting[]{ + config.getConcreteSetting(PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD) + }); } } diff --git a/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolverTests.java b/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolverTests.java index b55431dee1b00..98794dd4f705c 100644 --- a/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolverTests.java +++ b/x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/xpack/security/authc/ldap/SearchGroupsResolverTests.java @@ -9,11 +9,14 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.test.OpenLdapTests; +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.core.security.support.NoOpLogger; import java.util.List; +import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasItem; @@ -24,14 +27,15 @@ public class SearchGroupsResolverTests extends GroupsResolverTestCase { private static final String BRUCE_BANNER_DN = "uid=hulk,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; + private static final RealmConfig.RealmIdentifier REALM_ID = new RealmConfig.RealmIdentifier("ldap", "my-ldap-realm"); public void testResolveSubTree() throws Exception { Settings settings = Settings.builder() - .put("group_search.base_dn", "dc=oldap,dc=test,dc=elasticsearch,dc=com") - .put("group_search.user_attribute", "uid") + .put(getFullSettingKey(REALM_ID, SearchGroupsResolverSettings.BASE_DN), "dc=oldap,dc=test,dc=elasticsearch,dc=com") + .put(getFullSettingKey(REALM_ID.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "uid") .build(); - SearchGroupsResolver resolver = new SearchGroupsResolver(settings); + SearchGroupsResolver resolver = new SearchGroupsResolver(config(REALM_ID, settings)); List groups = resolveBlocking(resolver, ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(10), NoOpLogger.INSTANCE, null); assertThat(groups, containsInAnyOrder( @@ -43,12 +47,13 @@ public void testResolveSubTree() throws Exception { public void testResolveOneLevel() throws Exception { Settings settings = Settings.builder() - .put("group_search.base_dn", "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com") + .put(getFullSettingKey(REALM_ID, SearchGroupsResolverSettings.BASE_DN), + "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com") .put("group_search.scope", LdapSearchScope.ONE_LEVEL) - .put("group_search.user_attribute", "uid") + .put(getFullSettingKey(REALM_ID.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "uid") .build(); - SearchGroupsResolver resolver = new SearchGroupsResolver(settings); + SearchGroupsResolver resolver = new SearchGroupsResolver(config(REALM_ID, settings)); List groups = resolveBlocking(resolver, ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(10), NoOpLogger.INSTANCE, null); assertThat(groups, containsInAnyOrder( @@ -60,12 +65,13 @@ public void testResolveOneLevel() throws Exception { public void testResolveBase() throws Exception { Settings settings = Settings.builder() - .put("group_search.base_dn", "cn=Avengers,ou=People,dc=oldap,dc=test,dc=elasticsearch,dc=com") + .put(getFullSettingKey(REALM_ID, SearchGroupsResolverSettings.BASE_DN), + "cn=Avengers,ou=People,dc=oldap,dc=test,dc=elasticsearch,dc=com") .put("group_search.scope", LdapSearchScope.BASE) - .put("group_search.user_attribute", "uid") + .put(getFullSettingKey(REALM_ID.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "uid") .build(); - SearchGroupsResolver resolver = new SearchGroupsResolver(settings); + SearchGroupsResolver resolver = new SearchGroupsResolver(config(REALM_ID, settings)); List groups = resolveBlocking(resolver, ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(10), NoOpLogger.INSTANCE, null); assertThat(groups, hasItem(containsString("Avengers"))); @@ -73,28 +79,28 @@ public void testResolveBase() throws Exception { public void testResolveCustomFilter() throws Exception { Settings settings = Settings.builder() - .put("group_search.base_dn", "dc=oldap,dc=test,dc=elasticsearch,dc=com") + .put(getFullSettingKey(REALM_ID, SearchGroupsResolverSettings.BASE_DN), "dc=oldap,dc=test,dc=elasticsearch,dc=com") .put("group_search.filter", "(&(objectclass=posixGroup)(memberUID={0}))") - .put("group_search.user_attribute", "uid") + .put(getFullSettingKey(REALM_ID.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "uid") .build(); - SearchGroupsResolver resolver = new SearchGroupsResolver(settings); + SearchGroupsResolver resolver = new SearchGroupsResolver(config(REALM_ID, settings)); List groups = resolveBlocking(resolver, ldapConnection, "uid=selvig,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com", - TimeValue.timeValueSeconds(10), NoOpLogger.INSTANCE, null); + TimeValue.timeValueSeconds(10), NoOpLogger.INSTANCE, null); assertThat(groups, hasItem(containsString("Geniuses"))); } public void testFilterIncludesPosixGroups() throws Exception { Settings settings = Settings.builder() - .put("group_search.base_dn", "dc=oldap,dc=test,dc=elasticsearch,dc=com") - .put("group_search.user_attribute", "uid") + .put(getFullSettingKey(REALM_ID, SearchGroupsResolverSettings.BASE_DN), "dc=oldap,dc=test,dc=elasticsearch,dc=com") + .put(getFullSettingKey(REALM_ID.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "uid") .build(); - SearchGroupsResolver resolver = new SearchGroupsResolver(settings); + SearchGroupsResolver resolver = new SearchGroupsResolver(config(REALM_ID, settings)); List groups = resolveBlocking(resolver, ldapConnection, "uid=selvig,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com", - TimeValue.timeValueSeconds(10), NoOpLogger.INSTANCE, null); + TimeValue.timeValueSeconds(10), NoOpLogger.INSTANCE, null); assertThat(groups, hasItem(containsString("Geniuses"))); } @@ -104,7 +110,7 @@ public void testCreateWithoutSpecifyingBaseDN() throws Exception { .build(); try { - new SearchGroupsResolver(settings); + new SearchGroupsResolver(config(REALM_ID, settings)); fail("base_dn must be specified and an exception should have been thrown"); } catch (IllegalArgumentException e) { assertThat(e.getMessage(), containsString("base_dn must be specified")); @@ -113,9 +119,9 @@ public void testCreateWithoutSpecifyingBaseDN() throws Exception { public void testReadUserAttributeUid() throws Exception { Settings settings = Settings.builder() - .put("group_search.base_dn", "dc=oldap,dc=test,dc=elasticsearch,dc=com") - .put("group_search.user_attribute", "uid").build(); - SearchGroupsResolver resolver = new SearchGroupsResolver(settings); + .put(getFullSettingKey(REALM_ID, SearchGroupsResolverSettings.BASE_DN), "dc=oldap,dc=test,dc=elasticsearch,dc=com") + .put(getFullSettingKey(REALM_ID.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "uid").build(); + SearchGroupsResolver resolver = new SearchGroupsResolver(config(REALM_ID, settings)); PlainActionFuture future = new PlainActionFuture<>(); resolver.readUserAttribute(ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(5), future); assertThat(future.actionGet(), is("hulk")); @@ -123,10 +129,10 @@ public void testReadUserAttributeUid() throws Exception { public void testReadUserAttributeCn() throws Exception { Settings settings = Settings.builder() - .put("group_search.base_dn", "dc=oldap,dc=test,dc=elasticsearch,dc=com") - .put("group_search.user_attribute", "cn") + .put(getFullSettingKey(REALM_ID, SearchGroupsResolverSettings.BASE_DN), "dc=oldap,dc=test,dc=elasticsearch,dc=com") + .put(getFullSettingKey(REALM_ID.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "cn") .build(); - SearchGroupsResolver resolver = new SearchGroupsResolver(settings); + SearchGroupsResolver resolver = new SearchGroupsResolver(config(REALM_ID, settings)); PlainActionFuture future = new PlainActionFuture<>(); resolver.readUserAttribute(ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(5), future); @@ -135,10 +141,10 @@ public void testReadUserAttributeCn() throws Exception { public void testReadNonExistentUserAttribute() throws Exception { Settings settings = Settings.builder() - .put("group_search.base_dn", "dc=oldap,dc=test,dc=elasticsearch,dc=com") - .put("group_search.user_attribute", "doesntExists") + .put(getFullSettingKey(REALM_ID, SearchGroupsResolverSettings.BASE_DN), "dc=oldap,dc=test,dc=elasticsearch,dc=com") + .put(getFullSettingKey(REALM_ID.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "doesntExists") .build(); - SearchGroupsResolver resolver = new SearchGroupsResolver(settings); + SearchGroupsResolver resolver = new SearchGroupsResolver(config(REALM_ID, settings)); PlainActionFuture future = new PlainActionFuture<>(); resolver.readUserAttribute(ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(5), future); @@ -147,10 +153,10 @@ public void testReadNonExistentUserAttribute() throws Exception { public void testReadBinaryUserAttribute() throws Exception { Settings settings = Settings.builder() - .put("group_search.base_dn", "dc=oldap,dc=test,dc=elasticsearch,dc=com") - .put("group_search.user_attribute", "userPassword") + .put(getFullSettingKey(REALM_ID, SearchGroupsResolverSettings.BASE_DN), "dc=oldap,dc=test,dc=elasticsearch,dc=com") + .put(getFullSettingKey(REALM_ID.getName(), SearchGroupsResolverSettings.USER_ATTRIBUTE), "userPassword") .build(); - SearchGroupsResolver resolver = new SearchGroupsResolver(settings); + SearchGroupsResolver resolver = new SearchGroupsResolver(config(REALM_ID, settings)); PlainActionFuture future = new PlainActionFuture<>(); resolver.readUserAttribute(ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(5), future); diff --git a/x-pack/qa/rolling-upgrade/build.gradle b/x-pack/qa/rolling-upgrade/build.gradle index 355e78e170f5b..ca149ba7e16ff 100644 --- a/x-pack/qa/rolling-upgrade/build.gradle +++ b/x-pack/qa/rolling-upgrade/build.gradle @@ -152,6 +152,16 @@ subprojects { setting 'xpack.ssl.keystore.password', 'testnode' dependsOn copyTestNodeKeystore extraConfigFile 'testnode.jks', new File(outputDir + '/testnode.jks') + if (version.onOrAfter('7.0.0')) { + setting 'xpack.security.authc.realms.file.file1.order', '0' + setting 'xpack.security.authc.realms.native.native1.order', '1' + } else { + setting 'xpack.security.authc.realms.file1.type', 'file' + setting 'xpack.security.authc.realms.file1.order', '0' + setting 'xpack.security.authc.realms.native1.type', 'native' + setting 'xpack.security.authc.realms.native1.order', '1' + } + if (withSystemKey) { if (version.onOrAfter('5.1.0') && version.before('6.0.0')) { // The setting didn't exist until 5.1.0 diff --git a/x-pack/qa/saml-idp-tests/build.gradle b/x-pack/qa/saml-idp-tests/build.gradle index 11e89d93c8e6a..8e6672f21e9d5 100644 --- a/x-pack/qa/saml-idp-tests/build.gradle +++ b/x-pack/qa/saml-idp-tests/build.gradle @@ -35,31 +35,28 @@ integTestCluster { setting 'xpack.security.enabled', 'true' setting 'xpack.security.http.ssl.enabled', 'false' setting 'xpack.security.authc.token.enabled', 'true' - setting 'xpack.security.authc.realms.file.type', 'file' - setting 'xpack.security.authc.realms.file.order', '0' + setting 'xpack.security.authc.realms.file.file.order', '0' // SAML realm 1 (no authorization_realms) - setting 'xpack.security.authc.realms.shibboleth.type', 'saml' - setting 'xpack.security.authc.realms.shibboleth.order', '1' - setting 'xpack.security.authc.realms.shibboleth.idp.entity_id', 'https://test.shibboleth.elastic.local/' - setting 'xpack.security.authc.realms.shibboleth.idp.metadata.path', 'idp-metadata.xml' - setting 'xpack.security.authc.realms.shibboleth.sp.entity_id', 'http://mock1.http.elastic.local/' + setting 'xpack.security.authc.realms.saml.shibboleth.order', '1' + setting 'xpack.security.authc.realms.saml.shibboleth.idp.entity_id', 'https://test.shibboleth.elastic.local/' + setting 'xpack.security.authc.realms.saml.shibboleth.idp.metadata.path', 'idp-metadata.xml' + setting 'xpack.security.authc.realms.saml.shibboleth.sp.entity_id', 'http://mock1.http.elastic.local/' // The port in the ACS URL is fake - the test will bind the mock webserver // to a random port and then whenever it needs to connect to a URL on the // mock webserver it will replace 54321 with the real port - setting 'xpack.security.authc.realms.shibboleth.sp.acs', 'http://localhost:54321/saml/acs1' - setting 'xpack.security.authc.realms.shibboleth.attributes.principal', 'uid' - setting 'xpack.security.authc.realms.shibboleth.attributes.name', 'urn:oid:2.5.4.3' + setting 'xpack.security.authc.realms.saml.shibboleth.sp.acs', 'http://localhost:54321/saml/acs1' + setting 'xpack.security.authc.realms.saml.shibboleth.attributes.principal', 'uid' + setting 'xpack.security.authc.realms.saml.shibboleth.attributes.name', 'urn:oid:2.5.4.3' // SAML realm 2 (uses authorization_realms) - setting 'xpack.security.authc.realms.shibboleth_native.type', 'saml' - setting 'xpack.security.authc.realms.shibboleth_native.order', '2' - setting 'xpack.security.authc.realms.shibboleth_native.idp.entity_id', 'https://test.shibboleth.elastic.local/' - setting 'xpack.security.authc.realms.shibboleth_native.idp.metadata.path', 'idp-metadata.xml' - setting 'xpack.security.authc.realms.shibboleth_native.sp.entity_id', 'http://mock2.http.elastic.local/' - setting 'xpack.security.authc.realms.shibboleth_native.sp.acs', 'http://localhost:54321/saml/acs2' - setting 'xpack.security.authc.realms.shibboleth_native.attributes.principal', 'uid' - setting 'xpack.security.authc.realms.shibboleth_native.authorization_realms', 'native' - setting 'xpack.security.authc.realms.native.type', 'native' - setting 'xpack.security.authc.realms.native.order', '3' + setting 'xpack.security.authc.realms.saml.shibboleth_native.type', 'saml' + setting 'xpack.security.authc.realms.saml.shibboleth_native.order', '2' + setting 'xpack.security.authc.realms.saml.shibboleth_native.idp.entity_id', 'https://test.shibboleth.elastic.local/' + setting 'xpack.security.authc.realms.saml.shibboleth_native.idp.metadata.path', 'idp-metadata.xml' + setting 'xpack.security.authc.realms.saml.shibboleth_native.sp.entity_id', 'http://mock2.http.elastic.local/' + setting 'xpack.security.authc.realms.saml.shibboleth_native.sp.acs', 'http://localhost:54321/saml/acs2' + setting 'xpack.security.authc.realms.saml.shibboleth_native.attributes.principal', 'uid' + setting 'xpack.security.authc.realms.saml.shibboleth_native.authorization_realms', 'native' + setting 'xpack.security.authc.realms.native.native.order', '3' setting 'xpack.ml.enabled', 'false' diff --git a/x-pack/qa/security-example-spi-extension/build.gradle b/x-pack/qa/security-example-spi-extension/build.gradle index c75573431fb50..e3bbf6e613f4e 100644 --- a/x-pack/qa/security-example-spi-extension/build.gradle +++ b/x-pack/qa/security-example-spi-extension/build.gradle @@ -19,13 +19,10 @@ integTestRunner { integTestCluster { dependsOn buildZip - setting 'xpack.security.authc.realms.custom.order', '0' - setting 'xpack.security.authc.realms.custom.type', 'custom' - setting 'xpack.security.authc.realms.custom.filtered_setting', 'should be filtered' - setting 'xpack.security.authc.realms.esusers.order', '1' - setting 'xpack.security.authc.realms.esusers.type', 'file' - setting 'xpack.security.authc.realms.native.type', 'native' - setting 'xpack.security.authc.realms.native.order', '2' + setting 'xpack.security.authc.realms.custom.custom.order', '0' + setting 'xpack.security.authc.realms.custom.custom.filtered_setting', 'should be filtered' + setting 'xpack.security.authc.realms.file.esusers.order', '1' + setting 'xpack.security.authc.realms.native.native.order', '2' setting 'xpack.security.enabled', 'true' setting 'xpack.ilm.enabled', 'false' setting 'xpack.ml.enabled', 'false' diff --git a/x-pack/qa/security-example-spi-extension/src/main/java/org/elasticsearch/example/SpiExtensionPlugin.java b/x-pack/qa/security-example-spi-extension/src/main/java/org/elasticsearch/example/SpiExtensionPlugin.java index 07f769849d5d0..9314b6a675056 100644 --- a/x-pack/qa/security-example-spi-extension/src/main/java/org/elasticsearch/example/SpiExtensionPlugin.java +++ b/x-pack/qa/security-example-spi-extension/src/main/java/org/elasticsearch/example/SpiExtensionPlugin.java @@ -5,13 +5,15 @@ */ package org.elasticsearch.example; +import org.elasticsearch.common.settings.Setting; import org.elasticsearch.example.realm.CustomRealm; import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.xpack.core.security.authc.RealmSettings; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.List; /** @@ -25,7 +27,9 @@ public Collection getRestHeaders() { } @Override - public List getSettingsFilter() { - return Collections.singletonList("xpack.security.authc.realms.*.filtered_setting"); + public List> getSettings() { + List> list = new ArrayList<>(RealmSettings.getStandardSettings(CustomRealm.TYPE)); + list.add(RealmSettings.simpleString(CustomRealm.TYPE, "filtered_setting", Setting.Property.NodeScope, Setting.Property.Filtered)); + return list; } } diff --git a/x-pack/qa/security-example-spi-extension/src/main/java/org/elasticsearch/example/realm/CustomRealm.java b/x-pack/qa/security-example-spi-extension/src/main/java/org/elasticsearch/example/realm/CustomRealm.java index dfd4a81ea2157..b62eb4cae0eb9 100644 --- a/x-pack/qa/security-example-spi-extension/src/main/java/org/elasticsearch/example/realm/CustomRealm.java +++ b/x-pack/qa/security-example-spi-extension/src/main/java/org/elasticsearch/example/realm/CustomRealm.java @@ -28,7 +28,7 @@ public class CustomRealm extends Realm { static final String[] ROLES = new String[] { "superuser" }; public CustomRealm(RealmConfig config) { - super(TYPE, config); + super(config); } @Override diff --git a/x-pack/qa/security-example-spi-extension/src/test/java/org/elasticsearch/example/realm/CustomRealmIT.java b/x-pack/qa/security-example-spi-extension/src/test/java/org/elasticsearch/example/realm/CustomRealmIT.java index f7bdb0d0baa9a..4487187a80b6d 100644 --- a/x-pack/qa/security-example-spi-extension/src/test/java/org/elasticsearch/example/realm/CustomRealmIT.java +++ b/x-pack/qa/security-example-spi-extension/src/test/java/org/elasticsearch/example/realm/CustomRealmIT.java @@ -118,8 +118,8 @@ public void testSettingsFiltering() throws Exception { for(NodeInfo info : nodeInfos.getNodes()) { Settings settings = info.getSettings(); assertNotNull(settings); - assertNull(settings.get("xpack.security.authc.realms.custom.filtered_setting")); - assertEquals(CustomRealm.TYPE, settings.get("xpack.security.authc.realms.custom.type")); + assertNull(settings.get("xpack.security.authc.realms.custom.custom.filtered_setting")); + assertEquals("0", settings.get("xpack.security.authc.realms.custom.custom.order")); } } } diff --git a/x-pack/qa/security-example-spi-extension/src/test/java/org/elasticsearch/example/realm/CustomRealmTests.java b/x-pack/qa/security-example-spi-extension/src/test/java/org/elasticsearch/example/realm/CustomRealmTests.java index d1435ebaa3c28..cc7579df27fb3 100644 --- a/x-pack/qa/security-example-spi-extension/src/test/java/org/elasticsearch/example/realm/CustomRealmTests.java +++ b/x-pack/qa/security-example-spi-extension/src/test/java/org/elasticsearch/example/realm/CustomRealmTests.java @@ -22,8 +22,8 @@ public class CustomRealmTests extends ESTestCase { public void testAuthenticate() { Settings globalSettings = Settings.builder().put("path.home", createTempDir()).build(); - CustomRealm realm = new CustomRealm(new RealmConfig("test", Settings.EMPTY, globalSettings, - TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings))); + CustomRealm realm = new CustomRealm(new RealmConfig(new RealmConfig.RealmIdentifier(CustomRealm.TYPE, "test"), + globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings))); SecureString password = CustomRealm.KNOWN_PW.clone(); UsernamePasswordToken token = new UsernamePasswordToken(CustomRealm.KNOWN_USER, password); PlainActionFuture plainActionFuture = new PlainActionFuture<>(); @@ -36,8 +36,8 @@ public void testAuthenticate() { public void testAuthenticateBadUser() { Settings globalSettings = Settings.builder().put("path.home", createTempDir()).build(); - CustomRealm realm = new CustomRealm(new RealmConfig("test", Settings.EMPTY, globalSettings, - TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings))); + CustomRealm realm = new CustomRealm(new RealmConfig(new RealmConfig.RealmIdentifier(CustomRealm.TYPE, "test"), + globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings))); SecureString password = CustomRealm.KNOWN_PW.clone(); UsernamePasswordToken token = new UsernamePasswordToken(CustomRealm.KNOWN_USER + "1", password); PlainActionFuture plainActionFuture = new PlainActionFuture<>(); diff --git a/x-pack/qa/security-tools-tests/src/test/java/org/elasticsearch/xpack/security/authc/file/tool/UsersToolTests.java b/x-pack/qa/security-tools-tests/src/test/java/org/elasticsearch/xpack/security/authc/file/tool/UsersToolTests.java index d80f98964f3a6..0be06995502ba 100644 --- a/x-pack/qa/security-tools-tests/src/test/java/org/elasticsearch/xpack/security/authc/file/tool/UsersToolTests.java +++ b/x-pack/qa/security-tools-tests/src/test/java/org/elasticsearch/xpack/security/authc/file/tool/UsersToolTests.java @@ -46,7 +46,7 @@ public class UsersToolTests extends CommandTestCase { // the mock filesystem we use so permissions/users/groups can be modified static FileSystem jimfs; String pathHomeParameter; - String fileTypeParameter; + String fileOrderParameter; // the config dir for each test to use Path confDir; @@ -92,10 +92,10 @@ public void setupHome() throws IOException { settings = Settings.builder() .put("path.home", homeDir) - .put("xpack.security.authc.realms.file.type", "file") + .put("xpack.security.authc.realms.file.file.order", 0) .build(); pathHomeParameter = "-Epath.home=" + homeDir; - fileTypeParameter = "-Expack.security.authc.realms.file.type=file"; + fileOrderParameter = "-Expack.security.authc.realms.file.file.order=0"; } @AfterClass @@ -329,18 +329,18 @@ public void testParseMultipleRoles() throws Exception { public void testUseraddNoPassword() throws Exception { terminal.addSecretInput(SecuritySettingsSourceField.TEST_PASSWORD); terminal.addSecretInput(SecuritySettingsSourceField.TEST_PASSWORD); - execute("useradd", pathHomeParameter, fileTypeParameter, "username"); + execute("useradd", pathHomeParameter, fileOrderParameter, "username"); assertUser("username", SecuritySettingsSourceField.TEST_PASSWORD); } public void testUseraddPasswordOption() throws Exception { - execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSourceField.TEST_PASSWORD); + execute("useradd", pathHomeParameter, fileOrderParameter, "username", "-p", SecuritySettingsSourceField.TEST_PASSWORD); assertUser("username", SecuritySettingsSourceField.TEST_PASSWORD); } public void testUseraddUserExists() throws Exception { UserException e = expectThrows(UserException.class, () -> { - execute("useradd", pathHomeParameter, fileTypeParameter, "existing_user", "-p", SecuritySettingsSourceField.TEST_PASSWORD); + execute("useradd", pathHomeParameter, fileOrderParameter, "existing_user", "-p", SecuritySettingsSourceField.TEST_PASSWORD); }); assertEquals(ExitCodes.CODE_ERROR, e.exitCode); assertEquals("User [existing_user] already exists", e.getMessage()); @@ -349,7 +349,7 @@ public void testUseraddUserExists() throws Exception { public void testUseraddReservedUser() throws Exception { final String name = randomFrom(ElasticUser.NAME, KibanaUser.NAME); UserException e = expectThrows(UserException.class, () -> { - execute("useradd", pathHomeParameter, fileTypeParameter, name, "-p", SecuritySettingsSourceField.TEST_PASSWORD); + execute("useradd", pathHomeParameter, fileOrderParameter, name, "-p", SecuritySettingsSourceField.TEST_PASSWORD); }); assertEquals(ExitCodes.DATA_ERROR, e.exitCode); assertEquals("Invalid username [" + name + "]... Username [" + name + "] is reserved and may not be used.", e.getMessage()); @@ -358,27 +358,27 @@ public void testUseraddReservedUser() throws Exception { public void testUseraddNoRoles() throws Exception { Files.delete(confDir.resolve("users_roles")); Files.createFile(confDir.resolve("users_roles")); - execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSourceField.TEST_PASSWORD); + execute("useradd", pathHomeParameter, fileOrderParameter, "username", "-p", SecuritySettingsSourceField.TEST_PASSWORD); List lines = Files.readAllLines(confDir.resolve("users_roles"), StandardCharsets.UTF_8); assertTrue(lines.toString(), lines.isEmpty()); } public void testUserdelUnknownUser() throws Exception { UserException e = expectThrows(UserException.class, () -> { - execute("userdel", pathHomeParameter, fileTypeParameter, "unknown"); + execute("userdel", pathHomeParameter, fileOrderParameter, "unknown"); }); assertEquals(ExitCodes.NO_USER, e.exitCode); assertTrue(e.getMessage(), e.getMessage().contains("User [unknown] doesn't exist")); } public void testUserdel() throws Exception { - execute("userdel", pathHomeParameter, fileTypeParameter, "existing_user"); + execute("userdel", pathHomeParameter, fileOrderParameter, "existing_user"); assertNoUser("existing_user"); } public void testPasswdUnknownUser() throws Exception { UserException e = expectThrows(UserException.class, () -> { - execute("passwd", pathHomeParameter, fileTypeParameter, "unknown", "-p", SecuritySettingsSourceField.TEST_PASSWORD); + execute("passwd", pathHomeParameter, fileOrderParameter, "unknown", "-p", SecuritySettingsSourceField.TEST_PASSWORD); }); assertEquals(ExitCodes.NO_USER, e.exitCode); assertTrue(e.getMessage(), e.getMessage().contains("User [unknown] doesn't exist")); @@ -387,65 +387,65 @@ public void testPasswdUnknownUser() throws Exception { public void testPasswdNoPasswordOption() throws Exception { terminal.addSecretInput("newpassword"); terminal.addSecretInput("newpassword"); - execute("passwd", pathHomeParameter, fileTypeParameter, "existing_user"); + execute("passwd", pathHomeParameter, fileOrderParameter, "existing_user"); assertUser("existing_user", "newpassword"); assertRole("test_admin", "existing_user", "existing_user2"); // roles unchanged } public void testPasswd() throws Exception { - execute("passwd", pathHomeParameter, fileTypeParameter, "existing_user", "-p", "newpassword"); + execute("passwd", pathHomeParameter, fileOrderParameter, "existing_user", "-p", "newpassword"); assertUser("existing_user", "newpassword"); assertRole("test_admin", "existing_user"); // roles unchanged } public void testRolesUnknownUser() throws Exception { UserException e = expectThrows(UserException.class, () -> { - execute("roles", pathHomeParameter, fileTypeParameter, "unknown"); + execute("roles", pathHomeParameter, fileOrderParameter, "unknown"); }); assertEquals(ExitCodes.NO_USER, e.exitCode); assertTrue(e.getMessage(), e.getMessage().contains("User [unknown] doesn't exist")); } public void testRolesAdd() throws Exception { - execute("roles", pathHomeParameter, fileTypeParameter, "existing_user", "-a", "test_r1"); + execute("roles", pathHomeParameter, fileOrderParameter, "existing_user", "-a", "test_r1"); assertRole("test_admin", "existing_user"); assertRole("test_r1", "existing_user"); } public void testRolesRemove() throws Exception { - execute("roles", pathHomeParameter, fileTypeParameter, "existing_user", "-r", "test_admin"); + execute("roles", pathHomeParameter, fileOrderParameter, "existing_user", "-r", "test_admin"); assertRole("test_admin", "existing_user2"); } public void testRolesAddAndRemove() throws Exception { - execute("roles", pathHomeParameter, fileTypeParameter, "existing_user", "-a", "test_r1", "-r", "test_admin"); + execute("roles", pathHomeParameter, fileOrderParameter, "existing_user", "-a", "test_r1", "-r", "test_admin"); assertRole("test_admin", "existing_user2"); assertRole("test_r1", "existing_user"); } public void testRolesRemoveLeavesExisting() throws Exception { - execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSourceField.TEST_PASSWORD, + execute("useradd", pathHomeParameter, fileOrderParameter, "username", "-p", SecuritySettingsSourceField.TEST_PASSWORD, "-r", "test_admin"); - execute("roles", pathHomeParameter, fileTypeParameter, "existing_user", "-r", "test_admin"); + execute("roles", pathHomeParameter, fileOrderParameter, "existing_user", "-r", "test_admin"); assertRole("test_admin", "username"); } public void testRolesNoAddOrRemove() throws Exception { - String output = execute("roles", pathHomeParameter, fileTypeParameter, "existing_user"); + String output = execute("roles", pathHomeParameter, fileOrderParameter, "existing_user"); assertTrue(output, output.contains("existing_user")); assertTrue(output, output.contains("test_admin")); } public void testListUnknownUser() throws Exception { UserException e = expectThrows(UserException.class, () -> { - execute("list", pathHomeParameter, fileTypeParameter, "unknown"); + execute("list", pathHomeParameter, fileOrderParameter, "unknown"); }); assertEquals(ExitCodes.NO_USER, e.exitCode); assertTrue(e.getMessage(), e.getMessage().contains("User [unknown] doesn't exist")); } public void testListAllUsers() throws Exception { - String output = execute("list", pathHomeParameter, fileTypeParameter); + String output = execute("list", pathHomeParameter, fileOrderParameter); assertTrue(output, output.contains("existing_user")); assertTrue(output, output.contains("test_admin")); assertTrue(output, output.contains("existing_user2")); @@ -456,7 +456,7 @@ public void testListAllUsers() throws Exception { } public void testListSingleUser() throws Exception { - String output = execute("list", pathHomeParameter, fileTypeParameter, "existing_user"); + String output = execute("list", pathHomeParameter, fileOrderParameter, "existing_user"); assertTrue(output, output.contains("existing_user")); assertTrue(output, output.contains("test_admin")); assertFalse(output, output.contains("existing_user2")); @@ -467,9 +467,9 @@ public void testListSingleUser() throws Exception { } public void testListUnknownRoles() throws Exception { - execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSourceField.TEST_PASSWORD, + execute("useradd", pathHomeParameter, fileOrderParameter, "username", "-p", SecuritySettingsSourceField.TEST_PASSWORD, "-r", "test_r1,r2,r3"); - String output = execute("list", pathHomeParameter, fileTypeParameter, "username"); + String output = execute("list", pathHomeParameter, fileOrderParameter, "username"); assertTrue(output, output.contains("username")); assertTrue(output, output.contains("r2*,r3*,test_r1")); } @@ -479,14 +479,14 @@ public void testListNoUsers() throws Exception { Files.createFile(confDir.resolve("users")); Files.delete(confDir.resolve("users_roles")); Files.createFile(confDir.resolve("users_roles")); - String output = execute("list", pathHomeParameter, fileTypeParameter); + String output = execute("list", pathHomeParameter, fileOrderParameter); assertTrue(output, output.contains("No users found")); } public void testListUserWithoutRoles() throws Exception { - String output = execute("list", pathHomeParameter, fileTypeParameter, "existing_user3"); + String output = execute("list", pathHomeParameter, fileOrderParameter, "existing_user3"); assertTrue(output, output.contains("existing_user3")); - output = execute("list", pathHomeParameter, fileTypeParameter); + output = execute("list", pathHomeParameter, fileOrderParameter); assertTrue(output, output.contains("existing_user3")); // output should not contain '*' which indicates unknown role @@ -497,9 +497,9 @@ public void testUserAddNoConfig() throws Exception { Path homeDir = jimfs.getPath("eshome"); IOUtils.rm(confDir.resolve("users")); pathHomeParameter = "-Epath.home=" + homeDir; - fileTypeParameter = "-Expack.security.authc.realms.file.type=file"; + fileOrderParameter = "-Expack.security.authc.realms.file.file.order=0"; UserException e = expectThrows(UserException.class, () -> { - execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSourceField.TEST_PASSWORD); + execute("useradd", pathHomeParameter, fileOrderParameter, "username", "-p", SecuritySettingsSourceField.TEST_PASSWORD); }); assertEquals(ExitCodes.CONFIG, e.exitCode); assertThat(e.getMessage(), containsString("Configuration file [eshome/config/users] is missing")); @@ -509,9 +509,9 @@ public void testUserListNoConfig() throws Exception { Path homeDir = jimfs.getPath("eshome"); IOUtils.rm(confDir.resolve("users")); pathHomeParameter = "-Epath.home=" + homeDir; - fileTypeParameter = "-Expack.security.authc.realms.file.type=file"; + fileOrderParameter = "-Expack.security.authc.realms.file.file.order=0"; UserException e = expectThrows(UserException.class, () -> { - execute("list", pathHomeParameter, fileTypeParameter); + execute("list", pathHomeParameter, fileOrderParameter); }); assertEquals(ExitCodes.CONFIG, e.exitCode); assertThat(e.getMessage(), containsString("Configuration file [eshome/config/users] is missing")); @@ -521,9 +521,9 @@ public void testUserDelNoConfig() throws Exception { Path homeDir = jimfs.getPath("eshome"); IOUtils.rm(confDir.resolve("users")); pathHomeParameter = "-Epath.home=" + homeDir; - fileTypeParameter = "-Expack.security.authc.realms.file.type=file"; + fileOrderParameter = "-Expack.security.authc.realms.file.file.order=0"; UserException e = expectThrows(UserException.class, () -> { - execute("userdel", pathHomeParameter, fileTypeParameter, "username"); + execute("userdel", pathHomeParameter, fileOrderParameter, "username"); }); assertEquals(ExitCodes.CONFIG, e.exitCode); assertThat(e.getMessage(), containsString("Configuration file [eshome/config/users] is missing")); @@ -533,9 +533,9 @@ public void testListUserRolesNoConfig() throws Exception { Path homeDir = jimfs.getPath("eshome"); IOUtils.rm(confDir.resolve("users_roles")); pathHomeParameter = "-Epath.home=" + homeDir; - fileTypeParameter = "-Expack.security.authc.realms.file.type=file"; + fileOrderParameter = "-Expack.security.authc.realms.file.file.order=0"; UserException e = expectThrows(UserException.class, () -> { - execute("roles", pathHomeParameter, fileTypeParameter, "username"); + execute("roles", pathHomeParameter, fileOrderParameter, "username"); }); assertEquals(ExitCodes.CONFIG, e.exitCode); assertThat(e.getMessage(), containsString("Configuration file [eshome/config/users_roles] is missing")); diff --git a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ADLdapUserSearchSessionFactoryTests.java b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ADLdapUserSearchSessionFactoryTests.java index 9f97ebc6d03f6..a839a12e8da97 100644 --- a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ADLdapUserSearchSessionFactoryTests.java +++ b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ADLdapUserSearchSessionFactoryTests.java @@ -90,8 +90,8 @@ public void testUserSearchWithActiveDirectory() throws Exception { }); Settings fullSettings = builder.build(); sslService = new SSLService(fullSettings, TestEnvironment.newEnvironment(fullSettings)); - RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), - new ThreadContext(globalSettings)); + RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("ad", "ad-as-ldap-test"), settings, globalSettings, + TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)); LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool); String user = "Bruce Banner"; diff --git a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/AbstractActiveDirectoryTestCase.java b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/AbstractActiveDirectoryTestCase.java index 829e87c849df6..d5274ab8deef9 100644 --- a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/AbstractActiveDirectoryTestCase.java +++ b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/AbstractActiveDirectoryTestCase.java @@ -9,16 +9,17 @@ import com.unboundid.ldap.sdk.LDAPConnectionPool; import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.LDAPInterface; - import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.common.Booleans; 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.RealmConfig; import org.elasticsearch.xpack.core.security.authc.ldap.ActiveDirectorySessionFactorySettings; 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.SSLConfigurationSettings; import org.elasticsearch.xpack.core.ssl.SSLService; import org.elasticsearch.xpack.core.ssl.VerificationMode; import org.junit.Before; @@ -34,6 +35,8 @@ import java.util.ArrayList; import java.util.List; +import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey; + public abstract class AbstractActiveDirectoryTestCase extends ESTestCase { // follow referrals defaults to false here which differs from the default value of the setting @@ -98,25 +101,27 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO sslService = new SSLService(globalSettings, environment); } - Settings buildAdSettings(String ldapUrl, String adDomainName, String userSearchDN, LdapSearchScope scope, - boolean hostnameVerification) { + Settings buildAdSettings(RealmConfig.RealmIdentifier realmId, String ldapUrl, String adDomainName, String userSearchDN, + LdapSearchScope scope, boolean hostnameVerification) { + final String realmName = realmId.getName(); Settings.Builder builder = Settings.builder() - .putList(SessionFactorySettings.URLS_SETTING, ldapUrl) - .put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, adDomainName) - .put(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_BASEDN_SETTING, userSearchDN) - .put(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_SCOPE_SETTING, scope) - .put(ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING.getKey(), AD_LDAP_PORT) - .put(ActiveDirectorySessionFactorySettings.AD_LDAPS_PORT_SETTING.getKey(), AD_LDAPS_PORT) - .put(ActiveDirectorySessionFactorySettings.AD_GC_LDAP_PORT_SETTING.getKey(), AD_GC_LDAP_PORT) - .put(ActiveDirectorySessionFactorySettings.AD_GC_LDAPS_PORT_SETTING.getKey(), AD_GC_LDAPS_PORT) - .put("follow_referrals", FOLLOW_REFERRALS); + .putList(getFullSettingKey(realmId, SessionFactorySettings.URLS_SETTING), ldapUrl) + .put(getFullSettingKey(realmName, ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING), adDomainName) + .put(getFullSettingKey(realmName, ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_BASEDN_SETTING), userSearchDN) + .put(getFullSettingKey(realmName, ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_SCOPE_SETTING), scope) + .put(getFullSettingKey(realmName, ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING), AD_LDAP_PORT) + .put(getFullSettingKey(realmName, ActiveDirectorySessionFactorySettings.AD_LDAPS_PORT_SETTING), AD_LDAPS_PORT) + .put(getFullSettingKey(realmName, ActiveDirectorySessionFactorySettings.AD_GC_LDAP_PORT_SETTING), AD_GC_LDAP_PORT) + .put(getFullSettingKey(realmName, ActiveDirectorySessionFactorySettings.AD_GC_LDAPS_PORT_SETTING), AD_GC_LDAPS_PORT) + .put(getFullSettingKey(realmId, SessionFactorySettings.FOLLOW_REFERRALS_SETTING), FOLLOW_REFERRALS); if (randomBoolean()) { - builder.put("ssl.verification_mode", hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE); + builder.put(getFullSettingKey(realmId, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), + hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE); } else { - builder.put(SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING, hostnameVerification); + builder.put(getFullSettingKey(realmId, SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING), hostnameVerification); } if (useGlobalSSL == false) { - builder.putList("ssl.certificate_authorities", certificatePaths); + builder.putList(getFullSettingKey(realmId, SSLConfigurationSettings.CAPATH_SETTING_REALM), certificatePaths); } return builder.build(); } diff --git a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolverTests.java b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolverTests.java index 330ec6b9a758c..ebdb19be14f32 100644 --- a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolverTests.java +++ b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolverTests.java @@ -9,6 +9,7 @@ import org.elasticsearch.action.support.PlainActionFuture; 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.support.LdapSearchScope; import org.elasticsearch.xpack.core.security.support.NoOpLogger; import org.junit.Before; @@ -26,6 +27,8 @@ public class ActiveDirectoryGroupsResolverTests extends GroupsResolverTestCase { private static final String BRUCE_BANNER_DN = "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; + private static final RealmConfig.RealmIdentifier REALM_ID = new RealmConfig.RealmIdentifier("active_directory", "ad"); + @Before public void setReferralFollowing() { ldapConnection.getConnectionOptions().setFollowReferrals(AbstractActiveDirectoryTestCase.FOLLOW_REFERRALS); @@ -34,11 +37,11 @@ public void setReferralFollowing() { @SuppressWarnings("unchecked") public void testResolveSubTree() throws Exception { Settings settings = Settings.builder() - .put("group_search.scope", LdapSearchScope.SUB_TREE) - .put("group_search.base_dn", "DC=ad,DC=test,DC=elasticsearch,DC=com") - .put("domain_name", "ad.test.elasticsearch.com") + .put("xpack.security.authc.realms.active_directory.ad.group_search.scope", LdapSearchScope.SUB_TREE) + .put("xpack.security.authc.realms.active_directory.ad.group_search.base_dn", "DC=ad,DC=test,DC=elasticsearch,DC=com") + .put("xpack.security.authc.realms.active_directory.ad.domain_name", "ad.test.elasticsearch.com") .build(); - ActiveDirectoryGroupsResolver resolver = new ActiveDirectoryGroupsResolver(settings); + ActiveDirectoryGroupsResolver resolver = new ActiveDirectoryGroupsResolver(config(REALM_ID, settings)); List groups = resolveBlocking(resolver, ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(10), NoOpLogger.INSTANCE, null); assertThat(groups, containsInAnyOrder( @@ -53,11 +56,12 @@ public void testResolveSubTree() throws Exception { public void testResolveOneLevel() throws Exception { Settings settings = Settings.builder() - .put("scope", LdapSearchScope.ONE_LEVEL) - .put("group_search.base_dn", "CN=Builtin, DC=ad, DC=test, DC=elasticsearch,DC=com") - .put("domain_name", "ad.test.elasticsearch.com") + .put("xpack.security.authc.realms.active_directory.ad.scope", LdapSearchScope.ONE_LEVEL) + .put("xpack.security.authc.realms.active_directory.ad.group_search.base_dn", + "CN=Builtin, DC=ad, DC=test, DC=elasticsearch,DC=com") + .put("xpack.security.authc.realms.active_directory.ad.domain_name", "ad.test.elasticsearch.com") .build(); - ActiveDirectoryGroupsResolver resolver = new ActiveDirectoryGroupsResolver(settings); + ActiveDirectoryGroupsResolver resolver = new ActiveDirectoryGroupsResolver(config(REALM_ID, settings)); List groups = resolveBlocking(resolver, ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(10), NoOpLogger.INSTANCE, null); assertThat(groups, hasItem(containsString("Users"))); @@ -65,11 +69,12 @@ public void testResolveOneLevel() throws Exception { public void testResolveBaseLevel() throws Exception { Settings settings = Settings.builder() - .put("group_search.scope", LdapSearchScope.BASE) - .put("group_search.base_dn", "CN=Users, CN=Builtin, DC=ad, DC=test, DC=elasticsearch, DC=com") - .put("domain_name", "ad.test.elasticsearch.com") + .put("xpack.security.authc.realms.active_directory.ad.group_search.scope", LdapSearchScope.BASE) + .put("xpack.security.authc.realms.active_directory.ad.group_search.base_dn", + "CN=Users, CN=Builtin, DC=ad, DC=test, DC=elasticsearch, DC=com") + .put("xpack.security.authc.realms.active_directory.ad.domain_name", "ad.test.elasticsearch.com") .build(); - ActiveDirectoryGroupsResolver resolver = new ActiveDirectoryGroupsResolver(settings); + ActiveDirectoryGroupsResolver resolver = new ActiveDirectoryGroupsResolver(config(REALM_ID, settings)); List groups = resolveBlocking(resolver, ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(10), NoOpLogger.INSTANCE, null); assertThat(groups, hasItem(containsString("CN=Users,CN=Builtin"))); @@ -108,7 +113,7 @@ private void assertValidSidQuery(Filter query, String[] expectedSids) { Pattern sidQueryPattern = Pattern.compile("\\(\\|(\\(objectSid=S(-\\d+)+\\))+\\)"); assertThat("[" + queryString + "] didn't match the search filter pattern", sidQueryPattern.matcher(queryString).matches(), is(true)); - for (String sid: expectedSids) { + for (String sid : expectedSids) { assertThat(queryString, containsString(sid)); } } diff --git a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactoryTests.java b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactoryTests.java index 7861557709ed1..721c2d066778a 100644 --- a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactoryTests.java +++ b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactoryTests.java @@ -19,8 +19,10 @@ import org.elasticsearch.threadpool.ThreadPool; 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.support.LdapSearchScope; import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings; +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.LdapSession; @@ -33,6 +35,7 @@ import java.util.List; import java.util.concurrent.ExecutionException; +import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasItem; @@ -41,6 +44,8 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryTestCase { + private static final String REALM_NAME = "ad-test"; + private static final RealmConfig.RealmIdentifier REALM_ID = new RealmConfig.RealmIdentifier("ad", REALM_NAME); private final SecureString SECURED_PASSWORD = new SecureString(PASSWORD); private ThreadPool threadPool; @@ -90,7 +95,8 @@ private RealmConfig configureRealm(String name, Settings settings) { .put(globalSettings) .build(); this.sslService = new SSLService(mergedSettings, env); - return new RealmConfig(name, settings, globalSettings, env, new ThreadContext(globalSettings)); + final RealmConfig.RealmIdentifier identifier = new RealmConfig.RealmIdentifier(LdapRealmSettings.AD_TYPE, name); + return new RealmConfig(identifier, mergedSettings, env, new ThreadContext(globalSettings)); } @SuppressWarnings("unchecked") @@ -133,7 +139,7 @@ public void testAdAuthAvengers() throws Exception { @SuppressWarnings("unchecked") public void testAuthenticate() throws Exception { - Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", + Settings settings = buildAdSettings(REALM_ID, AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", LdapSearchScope.ONE_LEVEL, false); RealmConfig config = configureRealm("ad-test", settings); try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) { @@ -157,8 +163,8 @@ public void testAuthenticate() throws Exception { @SuppressWarnings("unchecked") public void testAuthenticateBaseUserSearch() throws Exception { - Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Bruce Banner, CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", - LdapSearchScope.BASE, false); + Settings settings = buildAdSettings(REALM_ID, AD_LDAP_URL, AD_DOMAIN, + "CN=Bruce Banner, CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", LdapSearchScope.BASE, false); RealmConfig config = configureRealm("ad-test", settings); try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) { @@ -181,7 +187,7 @@ public void testAuthenticateBaseUserSearch() throws Exception { public void testAuthenticateBaseGroupSearch() throws Exception { Settings settings = Settings.builder() - .put(buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", + .put(buildAdSettings(REALM_ID, AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", LdapSearchScope.ONE_LEVEL, false)) .put(ActiveDirectorySessionFactorySettings.AD_GROUP_SEARCH_BASEDN_SETTING, "CN=Avengers,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com") @@ -202,7 +208,7 @@ public void testAuthenticateBaseGroupSearch() throws Exception { @SuppressWarnings("unchecked") public void testAuthenticateWithUserPrincipalName() throws Exception { - Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", + Settings settings = buildAdSettings(REALM_ID, AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", LdapSearchScope.ONE_LEVEL, false); RealmConfig config = configureRealm("ad-test", settings); try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) { @@ -223,7 +229,7 @@ public void testAuthenticateWithUserPrincipalName() throws Exception { @SuppressWarnings("unchecked") public void testAuthenticateWithSAMAccountName() throws Exception { - Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", + Settings settings = buildAdSettings(REALM_ID, AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", LdapSearchScope.ONE_LEVEL, false); RealmConfig config = configureRealm("ad-test", settings); try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) { @@ -246,9 +252,9 @@ public void testAuthenticateWithSAMAccountName() throws Exception { @SuppressWarnings("unchecked") public void testCustomUserFilter() throws Exception { Settings settings = Settings.builder() - .put(buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", + .put(buildAdSettings(REALM_ID, AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", LdapSearchScope.SUB_TREE, false)) - .put(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_FILTER_SETTING, + .put(getFullSettingKey(REALM_ID.getName(), ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_FILTER_SETTING), "(&(objectclass=user)(userPrincipalName={0}@ad.test.elasticsearch.com))") .build(); RealmConfig config = configureRealm("ad-test", settings); @@ -273,12 +279,12 @@ public void testStandardLdapConnection() throws Exception { String userTemplate = "CN={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; Settings settings = Settings.builder() .put(LdapTestCase.buildLdapSettings( - new String[] { AD_LDAP_URL }, - new String[] { userTemplate }, - groupSearchBase, - LdapSearchScope.SUB_TREE, - null, - true)) + new String[]{AD_LDAP_URL}, + new String[]{userTemplate}, + groupSearchBase, + LdapSearchScope.SUB_TREE, + null, + true)) .put("follow_referrals", FOLLOW_REFERRALS) .build(); if (useGlobalSSL == false) { @@ -309,8 +315,8 @@ public void testHandlingLdapReferralErrors() throws Exception { String userTemplate = "CN={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; final boolean ignoreReferralErrors = false; Settings settings = LdapTestCase.buildLdapSettings( - new String[] { AD_LDAP_URL }, - new String[] { userTemplate }, + new String[]{AD_LDAP_URL}, + new String[]{userTemplate}, groupSearchBase, LdapSearchScope.SUB_TREE, null, @@ -321,7 +327,8 @@ public void testHandlingLdapReferralErrors() throws Exception { .putList("ssl.certificate_authorities", certificatePaths) .build(); } - RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), + RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("ad", "ad-as-ldap-test"), + settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)); LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool); @@ -342,7 +349,7 @@ public void testHandlingLdapReferralErrors() throws Exception { @SuppressWarnings("unchecked") public void testStandardLdapWithAttributeGroups() throws Exception { String userTemplate = "CN={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; - Settings settings = LdapTestCase.buildLdapSettings(new String[] { AD_LDAP_URL }, userTemplate, false); + Settings settings = LdapTestCase.buildLdapSettings(new String[]{AD_LDAP_URL}, userTemplate, false); if (useGlobalSSL == false) { settings = Settings.builder() .put(settings) @@ -389,21 +396,22 @@ private Settings buildAdSettings(String ldapUrl, String adDomainName, boolean ho private Settings buildAdSettings(String ldapUrl, String adDomainName, boolean hostnameVerification, boolean useBindUser) { Settings.Builder builder = Settings.builder() - .put(SessionFactorySettings.URLS_SETTING, ldapUrl) - .put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, adDomainName) - .put(ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING.getKey(), AD_LDAP_PORT) - .put(ActiveDirectorySessionFactorySettings.AD_LDAPS_PORT_SETTING.getKey(), AD_LDAPS_PORT) - .put(ActiveDirectorySessionFactorySettings.AD_GC_LDAP_PORT_SETTING.getKey(), AD_GC_LDAP_PORT) - .put(ActiveDirectorySessionFactorySettings.AD_GC_LDAPS_PORT_SETTING.getKey(), AD_GC_LDAPS_PORT) - .put("follow_referrals", FOLLOW_REFERRALS); + .put(getFullSettingKey(REALM_ID, SessionFactorySettings.URLS_SETTING), ldapUrl) + .put(getFullSettingKey(REALM_NAME, ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING), adDomainName) + .put(getFullSettingKey(REALM_NAME, ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING), AD_LDAP_PORT) + .put(getFullSettingKey(REALM_NAME, ActiveDirectorySessionFactorySettings.AD_LDAPS_PORT_SETTING), AD_LDAPS_PORT) + .put(getFullSettingKey(REALM_NAME, ActiveDirectorySessionFactorySettings.AD_GC_LDAP_PORT_SETTING), AD_GC_LDAP_PORT) + .put(getFullSettingKey(REALM_NAME, ActiveDirectorySessionFactorySettings.AD_GC_LDAPS_PORT_SETTING), AD_GC_LDAPS_PORT) + .put(getFullSettingKey(REALM_ID, SessionFactorySettings.FOLLOW_REFERRALS_SETTING), FOLLOW_REFERRALS); if (randomBoolean()) { - builder.put("ssl.verification_mode", hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE); + builder.put(getFullSettingKey(REALM_ID, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM), + hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE); } else { - builder.put(SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING, hostnameVerification); + builder.put(getFullSettingKey(REALM_ID, SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING), hostnameVerification); } if (useGlobalSSL == false) { - builder.putList("ssl.certificate_authorities", certificatePaths); + builder.putList(getFullSettingKey(REALM_ID, SSLConfigurationSettings.CAPATH_SETTING_REALM), certificatePaths); } if (useBindUser) { diff --git a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/UserAttributeGroupsResolverTests.java b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/UserAttributeGroupsResolverTests.java index d6fc22a5cf579..126cde20686c6 100644 --- a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/UserAttributeGroupsResolverTests.java +++ b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/UserAttributeGroupsResolverTests.java @@ -10,6 +10,7 @@ import com.unboundid.ldap.sdk.SearchScope; 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.support.NoOpLogger; import org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils; @@ -24,11 +25,12 @@ public class UserAttributeGroupsResolverTests extends GroupsResolverTestCase { public static final String BRUCE_BANNER_DN = "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; + private static final RealmConfig.RealmIdentifier REALM_ID = new RealmConfig.RealmIdentifier("ldap", "realm1"); @SuppressWarnings("unchecked") public void testResolve() throws Exception { //falling back on the 'memberOf' attribute - UserAttributeGroupsResolver resolver = new UserAttributeGroupsResolver(Settings.EMPTY); + UserAttributeGroupsResolver resolver = new UserAttributeGroupsResolver(config(REALM_ID, Settings.EMPTY)); List groups = resolveBlocking(resolver, ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(20), NoOpLogger.INSTANCE, null); assertThat(groups, containsInAnyOrder( @@ -43,7 +45,7 @@ public void testResolveFromPreloadedAttributes() throws Exception { SearchRequest preSearch = new SearchRequest(BRUCE_BANNER_DN, SearchScope.BASE, LdapUtils.OBJECT_CLASS_PRESENCE_FILTER, "memberOf"); final Collection attributes = ldapConnection.searchForEntry(preSearch).getAttributes(); - UserAttributeGroupsResolver resolver = new UserAttributeGroupsResolver(Settings.EMPTY); + UserAttributeGroupsResolver resolver = new UserAttributeGroupsResolver(config(REALM_ID, Settings.EMPTY)); List groups = resolveBlocking(resolver, ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(20), NoOpLogger.INSTANCE, attributes); assertThat(groups, containsInAnyOrder( @@ -58,7 +60,7 @@ public void testResolveCustomGroupAttribute() throws Exception { Settings settings = Settings.builder() .put("user_group_attribute", "seeAlso") .build(); - UserAttributeGroupsResolver resolver = new UserAttributeGroupsResolver(settings); + UserAttributeGroupsResolver resolver = new UserAttributeGroupsResolver(config(REALM_ID, settings)); List groups = resolveBlocking(resolver, ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(20), NoOpLogger.INSTANCE, null); assertThat(groups, hasItems(containsString("Avengers"))); //seeAlso only has Avengers @@ -68,7 +70,7 @@ public void testResolveInvalidGroupAttribute() throws Exception { Settings settings = Settings.builder() .put("user_group_attribute", "doesntExist") .build(); - UserAttributeGroupsResolver resolver = new UserAttributeGroupsResolver(settings); + UserAttributeGroupsResolver resolver = new UserAttributeGroupsResolver(config(REALM_ID, settings)); List groups = resolveBlocking(resolver, ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(20), NoOpLogger.INSTANCE, null); assertThat(groups, empty());