Skip to content

Commit

Permalink
updated elytron code
Browse files Browse the repository at this point in the history
  • Loading branch information
keshav-725 authored and keshav-redhat committed Jul 11, 2023
1 parent f7578fd commit 0f7120b
Show file tree
Hide file tree
Showing 14 changed files with 129 additions and 102 deletions.
5 changes: 0 additions & 5 deletions http/client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,6 @@
<groupId>org.wildfly.security</groupId>
<artifactId>wildfly-elytron-digest</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.security</groupId>
<artifactId>wildfly-elytron-http-basic</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
import org.wildfly.security.http.client.mechanism.basic.ElytronHttpClientBasicAuthMechanism;
import org.wildfly.security.http.client.mechanism.bearer.ElytronHttpClientBearerAuthMechanism;
import org.wildfly.security.http.client.mechanism.digest.ElytronHttpClientDigestAuthMechanism;
import org.wildfly.security.http.client.utils.ElytronHttpClientConstants;
import org.wildfly.security.http.client.utils.ElytronHttpClientCredentialUtils;
import org.wildfly.security.http.client.utils.ElytronHttpClientRequestBuilder;
import org.wildfly.security.http.client.utils.ElytronMessages;

import javax.net.ssl.SSLContext;
Expand Down Expand Up @@ -54,75 +52,71 @@ public ElytronHttpClient() {
this.httpClient = HttpClient.newHttpClient();
}

private HttpResponse getResponse(HttpRequest request) throws IOException, InterruptedException {
return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
}

private void addSSLContextToHttpClient(URI uri) throws MalformedURLException {
String protocol = new URL(uri.toString()).getProtocol();

if (protocol.equalsIgnoreCase("https")) {
SSLContext sslContext = ElytronHttpClientCredentialUtils.getSSLContext(uri);
httpClient = HttpClient.newBuilder().sslContext(sslContext).build();
}
}

