Is session a good choice? - asp.net-mvc-4

We are building ASP.NET MVC app that is supposed to manage sport objects reservations (tennis courts, squash courts etc).
Users are not supposed to act only in scope of one club at the moment of interaction with app.
Navigation to the app should be like:
appname.com/clubName or
clubName.appname.com
Questions:
1. What would be the best way to persist the data about selected club. We have implemented storing in session (injecting information about the club durint app opening), but we read that using session is rather deprecated solution. We are using ApiController so in order to get the session we had to hack the routing (registering custom RouteHandler). Is session mechanism applicable for this problem?
var session = HttpContext.Current.Session;
if (session != null)
{
service.ClubName = session[CustomSessionKeys.ClubName.ToString()].ToString();
}
Is it good idea to use subdomains for our problem?
Many thanks in advance :)

Generally a web api works differently than a normal mvc app.
In an MVC application you would use a session cookie to make the internet act like a state machine. However, this is not what is generally done for web api's. In a web api, you provide some form of authentication (e.g. via the header authentication field).
But within a request you ofcourse want to to keep track of the current user, or in asp.net terms, the current principal.
We set the principle though a Delegation handler
HttpContext.Current.User = user;
If you want some more code on how this whole authentication is done, just let me know.
This was all serverside ofcourse, on the client side, you can keep any information you want in a session store. Although you might want to consider using the local storage in stead (depending on what semantics you want to give it). They both work in the same way.
You can consult W3C webstorage specification for the complete information on both of these.

Well you have many choices I guess!
Go with the route thing as you suggested, where you keep the club Id or name as part of the URL. I would go for this if I need the link to give more meaning to the user.
Cookie! yes, if the information is not sensitive store it in a cookie. In case this cookie is only to be accessed from server side, then don't forget to make it HttpOnly
Session. I agree with you, I wouldn't choose session unless the data was very sensitive and I needed to make it secure.

Related

Unifying auth between a Blazor Server UI and an (effectively external) API

