JASPIC Login with Wildfly 9 Send HTTP Return Code - authentication

I'm still trying to implement a custom JASPIC login module for Wildfly 9. If the login is successful everything works as expected. But I would expect an HTTP 403 response, if the login is not successful. So I wrote this little test:
#Test
public void invalidCredentials() throws IOException, SAXException {
try {
WebConversation webConversation = new WebConversation();
GetMethodWebRequest request = new GetMethodWebRequest(deployUrl + "LoginServlet");
request.setParameter("token", "invalid");
WebResponse response = webConversation.getResponse(request);
fail("Got " + response.getResponseCode() + " expected 403!");
} catch (final HttpException e) {
assertEquals(403, e.getResponseCode());
}
}
The result is this:
Failed tests:
JaspicLoginTest.invalidCredentials:114 Got 200 expected 403!
I tried this three options to end the method validateRequest of the ServerAuthModule after invalid authentication:
return AuthStatus.SEND_FAILURE;
return AuthStatus.FAILURE;
throw new AuthException();
But none of the above produce a authentication failure HTTP response (403). Is this a Wildfly bug again? Or do I have to produce this return code in an other way?

Ok, obviously one can take the MessageInfo object and can do such like:
public AuthStatus validateRequest(MessageInfo messageInfo,
Subject clientSubject,
Subject serviceSubject) throws AuthException{
//Invalid case:
HttpServletResponse response =
(HttpServletResponse) messageInfo.getResponseMessage();
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return AuthStatus.SEND_FAILURE;
}

Related

got 'CancellationException: Request execution cancelled' always when throwing an exception in httpasyncclient callback

I use HttpAysnClient to do http requests, and I found when I throw an exception in the failed callback, the next request always be failed, how to fix it?
I use maven dependency: 'org.apache.httpcomponents:httpasyncclient:4.1.5'.
my java test code:
CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
try {
httpclient.start();
AtomicBoolean fireException = new AtomicBoolean(false);
while (true) {
try {
String url;
if (fireException.compareAndSet(false, true)) {
url = "http://localhost:8080"; // throw Connection refused
} else {
url = "http://www.apache.org/";
}
final HttpGet request2 = new HttpGet(url);
httpclient.execute(request2, new FutureCallback<HttpResponse>() {
public void completed(final HttpResponse response2) {
System.out.println("completed, " + request2.getRequestLine() + "->" + response2.getStatusLine());
}
public void failed(final Exception ex) {
System.out.println("failed, " + request2.getRequestLine() + "->" + ex);
throw new RuntimeException();
}
public void cancelled() {
System.out.println(request2.getRequestLine() + " cancelled");
}
});
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
TimeUnit.SECONDS.sleep(1);
}
}
} finally {
httpclient.close();
}
exception in the next requests: java.util.concurrent.CancellationException: Request execution cancelled
I can confirm same behavior with version 4.1.5.
I must confess it is quite surprising to see an application uncontrolled exception shutting down the whole client unexpectedly. In the context of an application reusing same client instance in multiple places, means the application client gets completely unsuable, with catastrophic consequences for the service.
You can use the "isRunning" method to evaluate if the client is under this situation, and potentially try to recreate the client again. But it is definately incovenient to see the client being shutdown like this.
After exercising the client with different conditions (error responses, slow responses...), the only way to reproduce this is to point to an invalid endpoint where no server is running. This is the condition presented in the original example.
I think I found the issue here https://jar-download.com/artifacts/org.apache.httpcomponents/httpasyncclient/4.1.5/source-code/org/apache/http/impl/nio/client/InternalIODispatch.java
You can see onException doesn't have a try/catch block to properly handle exceptions from the application.
I have confirmed this issue is fixed in Httpclient5 5.1.3. So other than fixing your application code to avoid uncontrolled exceptions, the solution is to migrate into the new Httpclient5 lib version.
you can see doc in https://hc.apache.org/httpcomponents-client-5.1.x/migration-guide/migration-to-async-simple.html
and if you want to use CloseableHttpClient you must start it client.start();

