i am currently building a security solution in spring cloud microservices.
when combining springs OAuth2 and Zuul implementation, it is quite easy to build an authenticationprocess like:
user calls the ui, which knows initially: user is not authenticated
redirect to auth server to ask the user for his login creds
redirects him back to the ui, providing a code or token.
I would prefer a flow with password authentication flow, in a way where the auth server is behind zuul
For example:
1.2.3.4:8080 is Zuul (with a UI with angularJS), domain "example.com"
1.2.3.5:9000 is the Auth Server
I could configure the zuul in a way, to access 1.2.3.5:9000 directly, passing form fields AND basic authentication to pass the client id.
since the auth server registers itself to eureka, I could also use "example.com/auth_server", which is the same, but managed through zuul. Alternatively I could also configure it manually....nevertheless:
Password authentication does not work, since Zuul is removing the basic authentication header from call....
at this point, I see I am doing something wrong...because the edge serve COULD have it's own security solution and tunneling the basic authentication to auth may be not the best way....but
HOW can I manage password authentication with ouath2 through zuul?
Please Help :)
By default "Cookie", "Set-Cookie", "Authorization" are marked as sensitive headers on a route and are not forwarded. Setting zuul.routes.myroute.sensitiveHeaders='' should allow you to pass those headers through, though I'm not sure it's the best idea.
The problem was a late working session in the evening :)
The component making the request didn't send the authorization since some updates which led to no headers ever reached the edge server.
Obviously, everything works as intended if basic or bearer authorization headers are passed over
Related
I have a front end (angular) with login form, a back-end for that angular application as my OAuth client (spring dependency) then I have a third application that is the Authorization server and finally the forth is the ressources server.
So I want to know is there is any way to jump the redirect to /login from the authorization server?
I want to login the user with angular login page, then make a get with my OAuth client (spring) for the authorization code flow and then, since i'm not authenticated, instead of getting redirect, I want to get an error "401" and then send a post request with my OAuth client (spring) to the auth server again to login the user that have sent the data previously in angular login page.
Essentially I just wanted to login to my auth server with a custom page that exists in the front end application and let the backend build specially for that front, take over the flow.
You want seamless integration between login form and the rest of your Angular app? Share your CSS between Angular (public) client and authorization-server embedded (private) one, don't implement login in public client.
You might need to better grasp OAuth2 concepts.
Login, logout and user-registration are authorization-server business. Leave it there. Reasons are related to security and just being future-proof: what if you want to plug additional clients to your system (mobile apps for instance)? Are you going to implement login, logout and user-registration again and again? What if you have to introduce multi-factor authentication at some point? Would you break all clients at once?
Your "backend" (Spring REST API secured with OAuth2) is a resource-server, not a client. Make sure it is configured as so: depends on spring-boot-starter-oauth2-resource-server (directly or transitively). This is where the HTTP status for missing (or invalid) authorization is handled. The way to do it depends on your resource-server being a servlet or reactive app. The libs in the repo linked just before do what you want by default (401 instead of 302).
In your case, client is Angular app. I hope you use an OAuth2 client lib such as angular-auth-oidc-client to handle:
authorization-code flow (redirects to authorization-server, back from authorization-server with authorization-code and tokens retrieval with this authorization-code)
refresh-token flow (automatic access-token refreshing just before it expires)
requests authorization (add Bearer Authorization header with access-token on configured routes)
What my Angular apps do for login is just redirect users to authorization-server "authorization" end-point and then just wait for a redirect back to "post-login URL" with an authorization-code. How this code was obtained is none of their business (can be a login form, a "remember-me" cookie, some biometry, etc.).
Also, I have to admit that I don't use Spring's authorization-server. I prefer mature / feature-full solutions like Keycloak, Auth0, Okta, etc. which come with much more already implemented: multi-factor authentication, integration with LDAP, identity federation for "social" providers (Google, Facebook, Github, etc.), administration UI, ...
As ch4mp said, it's best to leave all the authentication and authorization logic and pages to the Spring Authorization Server, it's pretty easy to customize and configure all the user accessible pages (login, authorize, etc...) with Thymeleaf, you only have to bring in your CSS to unify the design.
There was a great demo in last year's Spring One which seems like something you'd like to achieve, you can find the code in this repo.
They used Spring Cloud Gateway as a means to run the Angular SPA in the flights-web app, configuring it as the OAuth client. Following this path you can route all calls to your backend API through the gateway's WebClient.
I'm new to security and I'm trying to understand how to implement proper security without any overkill.
Below are my questions.
I don't want to allow 3rd party clients to use my API and hence I don't see any importance of OAuth 2.0. Hence I'm looking to use the sessions generated by keycloak (or Ory Kratos) in my Spring Boot Security. Any guidance on how to do that.
I have come across an application https://opstra.definedge.com/ which security is implemented using keycloak (can see the URL pattern). But in the requests, I can't see any JWT token in the chrome DevTools Network Tab while performing any network requests. I think they are implementing it the way I wanted. Any overview on how it is implemented.
I'm not architect at definedge, but I'm pretty sure they do not use Keycloak sessions in Opstra (they would have to run Opstra inside Keycloak servlet for that). It more looks like they use OAuth2 to authenticate users from a Java client and that this client has sessions of its own enabled (JSESSIONID cookie for opstra.definedge.com VS sso.definedge.com). It is quite possible that this java client uses access-tokens to authorize requests to resource-server(s), we just can't see it from the browser.
Restricting the clients allowed to consume your API has little to do with authorization method:
with basic authorization header, any client with login and password can access
with Bearer authorization header, any client with a valid token can access (which you already had anticipated)
even JSESSIONID cookie can be set for any origin (I believe), in which condition any request from the same browser would be authorized, whatever the web client.
Restricting your API clients is more about CORS configuration, which aims at just that: filtering which origins (host + port) can access which resource location (URL)
There is a notion of confidential client in Keycloak where the client must provide a password in addition to client-id to exchange authorization codes for access-tokens, but this does not apply to rich clients (clients running on devices you cannot trust): Angular, Vue, React, native mobile apps, etc. code can be reversed enginereed to read that password. But it is possible to configure a Java client of your own as "confidential" and as so, allow this client only to get access tokens to query resource-server (API).
OAuth2 comes with much more than just easing multi-client scenarios and JWTs with session-less java applications greatly ease horizontal scalability and fault tolerance. You should read this article for a refresher on
OAuth2 (and its value)
resource-server security configuration (with CORS)
I have a rest service which stores comments from the users in the database, my architecture is an angular fronted which connects to a load balancer server (zuul) which connects to an auth server to generate the jwt.
With the jwt the frontend generate the requests to the same zuul server with the jwt, this zuul server validate the jwt and if valid will connect to another backend service to store the comment.
The backend service where the comment is stored doesn't have any security validation all endpoints are accessible as the route of this microservices are not going to be exposed? Is there any risk on this?
As there is no jwt reaching the "comment backend service" how can I get the user that actually made the request? Should I implement some kind of filter in the zuul server to get the logged user from the jwt token and include the information in the request that is being sent to the "comment backend service"? If this is possible, any ideas on how to implement it?
Thanks
Regards
By default, Zuul considers the Authorization header as a sensitive header and it will not pass it downstream. So the first thing you need to do is to update Zuul configurations. Read the documentation here.
After that, in each of your downstream service, you need to add the capability to read the JWT token from the Authorization header and extract relevant information such as username, etc.
I am implementing REST services using springMVC. Now i have added basic authentication entry point in my spring security file. But i don`t know that, Once user authenticated by passing credentials in Authorization header does he need to pass those credentials for all subsequent requests?
for example,
I have two URLs:
1) localhost/apppName/login
// Here user passes credentials in Authorization header. So, user authenticated successfully.
2) localhost/appName/getUsers/1
//Here, client need to pass those credentials in Authorization header?
if it is needed, then why spring kept prinicpal object in the SecurityContextHoder after authentication done via BasicAuthenitcationEntryPoint?
Clients of this services can be any thing like Android, java, .Net
Any suggestions will be appreciated.
Pure REST is stateless, which means that no client context is being stored on the server between requests. That means you need to send the Authorization header for each request.
You don't need to hit the login URL when using Basic auth, that's the point.
However, you can use sessions in combination with Basic auth, and in that case you should pass session cookie between requests. It may have some performance advantage, but generally I would not recommend it.
In previous versions of ASP.NET you got authorization and authentication out of the box from the default template.
I have a Web API application and three or four well defined clients that will consume it and I need to secure it.
I read about OpenID and OAuth but they seem like an overkill for my problem.
What's the simplest way to achieve that?
These would be the 3 best solutions if you require security:
WEB API browser client: Implicit OAuth 2 flow
WEB API Application client: OAuth2 code flow
(With OpenId)
OR: Cookie Authentication with Cross-site request forgery protection. (Default template MVC 6 website template)
If your application is public, I would use at least one of these, otherwise it depends on how secure your data must be.
Well, it depends on your scenario. If you don't need authentication (because it's a server-to-server scenario), use a security token as described below. If you need authentication of the user, you may use Basic or Digest security combined with HTTPS.
In a security token scenario, the client simply has to add the token to the request headers and the server needs to validate the token. Make sure the requests transit as HTTPS to make sure the token is encrypted. Remember, this method is only valid if you know the applications that will access your API will be in a secure environment (another server, for example). Otherwise, I would go for another solution.