elastic / elastic/elasticsearch

bug on OpenID connect: java.lang.ClassCastException when the users claims do contain JSON

Open
#55,658 2 comments 0 reactions 0 assignees View on GitHub
:Security/Authentication team-discuss Team:Security
Dominant language
Java
Stars
77.9k
Forks
26.1k
PR merge metrics
PR metrics pending

Description

**Elasticsearch version** (`bin/elasticsearch --version`): 7.6.1

**Plugins installed**: []

**JVM version** (`java -version`): 1.8.0_242

**OS version** (`uname -a` if on a Unix-like system): RHEL 7.7 (exact version 3.10.0-1062.12.1.el7.x86_64)

**Description of the problem including expected versus actual behavior**:
When using OpenID connect method, some claims can contain JSON objects in JSON lists. This is especially desirable in real world applications, when having rights to multiple ressources (eg, multiple elastic instances). While it [isn't strictly part of the OpenID standard](https://openid.net/specs/openid-connect-core-1_0.html#IndividualClaimsRequests), many companies are using this format to transmit users permissions.

For example, a claim can have the following format :
```"user_authorization":[{"resource":"myElasticInstance","permissions":[{"name":"SUPERUSER","constraints":[]}]}],```

ElasticSearch does not handle the JSON object ```{"ressource": ...}```, and thus throw an error.

**Current behavior:**
A java.lang.ClassCastException is trigered

**Expected behavior:**
The "permission" field is mapped to the roles of the user (via role mapping or automatically)

The logs (see below) should provide a relevant explanation of the issue

**Steps to reproduce**:

1. Install an OpenAM instance (or any OpenID server). Store the permissions in the JSON format.
2. Configure a basic OpenID authentication in elasticsearch.yml :
```
logger.org.elasticsearch.xpack.security.authc.oidc: "TRACE"
xpack.security.authc.realms.oidc.oidc1:
rp.client_id: "11111111-1111-1111-1111-111111111111"
rp.response_type: code
rp.requested_scopes: ["openid","profile","myElasticInstance.KibanaAccess"]
rp.redirect_uri: "https://kibanaURL/api/security/oidc/callback"
op.issuer: "https://opURL/oauth2"
op.authorization_endpoint: "https://opURL/oauth2/authorize"
ssl.certificate_authorities: ["sslkeys/ca-bundle.crt"]
op.token_endpoint: "https://opURL/oauth2/access_token"
op.jwkset_path: "https://opURL/oauth2/jwk_uri"
op.userinfo_endpoint: "https://opURL/oauth2/userinfo"
op.endsession_endpoint: "https://opURL/oauth2/logout"
rp.post_logout_redirect_uri: "https://kibanaURL/logged_out"
claims.principal: "sub"
claims.groups: "user_authorization"
claims.name: "name"
claims.mail: "mail"
```
3. Try to get authentiated on kibana.
4. View your logs and see a java.lang.ClassCastException

The problem seems to come [from this part of the code](https://github.com/elastic/elasticsearch/blob/master/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectRealm.java#L460-L476). Not sure what's the best way to fix that through...

**Provide logs (if relevant)**:
```
2020-04-23T11:26:32,779][TRACE][o.e.x.s.a.o.OpenIdConnectAuthenticator] [elastic-node-0] Successfully retrieved user information: [
{
"sub":"myname@mycompany.com",
"mail":"myname@mycompany.com",
"auth_level":"L2",
"origin_network":"LAN",
"rc_local_sigle":"MyWonderful\/And\/Amazing\/Department",
"first_name":"MyFirstName",
"preferred_language":"EN",
"last_name":"myLastName",
"user_authorization":[{"resource":"myElasticInstance","permissions":[{"name":"SUPERUSER","constraints":[]}]}],
"name":"MyFirstName MyLastName",
"family_name":"MyLastName"
}
]
[2020-04-23T11:26:32,779][WARN][o.e.x.s.a.AuthenticationService] [elastic-node-0] An error occurred while attempting to authenticate [] against realm [oidc1]
java.lang.ClassCastException: class net.minidev.json.JSONObject cannot be cast to class java.lang.String (net.minidev.json.JSONObject is in unnamed module of loader java.net.FactoryURLClassLoader @7e4d2287; java.lang.String is in module java.base of loader 'bootstrap')
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:176) ~[?:?]
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1621) ~[?:?]
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[?:?]
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[?:?]
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[?:?]
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:?]
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[?:?]
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectRealm$ClaimParser.lambda$forSetting$2(OpenIdConnectRealm.java:480) ~[?:?]
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectRealm$ClaimParser.getClaimValues(OpenIdConnectRealm.java:403) ~[?:?]
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectRealm.buildUserFromClaims(OpenIdConnectRealm.java:228) ~[?:?]
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectRealm.lambda$authenticate$0(OpenIdConnectRealm.java:168) ~[?:?]
at org.elasticsearch.action.ActionListener$1.onResponse(ActionListener.java:63) [elasticsearch-7.6.1.jar:7.6.1]
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectAuthenticator.handleUserinfoResponse(OpenIdConnectAuthenticator.java:411) [x-pack-security-7.6.1.jar:7.6.1]
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectAuthenticator.access$700(OpenIdConnectAuthenticator.java:122) [x-pack-security-7.6.1.jar:7.6.1]
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectAuthenticator$1.completed(OpenIdConnectAuthenticator.java:364) [x-pack-security-7.6.1.jar:7.6.1]
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectAuthenticator$1.completed(OpenIdConnectAuthenticator.java:361) [x-pack-security-7.6.1.jar:7.6.1]
at org.apache.http.concurrent.BasicFuture.completed(BasicFuture.java:122) [httpcore-4.4.12.jar:4.4.12]
at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseCompleted(DefaultClientExchangeHandlerImpl.java:181) [httpasyncclient-4.1.4.jar:4.1.4]
at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.processResponse(HttpAsyncRequestExecutor.java:448) [httpcore-nio-4.4.12.jar:4.4.12]
at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.inputReady(HttpAsyncRequestExecutor.java:338) [httpcore-nio-4.4.12.jar:4.4.12]
at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:265) [httpcore-nio-4.4.12.jar:4.4.12]
at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81) [httpasyncclient-4.1.4.jar:4.1.4]
at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39) [httpasyncclient-4.1.4.jar:4.1.4]
at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:121) [httpcore-nio-4.4.12.jar:4.4.12]
at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162) [httpcore-nio-4.4.12.jar:4.4.12]
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337) [httpcore-nio-4.4.12.jar:4.4.12]
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315) [httpcore-nio-4.4.12.jar:4.4.12]
at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276) [httpcore-nio-4.4.12.jar:4.4.12]
at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104) [httpcore-nio-4.4.12.jar:4.4.12]
at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:591) [httpcore-nio-4.4.12.jar:4.4.12]
at java.lang.Thread.run(Thread.java:830) [?:?]
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.