Not getting response with Http Async Client

I am stuck with this weird situation where sometimes my HTTP requests don't go out or I don't get a HTTP response to my request sporadically. My application makes several (100s) http requests to other 3rd party service periodically most of which work absolutely fine.
I use the CloseableHttpAsyncClient (Version 4.0) with a custom HttpRequestIntercerptor and HttpResponseInterceptor. These were mainly added for debugging purpose with the RequestInterceptor is the last interceptor in the chain and the ResponseInterceptor is the first one. The idea was to log each http request at the last stage before it sends the actual request and to log each http response when it is first received.
I have the following pattern to setup the async client:
HttpAsyncClientBuilder asyncClientBuilder = HttpAsyncClientBuilder.create();
asyncClientBuilder.addInterceptorLast(new MyHttpRequestInterceptor());
asyncClientBuilder.addInterceptorFirst(new MyHttpResponseInterceptor());
IOReactorConfig reactorConfig = IOReactorConfig.DEFAULT;
reactorConfig.setConnectTimeout(5 * 60 * 1000); // 5 mins
reactorConfig.setSoTimeout(5 * 60 * 1000); // 5 mins
asyncClientBuilder.setDefaultIOReactorConfig(reactorConfig);
System.setProperty("http.maxConnections", "100");
this.asyncHttpClient = asyncClientBuilder.useSystemProperties().build();
this.asyncHttpClient.start();
To make the request I do:
HttpGet httpGet = new HttpGet("some url");
asyncHttpClient.execute(httpGet, new AsyncHTTPResponseHandler(requestMetadata));
Here is my AsyncHTTPResponseHandler class:
class AsyncHTTPResponseHandler implements FutureCallback<HttpResponse> {
// local copy of the request for reference while processing the response.
private RequestMetadata requestMetadata;
public AsyncHTTPResponseHandler(final RequestMetadata requestMetadata) {
this.setRequestMetadata(requestMetadata);
Thread.currentThread().setUncaughtExceptionHandler(new HttpUncaughtExceptionHandler(requestMetadata));
}
#Override
public void cancelled() {
logger.error("AsyncHTTPResponseHandler#Http request id: {} cancelled",
requestMetadata.getRequestId()));
}
#Override
public void completed(HttpResponse response) {
logger.debug("Received HTTP Response for request id: {}",
requestMetadata.getRequestId());
//handleHttpResponse(requestMetadata, response);
}
#Override
public void failed(Exception e) {
logger.error("AsyncHTTPResponseHandler#Error in Http request id: " + requestMetadata.getRequestId(), e);
}
}
Based on this setup, I see the following cases based on my interceptors logs:
1. My application http request triggers an asyncclient HttpRequest and I get the HttpResponse -- Success.
2. My application http request triggers an asyncclient HttpRequest (the interceptor logs it) and I don't get the HttpResponse for this request --- Don't know why?
3. My application http request does not trigger an asyncclient HttpRequest (the interceptor does not log it) and I don't get the HttpResponse for this request --- Don't know why?
Any tips or suggestions on what I can do fix this or debug this problem further?
Thanks!!
So, thought I will share my findings and solution here.
We were experiencing symptoms similar to this bug: https://issues.apache.org/jira/browse/HTTPASYNC-79
If you enable DEBUG logging for "org.apache.http.impl.nio" package, then you can see the exchanges. Note: The logs will be very verbose.
The issue was resolved by upgrading the HttpAsyncClient library from 4.0 to 4.0.2. I have also enabled socket and Connection timeouts. You should see timeout exceptions in the log files with this.
Here is how my HttpAsyncClient instance looks now:
HttpAsyncClientBuilder asyncClientBuilder = HttpAsyncClientBuilder.create();
asyncClientBuilder.addInterceptorLast(new MyHttpRequestInterceptor());
asyncClientBuilder.addInterceptorFirst(new MyHttpResponseInterceptor());
// reactor config
IOReactorConfig reactorConfig = IOReactorConfig.custom()
.setConnectTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setSoTimeout(TIMEOUT_5_MINS_IN_MILLIS).build();
asyncClientBuilder.setDefaultIOReactorConfig(reactorConfig);
// request config
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setConnectionRequestTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setSocketTimeout(TIMEOUT_5_MINS_IN_MILLIS).build();
asyncClientBuilder.setDefaultRequestConfig(requestConfig);
// connection config
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setMalformedInputAction(CodingErrorAction.IGNORE)
.setUnmappableInputAction(CodingErrorAction.IGNORE)
.build();
asyncClientBuilder.setDefaultConnectionConfig(connectionConfig);
System.setProperty("http.maxConnections", "100");
System.setProperty("http.conn-manager.timeout", "300000"); // 5 mins
this.asyncHttpClient = asyncClientBuilder.useSystemProperties().build();

