Skip to content

Commit 63e9e46

Browse files
committed
OpenID Connect Realm base functionality (elastic#37009)
This commit adds * An OpenID Connect Realm definition * Necessary OpenID Connect Realm settings to support Authorization code grant and Implicit grant flows * Rest and Transport Action and Request/Response objects for initiating and completing the authentication flow * Functionality for generating OIDC Authentication Request URIs Unit tests Notably missing (to be handled in subsequent PRs): * The actual implementation of the authentication flows * Necessary JW{T,S,E} functionality Relates: elastic#35339
1 parent f843c92 commit 63e9e46

19 files changed

+244
-241
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/oidc/OpenIdConnectAuthenticateAction.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package org.elasticsearch.xpack.core.security.action.oidc;
77

88
import org.elasticsearch.action.Action;
9+
import org.elasticsearch.common.io.stream.Writeable;
910

1011
/**
1112
* Action for initiating an authentication process using OpenID Connect
@@ -15,11 +16,17 @@ public final class OpenIdConnectAuthenticateAction extends Action<OpenIdConnectA
1516
public static final OpenIdConnectAuthenticateAction INSTANCE = new OpenIdConnectAuthenticateAction();
1617
public static final String NAME = "cluster:admin/xpack/security/oidc/authenticate";
1718

18-
protected OpenIdConnectAuthenticateAction() {
19+
private OpenIdConnectAuthenticateAction() {
1920
super(NAME);
2021
}
2122

23+
@Override
2224
public OpenIdConnectAuthenticateResponse newResponse() {
23-
return new OpenIdConnectAuthenticateResponse();
25+
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
26+
}
27+
28+
@Override
29+
public Writeable.Reader<OpenIdConnectAuthenticateResponse> getResponseReader() {
30+
return OpenIdConnectAuthenticateResponse::new;
2431
}
2532
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/oidc/OpenIdConnectAuthenticateRequest.java

+13-8
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,32 @@
1818
public class OpenIdConnectAuthenticateRequest extends ActionRequest {
1919

2020
/**
21-
* The URI were the OP redirected the browser after the authentication attempt. This is passed as is from the
21+
* The URI where the OP redirected the browser after the authentication attempt. This is passed as is from the
2222
* facilitator entity (i.e. Kibana)
2323
*/
2424
private String redirectUri;
2525

2626
/**
27-
* The state value that either we or the facilitator generated for this specific flow and that was stored at the user's session with
27+
* The state value that we generated for this specific flow and that should be stored at the user's session with
2828
* the facilitator
2929
*/
3030
private String state;
3131

3232
/**
33-
* The nonce value that the facilitator generated for this specific flow and that was stored at the user's session with
33+
* The nonce value that we generated for this specific flow and that should be stored at the user's session with
3434
* the facilitator
3535
*/
3636
private String nonce;
3737

3838
public OpenIdConnectAuthenticateRequest() {
39+
40+
}
41+
42+
public OpenIdConnectAuthenticateRequest(StreamInput in) throws IOException {
43+
super.readFrom(in);
44+
redirectUri = in.readString();
45+
state = in.readString();
46+
nonce = in.readOptionalString();
3947
}
4048

4149
public String getRedirectUri() {
@@ -76,11 +84,8 @@ public void writeTo(StreamOutput out) throws IOException {
7684
}
7785

7886
@Override
79-
public void readFrom(StreamInput in) throws IOException {
80-
super.readFrom(in);
81-
redirectUri = in.readString();
82-
state = in.readString();
83-
nonce = in.readOptionalString();
87+
public void readFrom(StreamInput in) {
88+
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
8489
}
8590

8691
public String toString() {

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/oidc/OpenIdConnectAuthenticateResponse.java

+8-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ public OpenIdConnectAuthenticateResponse(String principal, String accessTokenStr
2525
this.expiresIn = expiresIn;
2626
}
2727

28-
public OpenIdConnectAuthenticateResponse() {
28+
public OpenIdConnectAuthenticateResponse(StreamInput in) throws IOException {
29+
super.readFrom(in);
30+
principal = in.readString();
31+
accessTokenString = in.readString();
32+
refreshTokenString = in.readString();
33+
expiresIn = in.readTimeValue();
2934
}
3035

3136
public String getPrincipal() {
@@ -45,12 +50,8 @@ public TimeValue getExpiresIn() {
4550
}
4651

4752
@Override
48-
public void readFrom(StreamInput in) throws IOException {
49-
super.readFrom(in);
50-
principal = in.readString();
51-
accessTokenString = in.readString();
52-
refreshTokenString = in.readString();
53-
expiresIn = in.readTimeValue();
53+
public void readFrom(StreamInput in) {
54+
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
5455
}
5556

5657
@Override

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/oidc/OpenIdConnectPrepareAuthenticationAction.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,24 @@
66
package org.elasticsearch.xpack.core.security.action.oidc;
77

88
import org.elasticsearch.action.Action;
9+
import org.elasticsearch.common.io.stream.Writeable;
910

1011
public class OpenIdConnectPrepareAuthenticationAction extends Action<OpenIdConnectPrepareAuthenticationResponse> {
1112

1213
public static final OpenIdConnectPrepareAuthenticationAction INSTANCE = new OpenIdConnectPrepareAuthenticationAction();
1314
public static final String NAME = "cluster:admin/xpack/security/oidc/prepare";
1415

15-
protected OpenIdConnectPrepareAuthenticationAction() {
16+
private OpenIdConnectPrepareAuthenticationAction() {
1617
super(NAME);
1718
}
1819

20+
@Override
1921
public OpenIdConnectPrepareAuthenticationResponse newResponse() {
20-
return new OpenIdConnectPrepareAuthenticationResponse();
22+
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
23+
}
24+
25+
@Override
26+
public Writeable.Reader<OpenIdConnectPrepareAuthenticationResponse> getResponseReader() {
27+
return OpenIdConnectPrepareAuthenticationResponse::new;
2128
}
2229
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/oidc/OpenIdConnectPrepareAuthenticationRequest.java

+8-23
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,26 @@
1616
import static org.elasticsearch.action.ValidateActions.addValidationError;
1717

1818
/**
19-
* Represents a request to prepare an OAuth 2.0 authentication request
19+
* Represents a request to prepare an OAuth 2.0 authorization request
2020
*/
2121
public class OpenIdConnectPrepareAuthenticationRequest extends ActionRequest {
2222

2323
private String realmName;
24-
private String state;
25-
private String nonce;
2624

2725
public String getRealmName() {
2826
return realmName;
2927
}
3028

31-
public String getState() {
32-
return state;
33-
}
34-
35-
public String getNonce() {
36-
return nonce;
37-
}
38-
3929
public void setRealmName(String realmName) {
4030
this.realmName = realmName;
4131
}
4232

43-
public void setState(String state) {
44-
this.state = state;
33+
public OpenIdConnectPrepareAuthenticationRequest() {
4534
}
4635

47-
public void setNonce(String nonce) {
48-
this.nonce = nonce;
36+
public OpenIdConnectPrepareAuthenticationRequest(StreamInput in) throws IOException {
37+
super.readFrom(in);
38+
realmName = in.readString();
4939
}
5040

5141
@Override
@@ -61,20 +51,15 @@ public ActionRequestValidationException validate() {
6151
public void writeTo(StreamOutput out) throws IOException {
6252
super.writeTo(out);
6353
out.writeString(realmName);
64-
out.writeOptionalString(state);
65-
out.writeOptionalString(nonce);
6654
}
6755

6856
@Override
69-
public void readFrom(StreamInput in) throws IOException {
70-
super.readFrom(in);
71-
realmName = in.readString();
72-
state = in.readOptionalString();
73-
nonce = in.readOptionalString();
57+
public void readFrom(StreamInput in) {
58+
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
7459
}
7560

7661
public String toString() {
77-
return "{realmName=" + realmName + ", state=" + state + ", nonce=" + nonce + "}";
62+
return "{realmName=" + realmName + "}";
7863
}
7964

8065
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/oidc/OpenIdConnectPrepareAuthenticationRequestBuilder.java

-10
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,4 @@ public OpenIdConnectPrepareAuthenticationRequestBuilder realmName(String name) {
2222
request.setRealmName(name);
2323
return this;
2424
}
25-
26-
public OpenIdConnectPrepareAuthenticationRequestBuilder state(String state) {
27-
request.setState(state);
28-
return this;
29-
}
30-
31-
public OpenIdConnectPrepareAuthenticationRequestBuilder nonce(String nonce) {
32-
request.setNonce(nonce);
33-
return this;
34-
}
3525
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/oidc/OpenIdConnectPrepareAuthenticationResponse.java

+37-7
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,38 @@
88
import org.elasticsearch.action.ActionResponse;
99
import org.elasticsearch.common.io.stream.StreamInput;
1010
import org.elasticsearch.common.io.stream.StreamOutput;
11+
import org.elasticsearch.common.xcontent.ToXContentObject;
12+
import org.elasticsearch.common.xcontent.XContentBuilder;
1113

1214
import java.io.IOException;
1315

1416
/**
15-
* A response containing the authorization endpoint URL and the appropriate request parameters as URL parameters
17+
* A response object that contains the OpenID Connect Authentication Request as a URL and the state and nonce values that were
18+
* generated for this request.
1619
*/
17-
public class OpenIdConnectPrepareAuthenticationResponse extends ActionResponse {
20+
public class OpenIdConnectPrepareAuthenticationResponse extends ActionResponse implements ToXContentObject {
1821

1922
private String authenticationRequestUrl;
23+
/*
24+
* The oAuth2 state parameter used for CSRF protection.
25+
*/
2026
private String state;
27+
/*
28+
* String value used to associate a Client session with an ID Token, and to mitigate replay attacks.
29+
*/
30+
private String nonce;
2131

22-
public OpenIdConnectPrepareAuthenticationResponse(String authorizationEndpointUrl, String state) {
32+
public OpenIdConnectPrepareAuthenticationResponse(String authorizationEndpointUrl, String state, String nonce) {
2333
this.authenticationRequestUrl = authorizationEndpointUrl;
2434
this.state = state;
35+
this.nonce = nonce;
2536
}
2637

27-
public OpenIdConnectPrepareAuthenticationResponse() {
38+
public OpenIdConnectPrepareAuthenticationResponse(StreamInput in) throws IOException {
39+
super.readFrom(in);
40+
authenticationRequestUrl = in.readString();
41+
state = in.readString();
42+
nonce = in.readString();
2843
}
2944

3045
public String getAuthenticationRequestUrl() {
@@ -35,19 +50,34 @@ public String getState() {
3550
return state;
3651
}
3752

53+
public String getNonce() {
54+
return nonce;
55+
}
56+
3857
@Override
3958
public void readFrom(StreamInput in) throws IOException {
40-
super.readFrom(in);
41-
authenticationRequestUrl = in.readString();
59+
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
4260
}
4361

4462
@Override
4563
public void writeTo(StreamOutput out) throws IOException {
4664
super.writeTo(out);
4765
out.writeString(authenticationRequestUrl);
66+
out.writeString(state);
67+
out.writeString(nonce);
4868
}
4969

5070
public String toString() {
51-
return "{authenticationRequestUrl=" + authenticationRequestUrl + ", state=" + state + "}";
71+
return "{authenticationRequestUrl=" + authenticationRequestUrl + ", state=" + state + ", nonce=" + nonce + "}";
72+
}
73+
74+
@Override
75+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
76+
builder.startObject();
77+
builder.field("authentication_request_url", authenticationRequestUrl);
78+
builder.field("state", state);
79+
builder.field("nonce", nonce);
80+
builder.endObject();
81+
return builder;
5282
}
5383
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmSettings.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public static Setting.AffixSetting<String> simpleString(String realmType, String
5858
}
5959

6060
/**
61-
* Create a {@link SecureSetting#secureString secure string} {@link Setting} object for a realm of
61+
* Create a {@link SecureSetting#secureString secure string} {@link Setting} object of a realm of
6262
* with the provided type and setting suffix.
6363
*
6464
* @param realmType The type of the realm, used within the setting prefix

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/oidc/OpenIdConnectRealmSettings.java

+2-8
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,11 @@ private OpenIdConnectRealmSettings() {
4545
public static final Setting.AffixSetting<List<String>> RP_REQUESTED_SCOPES = Setting.affixKeySetting(
4646
RealmSettings.realmSettingPrefix(TYPE), "rp.requested_scopes",
4747
key -> Setting.listSetting(key, Collections.singletonList("openid"), Function.identity(), Setting.Property.NodeScope));
48-
public static final Setting.AffixSetting<List<String>> RP_ALLOWED_SCOPES = Setting.affixKeySetting(
49-
RealmSettings.realmSettingPrefix(TYPE), "rp.allowed_scopes",
50-
key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(), Setting.Property.NodeScope));
51-
public static final Setting.AffixSetting<List<String>> RP_ALLOWED_SIGNATURE_ALGORITHMS = Setting.affixKeySetting(
52-
RealmSettings.realmSettingPrefix(TYPE), "rp.allowed_signature_algorithms",
53-
key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(), Setting.Property.NodeScope));
5448

5549
public static Set<Setting.AffixSetting<?>> getSettings() {
5650
final Set<Setting.AffixSetting<?>> set = Sets.newHashSet(
57-
OP_NAME, RP_CLIENT_ID, RP_REDIRECT_URI, RP_RESPONSE_TYPE, RP_REQUESTED_SCOPES, RP_ALLOWED_SCOPES, RP_CLIENT_SECRET,
58-
RP_ALLOWED_SIGNATURE_ALGORITHMS, OP_AUTHORIZATION_ENDPOINT, OP_TOKEN_ENDPOINT, OP_USERINFO_ENDPOINT, OP_ISSUER);
51+
OP_NAME, RP_CLIENT_ID, RP_REDIRECT_URI, RP_RESPONSE_TYPE, RP_REQUESTED_SCOPES, RP_CLIENT_SECRET,
52+
OP_AUTHORIZATION_ENDPOINT, OP_TOKEN_ENDPOINT, OP_USERINFO_ENDPOINT, OP_ISSUER);
5953
set.addAll(DelegatedAuthorizationSettings.getSettings(TYPE));
6054
set.addAll(RealmSettings.getStandardSettings(TYPE));
6155
return set;

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/oidc/TransportOpenIdConnectAuthenticateAction.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.elasticsearch.action.support.ActionFilters;
1111
import org.elasticsearch.action.support.HandledTransportAction;
1212
import org.elasticsearch.common.inject.Inject;
13+
import org.elasticsearch.common.io.stream.Writeable;
1314
import org.elasticsearch.common.unit.TimeValue;
1415
import org.elasticsearch.common.util.concurrent.ThreadContext;
1516
import org.elasticsearch.tasks.Task;
@@ -27,8 +28,8 @@
2728

2829
import java.util.Map;
2930

30-
public class TransportOpenIdConnectAuthenticateAction extends HandledTransportAction<OpenIdConnectAuthenticateRequest,
31-
OpenIdConnectAuthenticateResponse> {
31+
public class TransportOpenIdConnectAuthenticateAction
32+
extends HandledTransportAction<OpenIdConnectAuthenticateRequest, OpenIdConnectAuthenticateResponse> {
3233

3334
private final ThreadPool threadPool;
3435
private final AuthenticationService authenticationService;
@@ -38,7 +39,8 @@ public class TransportOpenIdConnectAuthenticateAction extends HandledTransportAc
3839
public TransportOpenIdConnectAuthenticateAction(ThreadPool threadPool, TransportService transportService,
3940
ActionFilters actionFilters, AuthenticationService authenticationService,
4041
TokenService tokenService) {
41-
super(OpenIdConnectAuthenticateAction.NAME, transportService, actionFilters, OpenIdConnectAuthenticateRequest::new);
42+
super(OpenIdConnectAuthenticateAction.NAME, transportService, actionFilters,
43+
(Writeable.Reader<OpenIdConnectAuthenticateRequest>) OpenIdConnectAuthenticateRequest::new);
4244
this.threadPool = threadPool;
4345
this.authenticationService = authenticationService;
4446
this.tokenService = tokenService;

0 commit comments

Comments
 (0)