/**
* Used to connect to the secured uri and return the response based on that.
*/
public HttpResponse connect(String uri, String method, String body, Map<String, String> headers) throws IOException, InterruptedException, URISyntaxException {
URI uriPath = new URI(uri);
addSSLContextToHttpClient(uriPath);

HttpRequest request = ElytronHttpClientRequestBuilder.buildRequest(uriPath, method, body, headers);
HttpResponse response = getResponse(request);
public HttpResponse connect(HttpRequest httpRequest) throws IOException, InterruptedException, URISyntaxException {
addSSLContextToHttpClient(httpRequest.uri());

HttpResponse response = getResponse(httpRequest);
if (response.statusCode() == OK) {
return response;
}

String authHeader = getAuthHeader(response);

if (authHeader == null) {
String authenticateHeader = getAuthenticateHeader(response);
if (authenticateHeader == null) {
throw new ElytronHttpClientException(ElytronMessages.log.responseHeaderExtractionFailed());
}
String[] authChallenges = authHeader.split(",");
HttpRequest authRequest = null;

String challenge = authChallenges[0];
String challenge = getFirstChallenge(authenticateHeader);
String mechanismType = getMechanismType(challenge);

String authType = getAuthType(challenge);

switch (authType) {
switch (mechanismType) {
case "basic":
authRequest = ElytronHttpClientBasicAuthMechanism.evaluateMechanism(uriPath, method, body, headers);
authRequest = ElytronHttpClientBasicAuthMechanism.evaluateMechanism(httpRequest);
break;
case "digest":
authRequest = ElytronHttpClientDigestAuthMechanism.evaluateMechanism(uriPath, authHeader, method, body, headers);
authRequest = ElytronHttpClientDigestAuthMechanism.evaluateMechanism(authenticateHeader, httpRequest);
break;
case "bearer":
authRequest = ElytronHttpClientBearerAuthMechanism.evaluateMechanism(uriPath, method, body, headers);
authRequest = ElytronHttpClientBearerAuthMechanism.evaluateMechanism(httpRequest);
break;
default:
authRequest = ElytronHttpClientRequestBuilder.buildRequest(uriPath, method, body, headers);
}

if (authRequest != null) {
response = getResponse(authRequest);
return response;
}

// If none of the authentication mechanisms succeeded, fallback to the initial request
response = getResponse(request);
return response;
}

public HttpResponse connect(String uri) throws IOException, InterruptedException, URISyntaxException {
HttpResponse response = connect(uri, ElytronHttpClientConstants.GET, null, null);
return response;
public HttpResponse connect(String uri) throws URISyntaxException, IOException, InterruptedException {
URI uriPath = new URI(uri);
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(uriPath)
.build();
return connect(httpRequest);
}
private HttpResponse getResponse(HttpRequest request) throws IOException, InterruptedException {
return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
}

private void addSSLContextToHttpClient(URI uri) throws MalformedURLException {
String protocol = new URL(uri.toString()).getProtocol();

if (protocol.equalsIgnoreCase("https")) {
SSLContext sslContext = ElytronHttpClientCredentialUtils.getSSLContext(uri);
httpClient = HttpClient.newBuilder().sslContext(sslContext).build();
}
}

private String getFirstChallenge(String authHeader){
String[] authChallenges = authHeader.split(",");
String challenge = authChallenges[0];
return challenge;
}

private String getAuthHeader(HttpResponse response) {
private String getAuthenticateHeader(HttpResponse response) {
String authHeader = null;
Map<String, List<String>> allHeaderValues = response.headers().map();
for (String headerKey : allHeaderValues.keySet()) {
Expand All @@ -133,7 +127,7 @@ private String getAuthHeader(HttpResponse response) {
return authHeader;
}

private String getAuthType(String challenge) {
private String getMechanismType(String challenge) {
return challenge.trim().split(" ")[0].toLowerCase();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import org.wildfly.security.http.client.utils.ElytronHttpClientCredentialUtils;
import org.wildfly.security.http.client.utils.ElytronHttpClientRequestBuilder;

import java.net.URI;
import java.net.http.HttpRequest;
import java.util.Base64;
import java.util.HashMap;
Expand All @@ -36,14 +35,13 @@
public class ElytronHttpClientBasicAuthMechanism {
private static ElytronHttpClientCredentialUtils elytronHttpClientCredentialProvider = new ElytronHttpClientCredentialUtils();

public static HttpRequest evaluateMechanism(URI uri, String method, String body, Map<String, String> headers) {
String userName = elytronHttpClientCredentialProvider.getUserName(uri);
String password = elytronHttpClientCredentialProvider.getPassword(uri);
if(headers == null){
headers = new HashMap<>();
}
public static HttpRequest evaluateMechanism(HttpRequest httpRequest) {
String userName = elytronHttpClientCredentialProvider.getUserName(httpRequest.uri());
String password = elytronHttpClientCredentialProvider.getPassword(httpRequest.uri());

Map<String, String > headers = new HashMap<>();
headers.put(ElytronHttpClientConstants.AUTHORIZATION, basicAuth(userName, password));
HttpRequest request = ElytronHttpClientRequestBuilder.buildRequest(uri, method, body, headers);
HttpRequest request = ElytronHttpClientRequestBuilder.buildRequest(httpRequest, headers);
return request;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,17 @@
import org.wildfly.security.http.client.utils.ElytronHttpClientCredentialUtils;
import org.wildfly.security.http.client.utils.ElytronHttpClientRequestBuilder;

import java.net.URI;
import java.net.http.HttpRequest;
import java.util.HashMap;
import java.util.Map;

public class ElytronHttpClientBearerAuthMechanism {

public static HttpRequest evaluateMechanism(URI uri, String method, String body, Map<String, String> headers) {
String token = ElytronHttpClientCredentialUtils.getToken(uri);
if(headers == null){
headers = new HashMap<>();
}
public static HttpRequest evaluateMechanism(HttpRequest httpRequest) {
String token = ElytronHttpClientCredentialUtils.getToken(httpRequest.uri());
Map<String, String> headers = new HashMap<>();
headers.put(ElytronHttpClientConstants.AUTHORIZATION, getBearerHeader(token));
HttpRequest request = ElytronHttpClientRequestBuilder.buildRequest(uri, method, body, headers);
HttpRequest request = ElytronHttpClientRequestBuilder.buildRequest(httpRequest, headers);
return request;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

import java.net.URI;
import java.net.http.HttpRequest;
import java.util.Map;

/**
* Elytron client for HTTP authentication
Expand All @@ -33,9 +32,11 @@
*/
public class ElytronHttpClientDigestAuthMechanism {

public static HttpRequest evaluateMechanism(URI uri, String authHeader, String method, String body, Map<String, String> headers) throws AuthenticationMechanismException {
public static HttpRequest evaluateMechanism(String authHeader, HttpRequest httpRequest) throws AuthenticationMechanismException {
URI uri = httpRequest.uri();

String userName = ElytronHttpClientCredentialUtils.getUserName(uri);
String password = ElytronHttpClientCredentialUtils.getPassword(uri);
return DigestHttpMechanismUtil.createDigestRequest(uri, userName, password, authHeader, method, body, headers);
return DigestHttpMechanismUtil.createDigestRequest(uri, userName, password, authHeader, httpRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,41 +45,39 @@
*/
public class DigestHttpMechanismUtil {

public static HttpRequest createDigestRequest(URI uri, String userName, String password, String authHeader, String method, String body, Map<String, String> headers) throws AuthenticationMechanismException {
public static HttpRequest createDigestRequest(URI uri, String userName, String password, String authHeader, HttpRequest httpRequest) throws AuthenticationMechanismException {
Map<String, String> authParams = updateAuthParams(authHeader);
String realm = authParams.getOrDefault("realm", null);
String nonce = authParams.getOrDefault("nonce", null);
String opaque = authParams.getOrDefault("opaque", null);
String algorithm = authParams.getOrDefault("algorithm", "MD5");
String qop = authParams.getOrDefault("qop", "qop");
String qop = authParams.getOrDefault("qop", "auth");
String uriPath = getUriPath(uri);
String cnonce = generateCNonce();
String nc = new String(DigestUtil.convertToHexBytesWithLeftPadding(Integer.parseInt(authParams.getOrDefault("nc", "0")), 8));
String resp;
if (qop == null) {
resp = computeDigestWithoutQop(uriPath, nonce, userName, password, algorithm, realm, method);
resp = computeDigestWithoutQop(uriPath, nonce, userName, password, algorithm, realm, httpRequest.method());
} else {
resp = computeDigestWithQop(uriPath, nonce, cnonce, nc, userName, password, algorithm, realm, qop, method);
resp = computeDigestWithQop(uriPath, nonce, cnonce, nc, userName, password, algorithm, realm, qop, httpRequest.method());
}

StringBuilder requestAuthHeader = new StringBuilder();
requestAuthHeader.append("Digest ");
requestAuthHeader.append(ElytronHttpClientConstants.CHALLENGE_PREFIX + " ");
requestAuthHeader.append("username=\"").append(userName).append("\", ");
requestAuthHeader.append("realm=\"").append(realm).append("\", ");
requestAuthHeader.append("nonce=\"").append(nonce).append("\", ");
requestAuthHeader.append("uri=\"").append(uriPath).append("\", ");
if(realm != null) requestAuthHeader.append("realm=\"").append(realm).append("\", ");
if(nonce != null) requestAuthHeader.append("nonce=\"").append(nonce).append("\", ");
if(opaque != null) requestAuthHeader.append("uri=\"").append(uriPath).append("\", ");
requestAuthHeader.append("qop=\"").append(qop).append("\", ");
requestAuthHeader.append("nc=\"").append(nc).append("\", ");
requestAuthHeader.append("cnonce=\"").append(cnonce).append("\", ");
requestAuthHeader.append("response=\"").append(resp).append("\", ");
requestAuthHeader.append("opaque=\"").append(opaque).append("\", ");
requestAuthHeader.append("algorithm=").append(algorithm);

if(headers == null){
headers = new HashMap<>();
}
Map<String, String> headers = new HashMap<>();
headers.put(ElytronHttpClientConstants.AUTHORIZATION, requestAuthHeader.toString());
HttpRequest request = ElytronHttpClientRequestBuilder.buildRequest(uri, method, body, headers);
HttpRequest request = ElytronHttpClientRequestBuilder.buildRequest(httpRequest, headers);
int updateNonceCount = Integer.parseInt(authParams.getOrDefault("nc", "0")) + 1;
authParams.put("nc", String.valueOf(updateNonceCount));
return request;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
package org.wildfly.security.http.client.utils;

import java.net.URI;
import java.net.http.HttpHeaders;
import java.net.http.HttpRequest;
import java.util.Map;

public class ElytronHttpClientRequestBuilder {
public static HttpRequest buildRequest(URI uri, String method, String body, Map<String, String> headers){
public static HttpRequest buildRequest(HttpRequest httpRequest, Map<String, String> headers){
String body = null;
if(httpRequest.bodyPublisher() != null){
body = httpRequest.bodyPublisher().toString();
}
String method = httpRequest.method();
URI uri = httpRequest.uri();
HttpHeaders httpHeaders = httpRequest.headers();

HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(uri)
.method(method, body != null ? HttpRequest.BodyPublishers.ofString(body) : HttpRequest.BodyPublishers.noBody());
Expand All @@ -16,6 +25,16 @@ public static HttpRequest buildRequest(URI uri, String method, String body, Map<
}
}

if (headers != null) {
httpHeaders.map().forEach((headerName, headerValues) -> {
if (headerValues != null && !headerValues.isEmpty()) {
for (String headerValue : headerValues) {
requestBuilder.header(headerName, headerValue);
}
}
});
}

return requestBuilder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ public void testElytonHttpClientBasicAuthenticationMechanism() {
try {
HttpServerAuthenticationMechanism mechanism = basicFactory.createAuthenticationMechanism("BASIC", Collections.emptyMap(), getCallbackHandler("user1", "test-realm", "password1", null));
URI uri = new URI("http://localhost:8080/servlet-security/SecuredServlet");
HttpRequest httpRequest = ElytronHttpClientBasicAuthMechanism.evaluateMechanism(uri, "GET", null, null);
HttpRequest request = HttpRequest.newBuilder()
.uri(uri)
.build();
HttpRequest httpRequest = ElytronHttpClientBasicAuthMechanism.evaluateMechanism(request);

//Test successful authentication
TestingHttpServerRequest testingHttpServerRequest = new TestingHttpServerRequest(new String[]{httpRequest.headers().allValues("Authorization").get(0)});
Expand All @@ -95,7 +98,10 @@ public void testElytonHttpClientBasicAuthenticationMechanismUnauthorizedUser() {
try {
HttpServerAuthenticationMechanism mechanism = basicFactory.createAuthenticationMechanism("BASIC", Collections.emptyMap(), getCallbackHandler("unauthorizedUser", "test-realm", "password", null));
URI uri = new URI("http://localhost:8080/servlet-security/SecuredServlet");
HttpRequest httpRequest = ElytronHttpClientBasicAuthMechanism.evaluateMechanism(uri, "GET", null, null);
HttpRequest request = HttpRequest.newBuilder()
.uri(uri)
.build();
HttpRequest httpRequest = ElytronHttpClientBasicAuthMechanism.evaluateMechanism(request);

//Test successful authentication
TestingHttpServerRequest testingHttpServerRequest = new TestingHttpServerRequest(new String[]{httpRequest.headers().allValues("Authorization").get(0)});
Expand Down Expand Up @@ -125,7 +131,10 @@ public void testElytonHttpClientBasicAuthenticationMechanismInvalidUser() {
try {
HttpServerAuthenticationMechanism mechanism = basicFactory.createAuthenticationMechanism("BASIC", Collections.emptyMap(), getCallbackHandler("user1", "test-realm", "password", null));
URI uri = new URI("http://localhost:8080/servlet-security/SecuredServlet");
HttpRequest httpRequest = ElytronHttpClientBasicAuthMechanism.evaluateMechanism(uri, "GET", null, null);
HttpRequest request = HttpRequest.newBuilder()
.uri(uri)
.build();
HttpRequest httpRequest = ElytronHttpClientBasicAuthMechanism.evaluateMechanism(request);

//Test successful authentication
TestingHttpServerRequest testingHttpServerRequest = new TestingHttpServerRequest(new String[]{httpRequest.headers().allValues("Authorization").get(0)});
Expand Down

0 comments on commit 0f7120b

Please sign in to comment.