Get response and raw request when using proxies and resteasy client side framework 3.0.4

// Some setup steps
ResteasyProviderFactory factory = new ResteasyProviderFactory();
factory.registerProvider(com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider.class);
Client client = ClientBuilder.newClient(new ClientConfiguration(factory));
WebTarget target = client.target(webappURL.toURI() + "api/v1");
resteasyWebTarget = (ResteasyWebTarget) target;
// the real request
MyApiController myApiController = resteasyWebTarget.proxy(MyApiController.class);
ClientResponse response = (ClientResponse) myApiController.doSomeStuff();
The code above works great, but I want to really know what is going on in terms of real http request and real http response when
myApiController.doSomeStuff();
is executed.
I am wondering what the best way is to catch and log the "raw" request and a catch and log the "raw" http response. I am only interested in solutions for resteasy-client 3.0.2.Final or similar...
Thanks!
Not sure how to get it if everything went well (response code 200), but in case the server returned anything else, a sub type of ClientErrorException which gives you access to the response / status code / entity (message body) etc is thrown.
try {
myApiController.doSomeStuff();
} catch (BadRequestException ce) {
// Handle
} catch (ClientErrorException e) {
MyErrorObject obj = ce.getResponse().readEntity(MyErrorObject.class);
// Handle
}

Exception thrown when WebAuthenticationBroker receives an OAuth2 callback

