Skip to content

Commit 53f3f53

Browse files
committed
Correct code generation and apply timeout to login sequence.
1 parent d92c8ab commit 53f3f53

1 file changed

Lines changed: 55 additions & 16 deletions

File tree

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

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
import java.security.SecureRandom;
3838
import java.util.Base64;
3939
import java.util.concurrent.CompletableFuture;
40+
import java.util.concurrent.ExecutionException;
41+
import java.util.concurrent.TimeUnit;
42+
import java.util.concurrent.TimeoutException;
4043
import java.util.concurrent.atomic.AtomicReference;
4144
import java.awt.Desktop;
4245
import java.awt.Desktop.Action;
@@ -61,31 +64,38 @@ OAuth2Token retrieveToken() throws IOException {
6164
try {
6265
byte[] verifierBytes = new byte[128];
6366
SecureRandom.getInstanceStrong().nextBytes(verifierBytes);
64-
Base64.Encoder b64encoder = Base64.getUrlEncoder();
67+
Base64.Encoder b64encoder = Base64.getUrlEncoder().withoutPadding();
6568
final String verifier = b64encoder.encodeToString(verifierBytes);
6669

6770
MessageDigest md = MessageDigest.getInstance("SHA-256");
6871
final String challenge = b64encoder.encodeToString(md.digest(verifierBytes));
6972
HttpServer server = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
7073
int port = server.getAddress().getPort();
7174
String host = server.getAddress().getHostName();
72-
final AtomicReference<String> code = new AtomicReference<>();
73-
final AtomicReference<String> state = new AtomicReference<>();
74-
final CompletableFuture<Void> future = new CompletableFuture<>();
75+
76+
final CompletableFuture<Result> future = new CompletableFuture<>();
7577

7678
server.createContext("/", new HttpHandler() {
7779

7880
@Override
7981
public void handle(HttpExchange exchange) throws IOException {
82+
Result ret = null;
83+
8084
final String query = exchange.getRequestURI().getQuery();
85+
System.out.println("Got auth server response." + query);
8186
final QueryParameters parameters = QueryParameters.parse(query);
82-
83-
code.set(parameters.get("code").get(0));
84-
state.set(parameters.get("state").get(0));
85-
exchange.sendResponseHeaders(201, 0);
86-
System.out.println("Got code");
87+
if (!parameters.get("error").isEmpty()) {
88+
String error = parameters.get("error").get(0);
89+
String errorDescription = parameters.get("error_description").get(0);
90+
ret = Result.failure(error, errorDescription);
91+
} else {
92+
String code = parameters.get("code").get(0);
93+
String state = parameters.get("state").get(0);
94+
ret = Result.success(code ,state);
95+
}
96+
System.out.println("Finishing");
8797
server.stop(0);
88-
future.complete(null);
98+
future.complete(ret);
8999
}
90100

91101
});
@@ -94,26 +104,30 @@ public void handle(HttpExchange exchange) throws IOException {
94104
.set("grant_type", "code")
95105
.set("client_id", getClientId())
96106
.set("scopes", "openid profile")
107+
.set("response_type", "code")
97108
.set("code_challenge_method", "S256")
98109
.set("code_challenge", challenge)
99-
.set("redirect_uri", redirectUri);
110+
.set("redirect_uri", redirectUri)
111+
.set("kc_idp_hint", "login.gov");
100112
String urlStr= String.format("%s?%s", getAuthUrl().getApiRoot(), authParameters.encode());
101113
// start server to listen
102114
server.start();
115+
System.out.println(urlStr);
103116
this.authCallBack.accept(URI.create(urlStr));
104117

105-
106-
future.join();
118+
Result result = future.get(1, TimeUnit.MINUTES); // The user is now required to perform manual operations.
107119
System.out.println("Next steps.");
108-
120+
if (result.error != null) {
121+
throw new IOException(String.format("Unable to login. %s : %s", result.error, result.errorDescription));
122+
}
109123
final UrlEncodedFormData formData = new UrlEncodedFormData();
110124
formData.addClientId(getClientId())
111125
.addGrantType("authorization_code")
112126
.addParameter("code_verifier", verifier)
113127
.addScopes("openid", "profile")
114128
.addParameter("redirect_uri", redirectUri)
115-
.addParameter("session_state", state.get())
116-
.addParameter("code", code.get())
129+
.addParameter("session_state", result.state)
130+
.addParameter("code", result.code)
117131
.addParameter("response_mode", "fragment")
118132
.addParameter("response_type", "id_token token");
119133

@@ -131,6 +145,31 @@ public void handle(HttpExchange exchange) throws IOException {
131145
return retVal;
132146
} catch (NoSuchAlgorithmException ex) {
133147
throw new IOException("Unable to retrieve SecureRandom or Message Digest instance to generate verifier", ex);
148+
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
149+
throw new IOException("Unable to form login sequence.", ex);
134150
}
135151
}
152+
153+
private static class Result {
154+
public final String code;
155+
public final String state;
156+
157+
public final String error;
158+
public final String errorDescription;
159+
160+
private Result(String code, String state, String error, String errorDescription) {
161+
this.code = code;
162+
this.state = state;
163+
this.error = error;
164+
this.errorDescription = errorDescription;
165+
}
166+
167+
public static Result success(String code, String state) {
168+
return new Result(code, state, null, null);
169+
}
170+
171+
public static Result failure(String error, String errorDescription) {
172+
return new Result(null, null, error, errorDescription);
173+
}
174+
};
136175
}

0 commit comments

Comments
 (0)