How to ignore session in specific filters - shiro

We have a few filters that run and we are trying to implement the "hybrid" approach mentioned in the documentation.
Users can login through a web form and in most cases that is ok and using the created session works fine, but for /api/** calls we want to force the use of a tokens and ignore an authenticated user who may of come from a form login.
/api/content/** : jwt, api, user
/api/**: noSessionCreation, jwt, api, end
/**: jwt, api, user
We would like the /api/** to ignore any authenticated subjects that come from a session (created by a form login). Right now, if I login through the form page the session carries over to the /api calls and bypasses the need for the token being passed in on the url.
So, once I login from the form these calls will work:
/api/info
/api/info?token=123
/api/content/hello.png <-- This is the only one i want to work based off of the logged in user from the from
Our goal, basing of of the hybrid approach mentioned in the documentation is:
/api/** calls must be stateless and always use the token passed to the call.
/api/content/** can use a session, from a form login or the standard filter chain jwt and api calls
/** can pretty much take in anything - session or token.
Is there a way to recognize and forcibly (in a filter?) ignore authenticated users that come from the session?

Sounds like you would need to implement your own filter.
the noSessionCreation filter will not create a session but does not stop the use of an existing one.

Related

JWT default GET action limitation?

I've successfully used cookies before and I'd like to begin using JWT. My biggest question is how to pass your token to a website during the initial GET operation, for example when a user types your domain into their address bar or clicks on a link from some other website like google.
When using cookies for example, if you type stackoverflow.com into your web browser, the persistent cookie is sent to the website which seamlessly allows your own stackoverflow session to be automatically authorized.
I am aware that I can programatically pass my JWT token via a javascript GET through the HTTP headers but how do you pass the token when a visitor types in your URL into their web browser?
Possible solution #1
My thoughts have been to have javascript code check if 'authorized'. If not, check for a JWT token in local storage. If found, redirect to the same address. The problem of course would be that there is no way to pass the token during a redirect.
Possible solution #2
Similar to above but not issuing a redirect, I would update the current page to reflect the 'authorized' state.
Possible solution #3
Use a permanent cookie containing the JWT token. I am thinking that this 3rd option would be the best. If I did this, there would be no need to pass the JWT via an HTTP header.
I've thought about this for a few days, read up on JWT and here are my conclusions for avoiding JWT in my particular case:
No easy way to authorize a user who opens their browser and types in your website. With cookies, your server immediately knows how to respond to this headerless GET request.
No way to easily change the JWT token signature. All users are immediately affected by such a change, essentially forcing everyone to authenticate again.
No way to easily invalidate a specific JWT token. The best you can do is to maintain and check a banned signature list on the server. This of course would require a centralized or distributed server method almost identical to a cookie session management system. This would force a coupling between the token and the server, no longer stateless as intended by JWT.
SUMMARY
Cookie management requires more server infrastructure but you have much greater session control. State is seamless (in the case of #1 above). You can instantly invalidate state. For example, the user can log out (deleting the session at the server level) or the session can be instantly banned by an administrator by simply deleting the session.
I also see the benefits to JWS:
no need to hit the db or cache system when authorizing.
simple authorization between multiple servers having the secret key.
simple authorization, no session management programming and no db session state storage required.
...but the drawbacks stated previously are too great for my particular needs.

Can I use the access token directly from FB.login on my server?

I'd like to implement a Facebook authentication that does not perform traditional oauth redirects. It doesn't play nicely with my single-page-application and GraphQL API.
On the JS side, I can invoke FB.login to trigger a dialog for the user to login. If this is successful, I receive an object containing an accessToken and a signedRequest.
signedRequest can be decoded on the server and it spits out a code for me. I can use code with /oauth/access_token to get an accessToken.
However, I already had the accessToken this whole time from the FB.login response. So my question is: is there any point of me decoding the signed request, if I had the access token this whole time?
Bonus: Why does the FB API provide a signed request in the first place, and why does the oauth redirect by default forward the code and not an accessToken?
Yes, you can use the token you got from the client-side login, directly on the server.
It might however be a short-lived one, whereas the server-side login flow should give you a long-lived one right away. If you only need to perform API calls while the user is active on your page, the short-lived one will probably do. (And it could still be exchanged for a long-lived one with a server-side API call, https://developers.facebook.com/docs/facebook-login/access-tokens/refreshing)
Why does the FB API provide a signed request in the first place
It also contains a bit more info, that might be useful for a client-side app (user id, token expiry, externally passed in data in case of the old “Canvas” type apps), and might save on one additional API call to get that kind of info. https://developers.facebook.com/docs/reference/login/signed-request/
and why does the oauth redirect by default forward the code and not an accessToken?
General security measure. The token contained directly in the return URL, could easily be stolen by 3rd-party scripts that might be embedded on that page (ad servers etc. can get hacked from time to time, too), or leaked as part of the HTTP referrer.
The code parameter requires your app secret for the API call that exchanges it for a token, so if the code were to leak in any such way, whoever else got their hands on it, can’t do anything with it.

Limit user access to api calls?

I am creating a rest api to be the backend for a messaging app. I want a user to only have access to their own data. For example user1 can call /users/user1 but not /users/user2. How would I go about doing this.
So first the user will login and be authenticated via their username and password. But where do I go from here? I was thinking of storing a token with the users data so when they access it I can verify that the pair matches but there must be a better way to do this. Do I need to restructure my api?
After the user logs into the system, you should provide them a token or initialize a session for that user. In each consecutive call, the user should send the token to the API. As long as the token/session is alive user should be able to call the API.
You should have a way to verify the user token in the backend for each API call. A very popular way of doing this is to use JWT(JSON Web Tokens) based authentication.
See here for an example using python and flask: https://realpython.com/token-based-authentication-with-flask/
Once you verify the user, you should parse the user id to the database query in order to filter out the data for that user.
Even though I don't understand your full use case, it seems like you need to restructure your API calls as well. You should not provide API calls per user. What happens when the numbers of users increase in your system dynamically?
So you should either accept user id as a parameter or you should let the JWT authenticator take care of it.
Example REST API call would be
GET /user/data?userId=1234

IdentityServer3 - Contacting IdP after user is authenticated

We have SPA, IdSvr3, and a third party IdP(AAD B2C).
The user authenticates successfully. When the user clicks an edit profile link in the SPA, they are directed to IdSvr using the authorization_endpoint. I pass in an acr_value called "profile."
I believe this is the same problem as this gentleman- https://github.com/IdentityServer/IdentityServer3/issues/2816#issuecomment-217161898
I've tried a few things:
Implemented ICustomRequestValidator.ValidateAuthorizeRequestAsync.- In this method, I retrieve the acr_values. There doesn't appear to be a good way to direct the user from here. There is the RedirectUrl on the ValidatedAuthorizeRequest that does redirect the user, but all the information on that object is from the client request to IdSvr and is not relevant to the IdP.
Perhaps there is a setting on the ValidatedRequest that could be tweaked to force IdSvr to direct over to the identity provider(in this case the IdP is - Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthentication)
Implemented a UserService. If the user is logged in, the events trigger IsActiveAsync and GetProfileDataAsync. In IsActiveAsync I can get the acr value from the HTTP context, and set IsActive to false, forcing IdSvr to go back to the IdP. I can't access the context from OpenIdConnectAuthenticationNotifications.RedirectToIdentityProvider, so I haven't found a way to access the acr value there. Is there a way to pass something into here to check if this should be an edit profile?
Similar to the UserService I've implemented IsAuthenticationSessionValidAsync to invalidate the session and force the idsvr to direct to the Idp. This has the same issue of not being able to access the acr value.
PartialLogin doesn't appear to be the right strategy for this either because it appears to only be triggered from a user who isn't authenticated yet. Perhaps if we force the user to log-out, this could be used to direct them to the IdP? https://identityserver.github.io/Documentation/docsv2/advanced/userService.html
Logging the user out feels like the wrong approach to begin with, but it seems like it could be made to work.
Is there a standard way of intercepting a request and directing it over to the IdP based on something in the request?

Spring boot REST token authorization and authentication best practices

What is the best practise for authorization and authentication of users in REST spring boot?
I am building web app with standard pages + REST API for mobile. I looked at many articles about Spring security and basically most of them goes with some sort of fitler approach that will allow or block REST calls. In my case, however, I have some auth logic based on who the user is. For example, there is a /update API that updates user information, and user can update himself, but cannot update other person.
Initially I thought to use next auth schema:
User calls auth API and pass name/password or cookie
System generates short life token, saves in it's database.
User get this token, updates his cookie (so JS in web application can read and use it)
When REST call is being make cookies are passed. At Controller, token is extracted, checked for expiration, query is done to database to validate token and get user id.
Based on user id, REST will be permited or blocked.
Is this the right approach to implement? I have a pretty big mess in my head after reading articles about spring boot security.
At least: session auth will not work for me (REST is stateless). I want to make auth for mobile device without storing login/password there.
Does it make sense to pass this token in the REST body itself? What in case of GET method?
Many thanks for sharing your knowledge.
Did you find a solution to your problem?
I have answered this problem elsewhere, if you are sure you won't want to open up the API to other developers/clients in the future (if you do then you should look at OAuth) then a simple token based solution will work.
Something basically along the lines of this:
Setup a standard html login page, that you can use for user login to the app
setup spring security to return a cookie on sucessful login with an authentication token
in your mobile app, embed a WebView (or equivalent) and load this login form - allow the user to login via that webview, on response grab the cookie and store the token (as mobile is generally single user, you can keep that pretty long to save mobile users having to keep logging in)
Add a security filter to the the REST API to authenticate against the token (from the mobile app pass the token in the header for example) - then you will be able to use normal spring authentication context for current users etc.
This approach is suggested by Google here: (EDIT: Google seems to have changed the page I originally read to be about using Google+ sign in and OAuth2.0 - I can't see a link to their general Mobile/API docs so here it is in the web archive :) )
I have also written up my implementation here:
Overview of the approach using Spring security
The code & details
Although this was really just an experiment/Proof of concept, it might be useful in your thinking.
Cookie approach seems perfect for the use case. Token can be tied up with user id. Filter can extract cookie and pass user id for example as header to apis - that should take care of GET...