The WebAuthenticationBroker doesn't seem to be able to handle navigation to my ms-app://. Just throws this ugly error as you will see below.
Steps
Call AuthenticateAsync(), including callback uri obtained at runtime: WebAuthenticationBroker.GetCurrentApplicationCallbackUri()
Go through authorize process, hit Allow.
Instead of returning, the broker shows the page Can't connect to service. We can't connect to the service you need right now. Unable to do anything, so I hit the Back button visible.
Debugger breaks on catch: "The specified protocol is unknown. (Exception from HRESULT: 0x800C000D)"
The callback for WebAuthenticationBroker.AuthenticateAsync() is received (according to Fiddler4 & the Event Viewer) but it throws the aforementioned exception as if it doesn't know how to interpret the ms-app:// protocol.
All examples imply my code should work but I think there's something less obvious causing an issue.
Code
private static string authorizeString =
"https://api.imgur.com/oauth2/authorize?client_id=---------&response_type=token";
private Uri startUri = new Uri(authorizeString);
public async void RequestToken() {
try {
var war = await WebAuthenticationBroker.AuthenticateAsync(
WebAuthenticationOptions.UseTitle
, startUri);
// Imgur knows my redirect URI, so I am not passing it through here
if (war.ResponseStatus == WebAuthenticationStatus.Success) {
var token = war.ResponseData;
}
} catch (Exception e) { throw e; }
}
Event Viewer log excerpts (chronological order)
For information on how I obtained this, read the following MSDN: Web authentication problems (Windows). Unfortunately this is the only search result when querying authhost.exe navigation error.
Information: AuthHost redirected to URL: <ms-app://s-1-15-2-504558873-2277781482-774653033-676865894-877042302-1411577334-1137525427/#access_token=------&expires_in=3600&token_type=bearer&refresh_token=------&account_username=------> from URL: <https://api.imgur.com/oauth2/authorize?client_id=------&response_type=token> with HttpStatusCode: 302.
Error: AuthHost encountered a navigation error at URL: <https://api.imgur.com/oauth2/authorize?client_id=------&response_type=token> with StatusCode: 0x800C000D.
Information: AuthHost encountered Meta Tag: mswebdialog-title with content: <Can't connect to the service>.
Thanks for reading, Stack. Don't fail me now!
Afaik, you need to pass the end URL to AuthenticateAsync even if you assume that the remote service knows it.
The way WebAuthenticationBroker works is like the following: you specify an "endpoint" URL and when it encounters a link that starts with this URL, it will consider the authentication process complete and doesn't even try navigating to this URL anymore.
So if you specify "foo://bar" as callback URI, navigating to "foo://bar" will finish the authentication, as will "foo://barbaz", but not "foo://baz".
Resolved! #ma_il helped me understand how the broker actually evaluates the redirect callback and it led me back to square one where I realized I assumed WebAuthenticationOptions.UseTitle was the proper usage. Not so. Up against Imgur's API using a token, it requires WebAuthenticationOptions.None and it worked immediately.
As an example to future answer-seekers, here's my code.
private const string clientId = "---------";
private static Uri endUri = WebAuthenticationBroker.GetCurrentApplicationCallbackUri();
private static string authorizeString = "https://api.imgur.com/oauth2/authorize?"
+ "client_id="
+ clientId
+ "&response_type=token"
+ "&state=somestateyouwant"
+ "&redirect_uri="
+ endUri;
private Uri startUri = new Uri(authorizeString);
public async void RequestToken() {
try {
WebAuthenticationResult webAuthenticationResult =
await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None
, startUri
, endUri);
if (webAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success) {
string token = webAuthenticationResult.ResponseData;
// now you have the token
}
} catch { throw; }
}

using request builder to authenticate user: Not working in spring security

I need to authenticate a user in a page based on the remember me cookie,
inspired by this site: Tutorial for checking spring authentication,
I came up with a solution for checking the authentication.
Changes made in my application
applicationContext-security.xml:
<intercept-url pattern='/**AuthenticationChecker.html' access="ROLE_ADMIN"/>
...
<form-login login-page="/Login.html" authentication-failure-url="/Login.html" always-use-default-target="true" default-target-url="/Main.html"/>
Gwt code:
try
{
RequestBuilder rb = new RequestBuilder(
RequestBuilder.POST, "AuthenticationChecker.html");
rb.sendRequest(null, new RequestCallback()
{
public void onError(Request request, Throwable exception)
{
RootPanel.get().add(new HTML("[error]" + exception.getMessage()));
}
public void onResponseReceived(Request request, Response response)
{
RootPanel.get()
.add(new HTML("[success (" + response.getStatusCode() + "," + response.getStatusText() + ")]"));
}
}
);
}
catch (Exception e)
{
RootPanel.get().add(new HTML("Error sending request " + e.getMessage()));
}
AuthenticationChecker.html is a simple blank html page,
from what I understand, as AuthenticationChecker.html requires role as admin, I should have got a 401 Unauthorized if remember me cookie was not present and a 200 OK if the user was authenticated and his cookie was present.
However, the output always shows: [success (200,OK)]
To cross check, i simply typed authenticaionChecker.html (without logging in) and it returned back to Login.html indicating that spring is indeed authenticating the user.
Am I doing something wrong here ?
If you look at the tutorial, you'll see that a 401 is only returned when you're using Basic Authentication. With form-based authentication, you have to check the response text for an error message. For example:
public void onResponseReceived(Request request, Response response) {
if (response.getStatusCode() != Response.SC_OK) {
onError(request, new RequestException(response.getStatusText() + ":\n" + response.getText()));
return;
}
if (response.getText().contains("Access Denied")) {
Window.alert("You have entered an incorrect username or password. Please try again.");
} else {
// authentication worked, show a fancy dashboard screen
}
}