Skip to content

Commit 14b672e

Browse files
committed
CwbiAUthTokenProviderBase now extends OidcAuthTokenProvider.
Removed previous DiscoveryProvider as all configuration discovery is now handled within OidcAuthTokenProvider.
1 parent 53f3f53 commit 14b672e

14 files changed

Lines changed: 118 additions & 635 deletions

File tree

cwbi-auth-http-client/src/main/java/hec/army/usace/hec/cwbi/auth/http/client/AuthCodePkceTokenRequestBuilder.java

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,17 @@
3232
import java.io.IOException;
3333
import java.net.InetSocketAddress;
3434
import java.net.URI;
35+
import java.nio.charset.StandardCharsets;
3536
import java.security.MessageDigest;
3637
import java.security.NoSuchAlgorithmException;
3738
import java.security.SecureRandom;
3839
import java.util.Base64;
40+
import java.util.UUID;
3941
import java.util.concurrent.CompletableFuture;
4042
import java.util.concurrent.ExecutionException;
4143
import java.util.concurrent.TimeUnit;
4244
import java.util.concurrent.TimeoutException;
43-
import java.util.concurrent.atomic.AtomicReference;
44-
import java.awt.Desktop;
45-
import java.awt.Desktop.Action;
45+
import java.util.logging.Logger;
4646

