I have built a service with user authorization via Google. My project is registered in Google APIs console and it has one Client ID for web applications which is strongly binded to my web domain.
Let imagine that in future I will decide to change my domain name. How would it affect users who are already registered? It seems that they would need to accept my application permissions again? What is the best way to deal with such kind of migration?
I am not sure what you mean by
strongly binded to my web domain.
Authentication is created using the client id and client secret pair in the Client ID for web applications The only thing that is specific to your domain is problem the Redirect URI. All the redirect URI does is tell the authentication server where to return the authentication to.
You could easily add a second redirect URI to another domain or another page on your domain. You could also add a new one and delete the old one it wont mater users will still have access because the client id and client secret haven't changed. So in the event you delete your current domain and create a new one just remember to change the Redirect URI to point to the new domain and the old authentication will still work.
Related
How do i dynamically specify redirect uri for Oauth2 Authorization code flow in spring security? I have a use case where the application is being accessed by multiple users using 2 to 3 different urls. A user using one particular url has no access to another url. In this case, i want to configure oauth2 so that i can just provide /login or something instead of the entire url
In my case I wanted to be able to login and use my web app from two different urls, one for running the frontend locally from localhost.app.mydomain.com and one real url like app.mydomain.com using Google to login.
Simple solution
To achieve this in Spring Security I registered two different ClientRegistration's with the exact same info, except for the name, registrationId and the redirectUri
From the frontend I can then control which Oauth2 client I use by invoking the different registrationId endpoints which in turn decides which domain I'm logged into and which redirectUri will be used based on if I'm running my frontend locally or not.
It is not truly dynamic but solves the case where you have a limited number or redirect urls that you know on beforehand which can be controlled from the frontend this way.
Dynamic solution
Another more common solution, which I also use in my code, would probably be to pass a state parameter with the call to the oauth client in Spring. That will then get passed on to google and be returned untouched to Spring security from the google login flow. This can have whatever info you want to decided by the frontend and then decoded in the backend and e.g. the SimpleUrlAuthenticationSuccessHandler use this data to setDefaultTargetUrl to this which will cause a redirect to wherever the frontend decided on a successful login.
I have a single realm with 3 single-page applications and a shared backend. I want to restrict the access to one of the SPAs so that users without a specific role can't log in.
But once you create a user in the realm, he can log in to every SPA client. I can restrict the endpoints of the backend but I don't want to programmatically reject the user in the specific SPA but automatically on the login page.
I tried to use client roles which don't seem to have an effect in this case. The only solution I have found so far is to create separate realms which I think is conceptually the correct way but unfortunately brings up some practical issues, e.g. the administrators of one realm must be able to manage (CRUD) users of another realm which seems fairly unintuitive.
users without a specific role can't log in - it isn't good requirement. How system will known if user has a specific role without log in (authentication)? Keycloak provides Open ID Connect SSO protocol, which is designated for authentication. After successful OIDC authentication is token generated, which may contains also user role. So only then authorization can be applied. So let's change requirement to: users without a specific role can't access SPA, which better fits into OIDC concept.
The mature OIDC SPA libraries offer authorization guard (name can differs, it is some kind of post login function), where authorization can be implemented. Authorization requires to have a specific role in the token usually, otherwise user is redirected to the custom route, e.g./unauthorized. That's the page, where you can say a reason for denying access. Common use case is also customization of the app based on the user roles. For example users with admin role will see more items in the menu than standard users - that's also kind of authorization. Random example of SPA library with authorization guard (I'm not saying that's a best implementation) - https://github.com/damienbod/angular-auth-oidc-client/issues/441
Keep in mind that SPA is not "secure" - user may tamper code/data in the browser, so in theory user may skip any authorization in the browser. He may get access to SPA, so it's is important to have proper authorization also on the backend (API) side. Attacker may have an access to SPA, but it will be useless if API denies his requests.
BTW: You can find hackish advices on the internet how to add authorization to the Keycloak client with custom scripting (e.g. custom scripted mapper, which will test role presence). That is terrible architecture approach - it is solving authorization in the authentication process. It won't be clear why user can't log in - if it is because credentials are wrong or because something requires some role in the authentication process.
You should indeed not create multiple realms, since that is besides the point of SSO systems. Two approaches are possible in your - presumably - OAuth 2.0 based setup:
restrict access at the so-called Resource Server i.e your backend
use a per-SPA "scope" for each SPA that is sent in the authentication request
The first is architecturally sound but perhaps less preferred in some use cases as you seem to indicate. The second approach is something that OAuth 2.0 scopes were designed for. However, due to the nature of SPAs it is considered less secure since easier to spoof.
I was able to restrict users access to application using following approach:
I've created to clients in my default realm (master) i called my clients test_client1 and test_client2 both of them are OIDC clients with confidential access by secret
I've created a role for each of them, i.e. i have role test_client1_login_role for test_client1 and test_client2_login_role for test_client2.
I've created a two users - user1 and user2 and assign them to client 1 and client2 role. But to restrict access to client1 i have to delete default roles:
That did the trick, when i am logging with user2 i see test_client2 and not test_client1 as available application:
But i did n't delete roles from user1 and therefore i could see both clients when i am log in with user1:
Therefore you should use different clients for your applications, assign to each of a client specific role and remove from users default roles and add one releted to specific application.
I wonder is it possible to get cookies under another domain rather than my current app domain name?
I am building an application which access to another website's api. If the user has already logged in from the other site, my browser will create a cookies under that domain name. For example, user logged in under www.example.com, my browser will store a cookies:
cookies['token'] under www.example.com domain. When user visit my website, www.mywebsite.com, how can I get the cookies under www.example.com in my rails server?
Any help is highly appreciate.
This can be done, but it requires the client, your website, and your other website to all work together. You have a client that knows how to authenticate to site A. It wishes to view site B as the user it knows how to authenticate against site A with. The basic way to accomplish this is to have the client contact site A, authenticate itself, acquire a token from site A that site B can trust, and then hand that token to site B.
Effectively, you want to build a very specific case of OpenID or OAuth. This is certainly possible, but you're going to need to make some changes to www.example.com in order for it to play along. If you're able to do this, great.
Start by reading everything about OAuth. You don't need to use that exactly (although you could), but it will help explain what you need to do: http://hueniverse.com/oauth/
You can share cookies across different subdomains of a domain but you CANNOT share cookies across multiple domain names.
Cookies are stored by the BROWSER and the browser will not allow you to access or store cookies from external domain names. It would be a huge security flaw if browsers did allow you to do this.
You can, however, share session data that is stored on your server between domain names. This may not be completely trivial, but since session information is stored on the SERVER, you can access the information on the server between apps if needed. If your session data is stored in a database, then all that is required is to give database access to both domains. If need be, you could actually open your database to an external domain name and have the external domain directly connect to the database on your server.
I'm trying to understand how authentication in ASP.NET MVC works. I do not want the built-in MembershipProvider creating a local database behind the scenes. I've also looked at some blog posts talking about custom membership providers. While looking for a much simpler forms authentication model, I found the following:
FormsAuthentication.SetAuthCookie("myusername", true);
FormsAuthentication.SignOut();
The idea is to send the username and salted hashed password to the database and see if they match a record in there. If the user exists, then I pass the username to SethAuthCookie. My questions are:
Should the username be encrypted?
What happens if there are multiple servers and the user is surfing the website? I believe any one of the servers can serve content to the user, so how do they know if the user has been authenticated?
What's the preferred way of authenticating users in MVC without providers? Am I on the right track or should I be looking into something else?
Should the username be encrypted?
No.
What happens if there are multiple servers and the user is surfing the
website? I believe any one of the servers can serve content to the
user, so how do they know if the user has been authenticated?
At each request the server reads the authentication cookie that is sent by the client browser and which was generated by the FormsAuthentication.SetAuthCookie call, decrypts it and retrieves the username that is stored inside. Just make sure that you have set the same machine keys for all nodes of your server farm so that no matter which node emitted the authentication cookie, all other nodes can decrypt it.
What's the preferred way of authenticating users in MVC without
providers? Am I on the right track or should I be looking into
something else?
You are on the right track. You use the FormsAuthentication.SetAuthCookie method to emit the authentication cookie once you have verified that the password hash matches the one of the user in the database and in subsequent actions you could use the User.Identity.Name property to retrieve the currently authenticated user.
I would also recommend you checking out the following article which provides a good overview of how forms authentication works in ASP.NET.
I am putting a plan together for a series of sites that will share user account information among them. The idea is that once a user logs in using their OpenID, they can access any of the sites and it will know who they are.
What are the common patterns/best practices that i could employ to achieve this?
If all the sites share a common hostname in their URL then you can set an auth cookie (FormsAuthentication.SetAuthCookie) specifying the path of the cookie to be "/" so that all sites can see the user is logged in.
If the sites are not sharing a common host name, I think the only way to get a truly "once signed in, signed in everywhere [within your ring of web sites]" would be for all authentication to happen at just one site (perhaps one dedicated to authenticating the user) and for the other sites to redirect the user to that site for authentication and then that site would redirect back. In essence, that auth site becomes an identity provider, and almost exactly fills the role of an OpenID Provider (in fact DotNetOpenAuth could be used here for this exact purpose). Since it sounds like your goal is to let the user log in with their OpenID, your OpenID Provider on that one auth site could itself use OpenID to authenticate the user. Your own pure-delegation OpenID Provider could be written such that it always responds immediately to checkid_immediate requests as long as the Realm in the auth request is one of your trusted ring of sites. Thus you could effect single-sign-on across all your sites.
Please consider the following Patterns & Practices on Web Service Security from Microsoft:
Brokered Authentication - http://msdn.microsoft.com/en-us/library/aa480560.aspx
The main topic is - Web Service Security
Scenarios, Patterns, and Implementation Guidance for Web Services Enhancements (WSE) 3.0
http://msdn.microsoft.com/en-us/library/aa480545.aspx
Ultimately theres lots of ways you could do it. I achieved a simple single sign on by building a url with a token from one website pointing to another domain. The encoded & encrypted token contained details to submit back to the previous domain. Upon receiving an incoming request on the second domain, an underlying web service checks that the incoming request's token is valid with the previous domain using a shared private secret, known to both domains.