I've a situation where I'm creating a Blazor Server front end for an API, and that API may also be used directly by some other systems. Essentially some smaller customers might use the UI, others (perhaps larger with their own dev team) build their own UI and use the API. We control both sets of code (for the Blazor and the API).
Auth in the api is done (at the moment) by sending a userid and a password and getting a JWT Bearer token that is added to all subsequent requests.
Auth on the BS app is (at the moment) done using Azure AD B2C; the templating in VS makes it an easy setup and then no really specialist knowledge is needed to maintain and add new users
There isn't any special link between the two for now; both are in dev and the BS app just has a hard coded u/p for a single dev user inthe API side. At some point that needs to change so the API serves more than one customer via the UI
It seems I have a couple of routes I could go down:
Make the BS app use the API for auth; in my mind this looks like setting up something similar to what you get when you make a new BS app with "Individual Accounts" auth, except it doesn't use EF on a database with tables for tracking identity - it would probably use a custom store and usermanager that asks the API for auth instead of some DB, and then some (hopefully simple) mechanism of getting the returned token from the API into every httpclient that ends up being used to poke the API (they're abstracted away into proxies built by NSwag but it's easy enough to address because NSwag code calls a particular overridable method to setup the headers.. finding a way to have the httpclientfactory do it might be even easier)
Make the BS app and the API use AD B2C for auth. As a workflow I genuinely have no idea how that's done or what it looks like.
Of the two I'd prefer the latter because it hands off some additional responsibility to AD, such as maybe in future we want to have UI customers also do 2FA but I'm not really sure how to go about researching it. How do we go about sharing auth between the two systems?
I'm not looking for code; some rudimentary instructions on how to share the authenticated identity between the BS app and the API is really what I need. If it's not an achievable goal, what alternative mechanism for Blazor Server do I have that would allow easy sharing of a retrieved bearer across a everything the user might do in a "session" (I don't mind if they lose SignalR connection and have to log in again)?
If either of the approaches above look like I'm just making life hard work, and it should be done another way, an outline of the steps required to make it go would be ideal

Handling authorization with IdentityServer4

I'm extremely confused on how to use a centralized IDP with both authentication and authorization. The architecture for my project was to be a single web API and one React client. I wanted to keep things structured out into microservices just to try something more modern, but I'm having major issues with the centralized identity, as many others have.
My goal is fairly simple. User logs in, selects a tenant from a list of tenants that they have access to, and then they are redirected to the client with roles and a "tid" or tenant id claim which is just the GUID of the selected company.
The Microsoft prescribed way to add identity in my scenario is IdentityServer, so I started with that. Everything was smooth sailing until I discovered the inner workings of the tokens. While some others have issues adding permissions, the authorization logic in my application is very simple and roles would suffice. While I would initially be fine with roles refreshing naturally via expiration, they must immediately update whenever my users select a different tenant to "log in" to. However, the problem is that I cannot refresh these claims when the user changes tenants without logging out. Essentially, I tried mixing authorization with authentication and hit a wall.
It seems like I have two options:
Obtain the authorization information from a separate provider, or even an endpoint on the identity server itself, like /user-info but for authorization information. This ends up adding a huge overhead, but the actual boilerplate for the server and for the client is minimal. This is similar to how the OSS version of PolicyServer does it, although I do not know how their paid implementation is. My main problem here is that both the client and resource (API) will need this information. How could I avoid N requests per interaction (where N is the number of resources/clients)?
Implement some sort of custom state and keep a store of users who need their JWTs refreshed. Check these and return some custom response to the caller, which then uses custom js client code to refresh the token on this response. This is a huge theory and, even if it is plausible, still introduces state and kind of invalidates the point of JWTs while requiring a large amount of custom code.
So, I apologize for the long post but this is really irking me. I do not NEED to use IdentityServer or JWTs, but I would like to at least have a React front-end. What options do I have for up-to-date tenancy selection and roles? Right when I was willing to give in and implement an authorization endpoint that returns fresh data, I realized I'd be calling it both at the API and client every request. Even with cached data, that's a lot of overhead just in pure http calls. Is there some alternative solution that would work here? Could I honestly just use a cookie with authorization information that is secure and updated only when necessary?
It becomes confusing when you want to use IdentityServer as-is for user authorization. Keep concerns seperated.
As commented by Dominick Baier:
Yes – we recommend to use IdentityServer for end-user authentication,
federation and API access control.
PolicyServer is our recommendation for user authorization.
Option 1 seems the recommended option. So if you decide to go for option 1:
The OSS version of the PolicyServer will suffice for handling the requests. But instead of using a json config file:
// this sets up the PolicyServer client library and policy provider
// - configuration is loaded from appsettings.json
services.AddPolicyServerClient(Configuration.GetSection("Policy"))
.AddAuthorizationPermissionPolicies();
get the information from an endpoint. Add caching to improve performance.
In order to allow centralized access, you can either create a seperate policy server or extend IdentityServer with user authorization endpoints. Use extension grants to access the user authorization endpoints, because you may want to distinguish between client and api.
The json configuration is local. The new endpoint will need it's own data store where it can read the user claims. In order to allow centralized information, add information about where the permissions can be used. Personally I use the scope to model the permissions, because both client and api know the scope.
Final step is to add admin UI or endpoints to maintain the user authorization.
I ended up using remote gRPC calls for the authorization. You can see more at https://github.com/Perustaja/PermissionServerDemo
I don't like to accept my own answer here but I think my solution and thoughts on it in the repository will be good for anyone thinking about possible solutions to handing stale JWT authorization information.

Simple RESTful API authentication

I'm building a single-page web application, fully based on RESTful API. I've seen several topics in that matter, but some things remain unclear for me.
I will need users to log in. Here are some of my ideas:
I can send e-mail and password to API and use basic auth. I'm not sure where should I keep password, should it be encrypted and if so: how?
Can I use built-in session system instead? Is it wrong to use cookies directly in the RESTful API? Why is it so popular to send credentials/keys to API itself instead of using cookies?
I thought about having one API key per user, return it in login action and keep it in localStorage. I guess it's not the greatest idea to have just one key per user?
Then, I came up with idea to have separate keys table and add random keys each time somebody logs in. On logout, the key would go away and no longer be valid. This is more secure than previous idea.
How is it solved in simple projects? I'd like to make it simple but not ridiculously inserure.
Please help.
The commonly approach is to use the header Authorization in REST. The state of the application must be on the client side with REST and shouldn'a be tied to a particularly client kind (browser with cookies)
I think that this link could be helpful:
Implementing authentication with tokens for RESTful applications : https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/
There is also à great question to à similar question here : https://softwareengineering.stackexchange.com/questions/141019/should-cookies-be-used-in-a-restful-api
Hope it helps,
Thierry

How much state can I save in session variables for a web app?

I'm coding up a REST/RPC API for a web app that I'm creating. From what I've learned it seems like one of the core ideas behind REST is to not maintain any state. That said I find myself doing things like marking a session as authenticated on the server side of things and this feels like saving state. How far should I take this practice? Where should I draw the line? There are other things that would be really convenient to save as part of the session's variables but I'm wondering how do I know when I shouldn't or shouldn't do this.
I hope this is the right venue to ask this question. I debated on whether or not to post it in programmers but this just felt more appropriate.
UPDATE:
I'm told that using a ticketing system is better than using session variables to maintain things like auth information. Could someone include and answer that has a very highly description of how such a ticketing system would work?
You are correct - REST calls are ideally stateless, and storing something in a session variable, and using that for the REST call, is anathema. You can't, for instance, guarantee that a RESTful client can even send the cookie information necessary for the session variables.
If you need authentication, then you should have REST calls that return something like a ticket, then the REST caller would send that ticket as part of another call.
UPDATE
For a ticketing system, you generally want to use the same auth or similar auth system. For instance, if you require a user name and password, you might want the ticket request to POST that. A ticket is a GUID that is passed on subsequent calls. The ticket on the server can be stored in session, or in a DB (I typically have a TICKETS table, with things like expiration dates).
$result = file_get_contents('http://site.com?action=auth&user=matt&password=pass');
// parse $result XML for ticket or auth error
// subsequent calls...
$result = file_get_contents('http://site.com?action=getSomething&ticket=" . $ticket);
QuickBase works this way - you send an API_Auth action with a username, password and api app token, and get a ticket in return. Then you pass your api app token and the ticket on subsequent calls - both GET requests and POST sends.

How do I implement a single sign-on for different ColdFusion applications running on the same server?

I have multiple CF applications running on the same server under the same domain name. One of them, let's call it Portal, is intended to be the single sign-on for the other applications, which let's call Atlas and P-Body. Normally you would set some variables in the session scope to handle login info:
function Login()
{
session.auth = structNew();
session.auth.isLoggedIn = true;
session.auth.id = GetCurrentUserId();
}
But the session scope is only shared within one application, not the entire server. This means that any user who logs into Portal will stay logged in, but if they try to navigate to Atlas or P-Body, they will have to sign in again.
In this case, how would I 'share' the session scope so that all the applications on a server can get access to it? The only way I've been able to come up with is to use client variables and set a data store so that it's shared between applications. Then the code becomes:
function Login()
{
client.auth = structNew();
client.auth.isLoggedIn = true;
client.auth.id = GetCurrentUserId();
}
function Logout()
{
structDelete(client, "auth");
}
The thing to watch out for here is that, because the client variable is not cleared on session end, we have to manually clear it in the OnSessionEnd handler.
Is this the best way of handling single sign-on in ColdFusion? If so, are there any drawbacks to using the client variable, or pitfalls to watch out for?
Update: I just tested the client variable method and it looks like only the hitcount, timecreated, lastvisit, and urltoken are shared between applications, so I'm back to square 1.
Posting this as the answer given new information.
Caveat
Ensure that all of the applications have either a) unique application scope names for persistent variables, or b) all application scope variables for the same purpose are named the same.
Alright, with that out of the way, if all of your applications are on a single domain in subfolders, then change this.name or the name attribute of cfapplication the same, and all of the applications will share the same session and application scope variables. This will ensure that if you use session.loggedin in one app, that same session.loggedin variable will be available to all applications with the same name under that domain.
You just have to test carefully to make sure that you don't end up using Application.LoginService in Portal for your LoginService.cfc, and Application.LoginService in Atlas for either a different LoginService.cfc, or a completely different purpose altogether.
Single Sign On (SSO) is not an easy thing to do and there are several very expensive products out there that help to prove that.
Fortunately, there are some free OSS projects out there are well.
There are also many other considerations with SSO that make its implementation difficult, like how do you handle it when a user clicks "Log off" on one of the sites? Do you log them out of all of them? If so, how?
If you want to do SSO right, you need to look at using an SSO solution, like Shibboleth (FOSS), or Atlassian Crowd (Reasonably priced commercial solution).
If you do not have the resources to use an SSO product like those above, then you will end up hacking around the current security restrictions that make SSO so difficult.
You're very close with the client variable solution.
Set up a remote database that all applications can speak to, either through the DSN, or through another single point of entry (ie. a WebService)
Decide on a common way to identify users across all your applications (ie. come up with your own unique sessionid, perhaps based off of CFID/CFTOKEN, CreateUUID(), or anything else you can guarantee is unique).
Build your authentication process so that when someone authenticates somewhere in your application farm...anywhere...that unique sessionid is stored to the remote database.
Pass that unique sessionid from app to app. Perhaps append it to your hyperlinks, or store it in client variables (cookies) that you mentioned earlier.
Finally, in your application logic that checks to see if someone is authenticated, before forcing them to login again...use their client variables (or the passed unique sessionid) to check back with the remote datasource, and auth them if you have found/verified it.
This is an oversimplification, but is the foundation for SSO, and should get you thinking in the right direction.
PS: Keep all your applications on the same domain, if possible (xx.mysite.com, yy.mysite.com) so that your client vars (cookies) can be set to be domain-specific, allowing them to traverse the application farm as you need them to.
Use the server scope. It is shared across applications.
http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec0c35c-7fdb.html