4747
import com.sun.net.httpserver.HttpExchange;
4848
import com.sun.net.httpserver.HttpHandler;
@@ -55,20 +55,21 @@
5555
* To complete the additional requirements.
5656
*/
5757
public final class AuthCodePkceTokenRequestBuilder extends TokenRequestBuilder<AuthCodePkceTokenRequestBuilder> {
58-
58+
private static final Logger LOGGER = Logger.getLogger(AuthCodePkceTokenRequestBuilder.class.getName());
5959
@Override
6060
OAuth2Token retrieveToken() throws IOException {
6161

6262
OAuth2Token retVal = null;
6363
// https://datatracker.ietf.org/doc/html/rfc7636#section-4.1
6464
try {
65-
byte[] verifierBytes = new byte[128];
65+
byte[] verifierBytes = new byte[64];
6666
SecureRandom.getInstanceStrong().nextBytes(verifierBytes);
6767
Base64.Encoder b64encoder = Base64.getUrlEncoder().withoutPadding();
6868
final String verifier = b64encoder.encodeToString(verifierBytes);
69+
final String originalState = UUID.randomUUID().toString();
6970

7071
MessageDigest md = MessageDigest.getInstance("SHA-256");
71-
final String challenge = b64encoder.encodeToString(md.digest(verifierBytes));
72+
final String challenge = b64encoder.encodeToString(md.digest(verifier.getBytes(StandardCharsets.US_ASCII)));
7273
HttpServer server = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
7374
int port = server.getAddress().getPort();
7475
String host = server.getAddress().getHostName();
@@ -82,7 +83,7 @@ public void handle(HttpExchange exchange) throws IOException {
8283
Result ret = null;
8384

8485
final String query = exchange.getRequestURI().getQuery();
85-
System.out.println("Got auth server response." + query);
86+
LOGGER.finest("Got auth server response." + query);
8687
final QueryParameters parameters = QueryParameters.parse(query);
8788
if (!parameters.get("error").isEmpty()) {
8889
String error = parameters.get("error").get(0);
@@ -91,9 +92,10 @@ public void handle(HttpExchange exchange) throws IOException {
9192
} else {
9293
String code = parameters.get("code").get(0);
9394
String state = parameters.get("state").get(0);
94-
ret = Result.success(code ,state);
95+
String session_state = parameters.get("session_state").get(0);
96+
ret = Result.success(code ,state, session_state);
9597
}
96-
System.out.println("Finishing");
98+
LOGGER.finest("Returning result back to thread.");
9799
server.stop(0);
98100
future.complete(ret);
99101
}
@@ -108,25 +110,30 @@ public void handle(HttpExchange exchange) throws IOException {
108110
.set("code_challenge_method", "S256")
109111
.set("code_challenge", challenge)
110112
.set("redirect_uri", redirectUri)
111-
.set("kc_idp_hint", "login.gov");
113+
.set("state", originalState);
112114
String urlStr= String.format("%s?%s", getAuthUrl().getApiRoot(), authParameters.encode());
113115
// start server to listen
114116
server.start();
115-
System.out.println(urlStr);
117+
LOGGER.info("Handling Auth Request");
118+
LOGGER.finer("Auth Request URL: " + urlStr);
116119
this.authCallBack.accept(URI.create(urlStr));
117120

118-
Result result = future.get(1, TimeUnit.MINUTES); // The user is now required to perform manual operations.
119-
System.out.println("Next steps.");
121+
Result result = future.get(3, TimeUnit.MINUTES); // The user is now required to perform manual operations.
122+
LOGGER.info("Retrieving Token.");
120123
if (result.error != null) {
121124
throw new IOException(String.format("Unable to login. %s : %s", result.error, result.errorDescription));
122125
}
126+
if (!result.state.equals(originalState)) {
127+
throw new IOException("Unable to continue login sequence, incorrect state value returned.");
128+
}
123129
final UrlEncodedFormData formData = new UrlEncodedFormData();
124130
formData.addClientId(getClientId())
125131
.addGrantType("authorization_code")
126132
.addParameter("code_verifier", verifier)
127133
.addScopes("openid", "profile")
128134
.addParameter("redirect_uri", redirectUri)
129-
.addParameter("session_state", result.state)
135+
.addParameter("state", result.state)
136+
.addParameter("session_state", result.session_state)
130137
.addParameter("code", result.code)
131138
.addParameter("response_mode", "fragment")
132139
.addParameter("response_type", "id_token token");
@@ -153,23 +160,25 @@ public void handle(HttpExchange exchange) throws IOException {
153160
private static class Result {
154161
public final String code;
155162
public final String state;
163+
public final String session_state;
156164

157165
public final String error;
158166
public final String errorDescription;
159167

160-
private Result(String code, String state, String error, String errorDescription) {
168+
private Result(String code, String state, String session_state, String error, String errorDescription) {
161169
this.code = code;
162170
this.state = state;
171+
this.session_state = session_state;
163172
this.error = error;
164173
this.errorDescription = errorDescription;
165174
}
166175

167-
public static Result success(String code, String state) {
168-
return new Result(code, state, null, null);
176+
public static Result success(String code, String state, String session_state) {
177+
return new Result(code, state, session_state, null, null);
169178
}
170179

171180
public static Result failure(String error, String errorDescription) {
172-
return new Result(null, null, error, errorDescription);
181+
return new Result(null, null, null, error, errorDescription);
173182
}
174183
};
175184
}

cwbi-auth-http-client/src/main/java/hec/army/usace/hec/cwbi/auth/http/client/CwbiAuthTokenProvider.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,22 @@
3333
public final class CwbiAuthTokenProvider extends CwbiAuthTokenProviderBase {
3434

3535
private final SSLSocketFactory sslSocketFactory;
36-
private final String url;
3736

3837
/**
3938
* Provider for OAuth2Tokens.
4039
*
41-
* @param tokenUrl - URL we are fetching token from
40+
* @param wellKnownUrl - URL we are retrieving configuration from
4241
* @param clientId - client name
4342
* @param sslSocketFactory - ssl socket factory
4443
*/
45-
public CwbiAuthTokenProvider(String tokenUrl, String clientId, SSLSocketFactory sslSocketFactory) {
46-
super(clientId);
44+
public CwbiAuthTokenProvider(String wellKnownUrl, String clientId, SSLSocketFactory sslSocketFactory) {
45+
super(clientId, wellKnownUrl);
4746
this.sslSocketFactory = Objects.requireNonNull(sslSocketFactory, "Missing required sslSocketFactory");
48-
this.url = Objects.requireNonNull(tokenUrl, "Missing required tokenUrl");
4947
}
5048

5149
@Override
5250
ApiConnectionInfo getUrl() {
53-
return new ApiConnectionInfoBuilder(url)
51+
return new ApiConnectionInfoBuilder(this.wellKnownUrl)
5452
.withSslSocketData(new SslSocketData(sslSocketFactory, CwbiAuthTrustManager.getTrustManager()))
5553
.build();
5654
}

cwbi-auth-http-client/src/main/java/hec/army/usace/hec/cwbi/auth/http/client/CwbiAuthTokenProviderBase.java

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,51 +24,43 @@
2424
package hec.army.usace.hec.cwbi.auth.http.client;
2525

2626
import java.io.IOException;
27-
import java.util.Objects;
2827

2928
import mil.army.usace.hec.cwms.http.client.ApiConnectionInfo;
3029
import mil.army.usace.hec.cwms.http.client.auth.OAuth2Token;
31-
import mil.army.usace.hec.cwms.http.client.auth.OAuth2TokenProvider;
3230

33-
abstract class CwbiAuthTokenProviderBase implements OAuth2TokenProvider {
34-
protected OAuth2Token oauth2Token;
35-
protected final String clientId;
31+
abstract class CwbiAuthTokenProviderBase extends OidcAuthTokenProvider {
3632

37-
protected CwbiAuthTokenProviderBase(String clientId) {
38-
this.clientId = Objects.requireNonNull(clientId, "Missing required clientId");
33+
protected CwbiAuthTokenProviderBase(String clientId, String wellKnownUrl) {
34+
super(clientId, wellKnownUrl);
3935
}
4036

4137
abstract ApiConnectionInfo getUrl() throws IOException;
4238

43-
@Override
44-
public synchronized void clear() {
45-
oauth2Token = null;
46-
}
4739

4840
@Override
4941
public synchronized OAuth2Token getToken() throws IOException {
50-
if (oauth2Token == null) {
51-
oauth2Token = newToken();
42+
if (token == null) {
43+
token = newToken();
5244
}
53-
return oauth2Token;
45+
return token;
5446
}
5547

5648
@Override
5749
public OAuth2Token newToken() throws IOException {
5850
return new DirectGrantX509TokenRequestBuilder()
59-
.withUrl(getUrl())
51+
.withUrl(tokenUrl)
6052
.withClientId(clientId)
6153
.fetchToken();
6254
}
6355

6456
@Override
6557
public synchronized OAuth2Token refreshToken() throws IOException {
66-
OAuth2Token token = new RefreshTokenRequestBuilder()
67-
.withRefreshToken(oauth2Token.getRefreshToken())
68-
.withUrl(getUrl())
58+
OAuth2Token newToken = new RefreshTokenRequestBuilder()
59+
.withRefreshToken(token.getRefreshToken())
60+
.withUrl(tokenUrl)
6961
.withClientId(clientId)
7062
.fetchToken();
71-
oauth2Token = token;
63+
token = newToken;
7264
return token;
7365
}
7466

cwbi-auth-http-client/src/main/java/hec/army/usace/hec/cwbi/auth/http/client/DiscoveredCwbiAuthTokenProvider.java

Lines changed: 0 additions & 49 deletions
This file was deleted.

cwbi-auth-http-client/src/main/java/hec/army/usace/hec/cwbi/auth/http/client/OidcAuthTokenProvider.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,32 @@
1414
/**
1515
* Handle generic OIDC auth based on configuration elements in the .well-known/openid-configuration
1616
* values.
17-
*
17+
*
1818
* Defaults to using Authorization Code + PKCE.
1919
* Support should be provided to support alternative flows as a user-at-login decision point.
2020
*/
21-
public final class OidcAuthTokenProvider implements OAuth2TokenProvider {
21+
public class OidcAuthTokenProvider implements OAuth2TokenProvider {
2222

23-
private final String clientId;
24-
private final String wellKnownUrl;
25-
private final ApiConnectionInfo tokenUrl;
26-
private final ApiConnectionInfo authUrl;
27-
private OAuth2Token token = null;
23+
protected final String clientId;
24+
protected final String wellKnownUrl;
25+
protected final ApiConnectionInfo tokenUrl;
26+
protected final ApiConnectionInfo authUrl;
27+
protected OAuth2Token token = null;
2828
// Default to open browser or print to console for usage, but allow overriding for testing and
2929
// other usages.
3030
private Consumer<URI> authCallback = TokenRequestBuilder.BROWSER_OR_CONSOLE_AUTH_CALLBACK;
3131

3232
public OidcAuthTokenProvider(String clientId, String wellKnownUrl) {
3333
this.clientId = Objects.requireNonNull(clientId, "Missing required client id.");
34-
this.wellKnownUrl = Objects.requireNonNull(clientId, "Missing required well known Url.");
34+
this.wellKnownUrl = Objects.requireNonNull(wellKnownUrl, "Missing required well known Url.");
3535

3636
OpenIdTokenController controller = new OpenIdTokenController() {
3737

3838
@Override
3939
public String retrieveWellKnownEndpoint(ApiConnectionInfo apiConnectionInfo) throws IOException {
4040
return wellKnownUrl; // we already have it.
4141
}
42-
42+
4343
};
4444
ApiConnectionInfo info = new ApiConnectionInfoBuilder(wellKnownUrl).build();
4545
String what = "auth";
@@ -110,7 +110,7 @@ public OAuth2Token newToken() throws IOException {
110110
.fetchToken();
111111
return token;
112112
}
113-
113+
114114
}
115-
115+
116116
}

cwbi-auth-http-client/src/test/java/hec/army/usace/hec/cwbi/auth/http/client/MockCwbiAuthTokenProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ public class MockCwbiAuthTokenProvider extends CwbiAuthTokenProviderBase {
4444
* @param sslSocketFactory - ssl socket factory
4545
*/
4646
public MockCwbiAuthTokenProvider(String url, String clientId, SSLSocketFactory sslSocketFactory) {
47-
super(clientId);
47+
super(clientId, url);
4848
this.sslSocketFactory = Objects.requireNonNull(sslSocketFactory, "Missing required sslSocketFactory");
4949
this.url = url;
5050
}
5151

5252
//used to manually set token for testing
5353
void setOAuth2Token(OAuth2Token token) {
54-
oauth2Token = token;
54+
this.token = token;
5555
}
5656

5757
@Override

0 commit comments

Comments
 (0)