I downloaded the Azure AD with spring boot from https://github.com/microsoft/azure-spring-boot. Its all nice and works well as long as I run theazure-active-directory-spring-boot-sample using
mvn spring-boot:run
as shown in the README file.
I am trying just a basic real-life scenario where the angular/react app is running separately on a separate port using npm. The moment I separated them out the main Filter AADAuthenticationFilter is only invoked once on the first request where it does token verification and never again for subsequent requests.
I went around and configured an nginx proxy so that the domains of these two are now same
localhost:9999 and I redirect based on the next path like web for the npm and app for the Spring boot. This enabled the cookies to be available at every request.
This helps because what I learned is that Spring uses cookies to maintain a session. But ideally, the AAD filter should revalidate the token every request.
But if I add a property of azure.activedirectory.session-stateless=true to my application.properties, as mentioned in the filter's code to make it stateless and validate on every request. It expects roles as a different attribute in AD instead of it being a group of the user.
I also don't understand get the behaviour, when the js files are embedded within the spring app and run all this works perfectly fine and the filter is invoked at every request. But when I separate them out it just doesn't work.
Any help or pointers would be appreciated.
I realize that a lot more info may be required for someone to debug the above problem. But I was just able to solve this - at least found the problem that was causing it. Like I mentioned earlier the problem started when I separated the client and spring APIs. And since the client was not able to send back the cookies set by server, due to change in domains I had to put a proxy server.
What I found out later was that every GET request was always invoking the AAD filter. Even multiple requests. But other requests like POST, PUT were failing. I tried disabling the csrf config in spring WebSecurityConfig.java -->> http.csrf().disable();
This solved my problem and now I receive a request and all works as expected. Now I am trying to figure out how not to disable csrf completely.
Thanks
Related
I want to put SCDF's dashboard behind zuul (or just assume any proxy, really), but when I do that, Spring Cloud Data Flow will redirect to what it thinks it's actual host is.
Example:
Zuul is http://zuul/. It's configured to route any /dashboard requests to http://scdf/host
In a browser, I go to http://zuul/dashboard.
As soon as the request routes through zuul, and then hits SCDF, SCDF will redirect to http://scdfhost/dashboard, which won't work in a locked down environment. (scdfhost will not be visible through the outside)
I've looked for any properties that would work here, but I can't figure it out.
Anyone tried this? Or tips?
Thanks for your question! The issue is the redirect 302 from http://localhost:9393/dashboard to the absolute URI of the dashboard (http://localhost:9393/dashboard/index.html). If you are running Spring Cloud Data Flow Server behind a proxy server, such as Zuul, you will have to specify the property
server.use-forward-headers and set it to true. That way Spring Boot is aware of the HTTP forward headers from the proxy. See also the Spring Boot reference guide ("Running Behind a Front-end Proxy Server").
You can find a basic example at:
https://github.com/spring-cloud/spring-cloud-dataflow-samples/tree/master/dataflow-zuul
In order to clarify the reference documentation, I have created a follow-up issue:
https://github.com/spring-cloud/spring-cloud-dataflow/issues/2929
In my application, user management is done through Keycloak. While testing my application end-to-end through Cypress, I came across an issue. When I sign up a user, it gives the following error:
We're sorry. An error has occurred, please login again through your application.
Cypress is adding something to a generated URL after I click the submit button, which is causing this issue. The same scenario tested through Protractor ran fine. I have noticed Cypress is appending session_code to the request URL. While doing manual testing, I don't get session_code.
Below is the URL generated through Cypress:
.../login-actions/registration?session_code=LsZbmsVVLwEH9s-xwFJ2JdDtaCu1_xzqAGOQCpjxGJI&execution=06fac3bb-fb19-474b-8659-2572586ae371&client_id=web_app&tab_id=PSlmfgdv0ls
Where as a manually generated URL is like following:
.../login-actions/registration?client_id=web_app&tab_id=PSlmfgdv0ls
My application backend is Spring Boot and the front-end is in React and Next.js.
It would be really helpful if anyone could guide us through this issue. Please let me know if you need more information about our application.
The Keycloak Authenticator documentation explains that the authenticate method checks the current HTTP request to determine if authentication requirements have been satisfied, and, if not, a challenge response is sent back. If the challenge response itself is authentication, then you'll see a URL with the session_code parameter.
It goes on to say that session_code, in the first URL example, pertains to the code generated from AuthenticationFlowContext.generateAccessCode(), which further explains:
String generateAccessCode()
Generates access code and updates clientsession timestamp. Access codes must be included in form action callbacks as a query parameter.
However, the "manually" generated URL, that does not include the session_code parameter, seems to indicate that the initial registration of the client has been successful and a client configuration endpoint is being used to make a GET request - a client read request - and all is well. Everything works fine.
Therefore, it seems that Cypress is being sent a challenge response (and potentially exposing a security flaw in your application). Possible reasons for this might be further explained within Cypress's documentation on Web Security.
Common Workarounds might provide you with a remedy, or, if all else fails, you might try Disabling Web Security for testing purposes as well.
We have an application which is using spring-security-oauth2:1.0. I was trying to change it to a newer version, spring-security-oauth2:2.0.7.RELEASE. If I don't specify the scope or If I specify I single scope, the application works fine. I have a problem while requesting multiple scopes like read,write, which used to work in previous version.
The client I am requesting has all read,write and trust permissions.
When I was using spring-security-oauth2:1.0, to get a token I used to do a get call like
http://localhost:8080/oauth/token?grant_type=password&client_id=ws&client_secret=secret&scope=read,write&username=user#abc.com&password=temp123
If you see the scope parameter scope=read,write, by requesting this way I used to get a token with scope read and write.
If I try to do the same thing with Oauth2 version 2.0.7.RELEASE(with a POST request though), I get Invalid Scope exception because the tokenRequestis taking read,write as a single scope. The client I am requesting has read,write and trust permissions but read,write is not one of them.
If I try it with scope=write or scope=read, It works fine because read or write are part of the client's scope.
If I want to request for multiple scopes in OAuth2 2.0.7.RELEASE, how do I do that?
I found the correct way to do this. Instead of a comma separated scopes, you have to use + to separate scopes.
Ex: read+write , write+trust
So the following POST request worked fine.
http://localhost:8080/oauth/token?grant_type=password&client_id=ws&client_secret=secret&scope=read+write&username=user#abc.com&password=temp123
I hope it will help others :)
i am currently working on a project involving spring security (for OAuth2).
We are using the authorization_code flow.
However when the client hits the AuthorizationEndpoint (/oauth/authorize)
we get an "InsufficientAuthenticationException".
This may be due to an external system which is also involved in this flow which performs a redirect for the client, sending him to the /oauth/authorize endpoint.
From what I understand by looking through the debug logfile and from reading the source code, the principal is null which is used in the AuthorizationEndpoint.authorize method (specifically line 138, we are using spring-security-oauth2-2.0.7.RELEASE).
I understand what spring's problem is at this point (it does not "know" the user who is already authenticated with the system) but I do not understand which information specifically spring uses to identify the user (I guess this would be my central question)
I tried performing a GET against /oauth/authorize with the correct parameters and sending with the request the authorization header containing the bearer access token but spring always throws the InsufficientAuthenticationException. I'm hoping somebody can help me with this.
Best regards
p.s.
I am going to answer my own question here for the sake of documentation.
TJ basically pointed me in the right direction.
In my case, the InsufficientAuthenticationException stems from a slightly wrong setup of the whole stack. For delivering the content to users an apache is used which also serves as a reverse proxy, truncating the root context of the application deployed on the tomcat behind it.
The answer which finally solved my problem can be found here.
The problem actually was, that the session cookie contained an invalid path (the path attribute still contained the rootcontext, because tomcat has not been made aware that the apache in front of it is truncating the rootcontext to just "/".) So setting the path on tomcat side via setSessionCookie="/" in tomcat's context.xml did the trick.
So, when a redirect hit spring's oauth/authorize endpoint it did so with a session cookie containing the wrong path. because of this, for spring the request seemed to originate from an unauthenticated source, thus leaving me scratching my head about the InsufficientAuthenticationException.
I'm hosting a REST web service in a Grails application, using Spring Security, i.e.:
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
def save = {
println "Save Ride REST WebMethod called"
}
I'm calling it from an Android app. (Calling the unsecured service works just fine.)
To call the service, I'm manually building up a request (HttpUriRequest) and executing it with an HttpClient.
I'm wondering what the best practices are, and how to implement them... Specifically, should I:
Perform a login once, to retrieve a JSESSION_ID, then add a header containing it into the HttpUriRequest for each subsequent request?
Or (not sure how I would even do this) include the login and password directly on each request, foregoing the cookie/server-side session
I think I can get option 1 working, but am not sure if Spring Security permits (2), if that's the way to go... Thanks!
--also, there isn't any library I'm missing that would do all this for me is there? :)
Spring security does support both basic authentication and form based authentication (embedding the username/password in the URL).
A REST service is generally authenticated on each and every request, not normally by a session. The default spring security authentication (assuming you're on 3.x) should look for basic authentication parameters or form parameters (j_username and j_password) (in the form http://you.com/rest_service?j_username=xyz&j_password=abc).
Manually tacking the j_username/j_password onto the URL, adding them as post parameters (I believe), or setting the basic authentication username/password should all work to authenticate a REST service against the default Spring Security interceptors, right out of the box.
I will admit that I haven't tried this on REST services, though I do clearly recall reading exactly this in the docs as I did the same for basic page logins on spring security recently. Disclaimer over.
I think you can use a login-once-and-get-a-token method that's similar to how oauth works.
sending username and password across the network outside of secured channel(https/ssl) is a terrible idea. anyone on the network can sniff your request package and see the clear text password.
on the other hand, if you use a token method, since the token string is randomly generated, even the token is compromised, the worst case is someone can use the token accessing your REST API.
another solution is going through ssl tunnel(HTTPS). i have actually done a comparison and result shows: 80 requests/min(https) vs 300 requests/min(http)