Why is RestEasy Quarkus ResponseFilter not getting called after 401 status? - response

Hi this is my ResponseFilter:
#Provider
#Priority(Priorities.AUTHENTICATION)
public class ResponseLoggingFilter implements ContainerResponseFilter {
if (containerResponseContext.getStatus() != Response.Status.OK.getStatusCode()) {
switch (containerResponseContext.getStatus()) {
case 401:
// Do something
break;
The thing is we are using JWT which is automatically evaluated by Quarkus.
Unfortunately when the JWT is invalid my ResponseFilter is not getting called.
So what should happen in case of 401 status code is not executed.
Does anyone know what to do in case of Quarkus and RestEasy ??

Related

Adding a Policy-based Authorization skips JWT bearer token authentication check?

I have a REST API service that implements JWT bearer token based authentication obtained from Azure AD.
// add support for custom Authorization policies
services
.AddAuthorization(authoptions =>
{
authoptions.AddPolicy("MemberOfUsersADGroup", policy =>
policy.Requirements.Add(new IsMemberOfUsersADGroup())
);
})
.AddSingleton<IAuthorizationHandler, IsMemberOfUsersADGroupAuthHandler>();
// add support for this service to recieve OAUTH2 JWT bearer tokens
services
.AddAuthentication(authOptions =>
{
authOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
// token validation (REQUIRED)
options.Audience = "AUDIENCE GUID";
options.Authority = String.Format("https://login.microsoftonline.com/[TENANTGUID]/");
});
And here's how the policy authorizaton handler is implemented. IT returns success unconditionally.
public class IsMemberOfSenseiUsersADGroup : IAuthorizationRequirement
{
}
public class IsMemberOfUsersADGroupAuthHandler : AuthorizationHandler<IsMemberOfUsersADGroup>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IsMemberOfUsersADGroup requirement)
{
// unconditional success for now
context.Succeed(requirement);
return Task.CompletedTask;
}
}
CASE 1
If I decorate my controller like this, and call without a bearer token, then I get a 401 as expected.
[Authorize]
[Route("api/dostuff")]
public class DoStuffController : Controller
{
CASE 2
HOWEVER, if I decorate my controller with the Policy, and call without a bearer token, then the REST API call passes fine and doesnt require a bearer token at all!!! I see the call enter into the AuthHandler HandleRequirementAsync() and then it succeeds, even tho bearer tokens were not passed in.
[Authorize(Policy = "MemberOfUsersADGroup")]
[Route("api/dostuff")]
public class DoStuffController : Controller
{
I am unable to explain this behavior at all. I am glad I caught this in my testing because I assumed the policy check is additive (as indicated by "AddPolicy" call), but it seems to replace the entire validation chain incl. the one done by JWT bearer middleware in CASE 1.
Am I doing something wrong? Is it related to the ordering of the Add*** calls made in ConfigureServices() How do I make sure the JWT bearer token validation occurs no matter if the policy authhandler checks pass or not?
That's the expected behavior.
If you want your authorization policy to reject unauthenticated requests, simply call builder.RequireAuthenticatedUser().
I've had a same problem. My workaround was that I put controller under default [Authorize] attribute and then every action has it's own policy [Authorize(Policy = "MemberOfUsersADGroup")]. To me it wasn't such a big deal because I had only one controller which action's was under the same policy. RequireAuthenticatedUser and similar wasn't necessary.

How do I set up an OAuth2RestTemplate with client credentials and automatic token refresh in spring-security-oauth 2.2.1.RELEASE

I am implementing a client that authenticates with OAuth2 against WSO2 and I have serious trouble refreshing the access token, getting 401 UNAUTHORIZED. While I have already found out, what the Spring OAuth2 code does, I do not know why its behavior was changed in 2.2.1.RELEASE and to me it seems plain wrong. Actually using 2.0.14.RELEASE works.
Before I am going to show to you, what I have done and what I have already found out, let me formulate my question:
How am I supposed to realize an OAuth2 client with automatic token refresh with client credentials instead of user credentials?
So here is, what I have implemented so far. The client configures an OAuth2RestTemplate with ResourceOwnerPasswordResourceDetails with isClientOnly flag true, as there are no user sessions. The client session can successfully be established and an access token and a refresh token are set.
#Bean
protected OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails() {
#Override
public boolean isClientOnly() {
return true;
}
};
List<String> scopes = new ArrayList<>(2);
scopes.add("write");
scopes.add("read");
resource.setScope(scopes);
resource.setGrantType("password");
resource.setAccessTokenUri(TOKEN_URL);
resource.setClientId(MY_CLIENT_ID);
resource.setClientSecret(MY_CLIENT_SECRET);
resource.setUsername(MY_SERVICE_USER);
resource.setPassword(MY_SERVICE_USER_PW);
return resource;
}
#Bean
public OAuth2RestOperations restTemplate() {
AccessTokenRequest atr = new DefaultAccessTokenRequest();
OAuth2RestTemplate template = new OAuth2RestTemplateWithBasicAuth(resource(), new DefaultOAuth2ClientContext(atr));
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
interceptors.add(new LoggingRequestInterceptor());
template.setInterceptors(interceptors);
template.setRetryBadAccessTokens(true);
return template;
}
So far so good. I have verified that this basically works.
But as soon as the access token expires I frequently run into 401 errors, because the token refresh is not executed. Instead, an ordinary authentication request is carried out, but using the client key and secret instead of user/password. To cut a long story short, I have debugged my way through spring-security-oauth2 into AccessTokenProviderChain#obtainAccessToken and found out, that whether a token refresh request is executed is decided upon in the following bit of code. See on Github
if (resource.isClientOnly() || (auth != null && auth.isAuthenticated())) { // P1
existingToken = request.getExistingToken();
if (existingToken == null && clientTokenServices != null) {
existingToken = clientTokenServices.getAccessToken(resource, auth);
}
if (existingToken != null) {
if (existingToken.isExpired()) {
if (clientTokenServices != null) {
clientTokenServices.removeAccessToken(resource, auth);
}
OAuth2RefreshToken refreshToken = existingToken.getRefreshToken();
if (refreshToken != null && !resource.isClientOnly()) { // P2
accessToken = refreshAccessToken(resource, refreshToken, request);
}
}
else {
accessToken = existingToken;
}
}
}
As you can see at P1, the block is entered if either an authorized user session exists (auth) or the resource is configured as clientOnly. As I do not have users but I am in a linked service scenario, I have isClientOnly() == true && auth == null. But at P2 the final decision upon actually doing the refresh is contraticted by requiring !isClientOnly(). So this effectively bans refresh requests in client only scenarios.
This was the way to go in versions before 2.2.1 and I have found out, that this seems to be a fix to the following Issue. To me this seems plain wrong.
Furthermore, to me the patch appears to break client functionality to fix an actual server misbehavior. As you can see in the issue discussion, I have already commented the there. But as that issue is closed and the spring-security-oauth2 forum states that discussions should be held here on StackOverflow, I am asking for help here.
Again the question: How should a client application be configured to consume OAuth2 secured services via OAuth2RestTemplate and an access token runtime of an hour and refresh token runtime of lets say two hours.

What could cause the original 'OAuth2' state parameter to be null in org.springframework.social.connect.web.ConnectSupport?

I am trying to use Spring Social on my application and I noticed while debugging that the original 'OAuth2' state parameter is always null on my app.
See Spring Social source code for org.springframework.social.connect.web.ConnectSupport below:
private void verifyStateParameter(NativeWebRequest request) {
String state = request.getParameter("state");
String originalState = extractCachedOAuth2State(request);//Always null...
if (state == null || !state.equals(originalState)) {
throw new IllegalStateException("The OAuth2 'state' parameter is missing or doesn't match.");
}
}
private String extractCachedOAuth2State(WebRequest request) {
String state = (String) sessionStrategy.getAttribute(request, OAUTH2_STATE_ATTRIBUTE);
sessionStrategy.removeAttribute(request, OAUTH2_STATE_ATTRIBUTE);
return state;
}
Can anyone please help?
edit: I do see the state parameter being passed back by facebook:
Request URL:https://www.facebook.com/v2.5/dialog/oauth?client_id=414113641982912&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fconnect%2Ffacebook&scope=public_profile&state=0b7a97b5-b8d1-4f97-9b60-e3242c9c7eb9
Request Method:GET
Status Code:302
Remote Address:179.60.192.36:443
edit 2: By the way, the exception I get is the following:
Exception while handling OAuth2 callback (The OAuth2 'state' parameter is missing or doesn't match.). Redirecting to facebook connection status page.
It turned out that the issue was caused by the fact that I was relying on headers - as opposed to cookies - to manage the session.
By commenting out the following spring session configuration bean:
#Bean
public HttpSessionStrategy sessionStrategy(){
return new HeaderHttpSessionStrategy();
}
The oauth2 state parameter issue was sorted.
P.S. Now I have got to find a way to get Spring Social to work with my current configuration of Spring Session...
Edit: I managed to keep the HeaderHttpSessionStrategy (on the spring session side) and get it to work by implementing my own SessionStrategy (on the spring social side) as follows:
public class CustomSessionStrategy implements SessionStrategy {
public void setAttribute(RequestAttributes request, String name, Object value) {
request.setAttribute(name, value, RequestAttributes.SCOPE_SESSION);
}
public Object getAttribute(RequestAttributes request, String name) {
ServletWebRequest servletWebRequest = (ServletWebRequest) request;
return servletWebRequest.getParameter(name);
}
public void removeAttribute(RequestAttributes request, String name) {
request.removeAttribute(name, RequestAttributes.SCOPE_SESSION);
}
}
Try this work around and see if that works for you:
To my surprise I opened application in a 'incognito' browser and everything worked. Just like that. I think before something got cached and was causing the issue.
I ran into this issue today, My application was working perfectly fine. I just took a break for few hours and when I ran it again it started complaining about 'The OAuth2 'state' parameter is missing or doesn't match.'
The state param is first put into the session then the request goes out to facebook and the request comes back with the same state param but when spring is looking for session object to get the state param, it is not finding the session. I think it is not finding the session because when the request comes back it thinks that it is a different client (or host), even though the old HttpSession object still exists. The container maintains a HttpSession per client.
What you're getting from Facebook is not a request attribute , it's a request parameter.
You should get it by something like:
request.getParameter("state")

Override error code on AuthorizationCodeProvider.Create

This question is about the implementation of the Authorization Code flow using Owin in Asp.net Wep Api.
I was trying to handle some error that might happen on my AuthorizationCode code creation. Apparently I can't redirect my self to the Client Redirect URI with he correct error code which is "server_error"
The following is my code :
private static void CreateAuthorizationCode(AuthenticationTokenCreateContext context)
{
try
{
//Some Code to create and save the AuthorizationCode that can throw an Exception
context.SetToken(code);
}
catch (Exception ex)
{
logger.Fatal(ex);
var redirectUri = GetRedirectUri();
var redirectLocation = string.Format("{0}?code={1}", redirectUri, "server_error");
context.Response.Redirect(redirectLocation);
}
}
But I get redirected by the framework to the redirect Uri with https://redirecturi?error=unsupported_response_type !
Is this a normal behavior ? Or maybe there is any other way to handle those kind of scenario and set by myself the error code !?
PS : I created an issue in Github about that : https://github.com/aspnet/Security/issues/375 no answer so far !
Thank you.
Is this a normal behavior ? Or maybe there is any other way to handle those kind of scenario that I'm missing?
Normal, I dunno. But expected, definitely: when using an IAuthenticationTokenProvider, you're not supposed to alter the HTTP response.
Why there is not way to set by myself the error using the AuthenticationTokenCreateContext object like context.SetError("my_error") ?
Unlike the ValidateAuthorizeRequest notification, it hasn't been designed to allow you to return an error.
Sadly, there's no way to return a server_error response from an IAuthenticationTokenProvider, since OAuthAuthorizationServerHandler will always use unsupported_response_type if you don't provide an authorization code: https://github.com/jchannon/katanaproject/blob/master/src/Microsoft.Owin.Security.OAuth/OAuthAuthorizationServerHandler.cs#L204
FYI, this is something we fixed recently in AspNet.Security.OpenIdConnect.Server (a fork of the OAuth2 authorization server shipped with Katana 3): https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/issues/112#issuecomment-125040925. If your custom code returns a null authorization code, a server_error response will be automatically returned to the client application.

Difference between Token Interceptor and Token Session Interceptor?

I Know that both the interceptors are used to prevent duplicate form submissions? But What really are the difference between both of them?
Which one has extra edge over other?
The tokenSession extends token interceptor, they are both used to ensure that only one request per token is processed. The difference is in the handling of the invalid tokens.
When invalid token is found the token interceptor just returns invalid.token result. The tokenSession interceptor on invalid token will try to display the same response that would have been displayed in case of valid token.
Some pseudo code for illustrating workflow of the tokenSession interceptor:
intercept() {
if(validToken){
storeInvocation();
return invocation.invoke();
}else {
ActionInvocation storedInvocation = loadStoredInvocation();
// ...
return storedInvocation.getResultCode();
}
}

Resources