Spring OAuth2 token without ClientId and ClientSecret for External Clients - spring

We have OAuth token generation using Spring which accepts Username/Password/ClientId/Secret, which works perfect. For External Client we just need input as username and password and generate OAuth Token.
<security:http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<security:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<security:anonymous enabled="false" />
<security:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request parameters -->
<security:custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
Below is the new code that we need to add, but it is asking for username and password in browser.
<security:http pattern="/**external**/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<security:intercept-url pattern="/external/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<security:anonymous enabled="false" />
<security:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<security:custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
Please guide if we can generate OAuth without clientId and internally pass clientId to generate OAuth.

You can never generate an OAuth token without a clientId! Oauth2 has 3 ways of creating a token, Implicit, Code, and user/pass. The last should be avoided, since it means that the Oauth client will get access to the user's credentials, and OAuth was built to prevent exactly that. Implicit token are granted using only the user's credentials (typically involving only the browser). In Code-mode the OAuth client received a code (should not be in a browser), which is then exchanged to a Token. The code to Token exchange require that the Oauth client authenticates, using it's clientId and a secret, this is typically done using Basic Authentication.

I think what you need is Resource Owner Password grant type which is explained in https://www.rfc-editor.org/rfc/rfc6749#section-1.3.3
Resource Owner Password grant type should only be used with the trusted clients. So if the external client you are talking about is a trusted client (Like a native mobile app developed by the same company. ex. Facebook Mobile App), this can be used.
Flow is explained in https://www.rfc-editor.org/rfc/rfc6749#section-4.3.1
The most important aspect of Resource Owner grant type is client should not store user name and password.

Related

How to disable fallback to NTLM on Spring Security configured with Kerberos?

I have a Spring App configured with Kerberos and it's working fine for users joined to the AD domain. There are other users who access to the app outside the domain, so Kerberos will not work and they should be prompted for user and password (html form).
If found that in some cases (depending on the browser) this procedure fails with a GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag).
It seems that the browser fails to use kerberos (that's ok because the user is not joined to the domain) and tries to send NTLM token to the App (SpnegoAuthenticationProcessingFilter:149 - Negotiate Header was invalid: Negotiate TlRMTVNTUAABAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==) which is not recognized as a Kerberos valid token so it fails with the GSSException.
There are lot of references to this issue in Internet (here, here, and here) and most of them suggest to fix the kerberos issue, but in my case this is not a kerberos issue because there are users that are not joined to the domain.
So, is there any way to force the kerberos fallback to the html form instead of sending the NTLM token ?
This is my configuration block on the spring-security.xml
<http entry-point-ref="spnegoEntryPoint" use-expressions="true">
<intercept-url pattern="/logout" access="permitAll"/>
<intercept-url pattern="/login" access="permitAll"/>
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<form-login login-page="/login"/>
<custom-filter ref="spnegoAuthenticationProcessingFilter" before="BASIC_AUTH_FILTER" />
<csrf disabled="true"/>
</http>

Spring Security - Access Token without client_secret in parameters

I have a spring security oauth2 based application, configured with a JDBC Client Store. As per the OAuth2 specs, client secret must only be used when client-server connections are trustworthy, and certainly not from a web application - where the client secret could be extracted from.
So the question is - how do we configure to let the /oauth/token requests with a grant type as "password" produce an access token, without the client_secret key in the POST parameters?
This is my authorization server configuration. Pretty basic I would say.
<sec:http pattern="/token" create-session="stateless" use-expressions="true" authentication-manager-ref="authenticationManager">
<sec:headers>
<sec:frame-options policy="DENY" />
<sec:hsts />
</sec:headers>
<sec:csrf disabled="true" />
<sec:anonymous enabled="false" />
<sec:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<sec:custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
<sec:access-denied-handler ref="oauthAccessDeniedHandler" />
</sec:http>
According to RFC6749, the OAuth2 Specs, a password grant type must have the client secret passed in either as a request body parameter or as a BASE64 encoded string. The password grant type is not suited for applications that has lesser security or high risk of secrets being exposed to the outer world.
For applications which has a user-agent (web browsers), Implicit Grant Type is the best sought out method.
Refer the OAuth2 Specs here

Is it possible to use HTTPS only for login in Spring security?

My requirement is to secure only the login page to protect user credentials. After successful login, the user can access to the restricted pages but in http mode.
It is a requirement because of SSL overload. Users need to access to protected pages which contains a lot of data.
I would like to know whether it is possible to do although it isn't as secure as maintain https context.
This is my config:
<security:http auto-config="true">
<security:intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="https"/>
<security:intercept-url pattern="/welcome*" access="ROLE_USER, ROLE_ADMIN" />
<security:form-login login-page="/login" authentication-failure-handler-ref="customAuthenticationFailureHandler" default-target-url="/welcome" />
<security:access-denied-handler ref="openIdAuthFailureHandler"/>
</security:http>
If I try to set /login as https, everything is in https mode. How can I manage to do that?
Edit:
As s.kwiotek suggested I added requires-channel="http" to the other url patterns:
<security:http auto-config="true">
<security:intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="https"/>
<security:intercept-url pattern="/welcome*" access="ROLE_USER, ROLE_ADMIN" requires-channel="http"/>
<security:intercept-url pattern="/user/*" access="ROLE_USER, ROLE_ADMIN" requires-channel="http" />
<security:intercept-url pattern="/rest/*" access="ROLE_USER, ROLE_ADMIN" requires-channel="http" />
<security:intercept-url pattern="/admin/*" access="ROLE_ADMIN" requires-channel="http" />
<security:session-management session-fixation-protection="none"/>
<security:port-mappings>
<security:port-mapping http="8080" https="8443"/>
</security:port-mappings>
<security:form-login login-page="/login" authentication-failure-handler-ref="customAuthenticationFailureHandler" always-use-default-target="true" default-target-url="/user/home" />
<security:logout logout-success-url="/" />
<security:access-denied-handler ref="openIdAuthFailureHandler"/>
</security:http>
I added the session-fixation-protection="none" because If I only include requires-channel="http" it doesn't go further from the login. I try to log in but I come back to the login.
If I add the session-fixation-protection it goes to the user's home but at the second login attempt. When you access to /myapp/login two jsessionid are created:
JSESSIONID=5B37413F33DF0AA45F31D711754C3704; path=/myapp; domain=localhost
JSESSIONID=658F9F8669AF6B296A77D448C1A64B71; path=/myapp/; domain=localhost; HttpOnly
Then I try to log in and I come back to the log in but the url is different:
https://myapp/login;jsessionid=C1EC352C42D6AC379DB1B65A9295E8A1
When the jsessionid is in the URL, I try to log in and I'm successfully redirected to the users'home (/user/home). If I remove the session-fixation-protection, the jessesionid is in the URL but I'm not successfully redirected to the user's home.
I don't know who creates the two first jsessionid and how to explain this behaviour. The only thing I want to do is to secure the login by ssl and then access by http.
(This should have been a comment. But my account is limited in reputation.)
You may want to reconsider allowing access to the restricted pages in http mode.
According to http://www.troyhunt.com/2011/11/owasp-top-10-for-net-developers-part-9.html,
Many people think of TLS as purely a means of encrypting sensitive user data in transit. For example, you’ll often see login forms posting credentials over HTTPS then sending the authenticated user back to HTTP for the remainder of their session. The thinking is that once the password has been successfully protected, TLS no longer has a role to play. The example above shows that entire authenticated sessions need to be protected, not just the credentials in transit. This is a lesson taught by Firesheep last year and is arguably the catalyst for Facebook implementing the option of using TLS across authenticated sessions.
Try for Example:
<security:intercept-url pattern="/**" access="ROLE_USER" requires-channel="http"/>

Support SAML SSO and normal login

I have an application which is accessed by two types of users, internal and external.
I need to authenticate external users using SAML.
I need to authenticate internal users with the normal form-based login. My application need to support both types of users. I use spring security frame work.
Is it possible to support both types of users? if so can you suggest the approach at high level? Thanks.
You can easily enable support for both form and SAML authentication with configuration similar to this:
<http entry-point-ref="authenticationEntryPoint" authentication-manager-ref="authenticationManager">
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
<form-login login-page="/login" />
<custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
<custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
</http>
Make sure that your AuthenticationManager contains the samlAuthenticationProvider. And of course include other configuration parts from the Spring SAML sample application.
You can then create your custom login page which presents user with username+password fields for form-based authentication and a link/picture (or multiple of them) which initialize authentication with the IDP (by redirecting user to scheme://host:port/saml/login?idp=selectedIdpEntityId).
Your users then decide which one to use - depending on whether they's internal or external.
The part of Spring SAML documentation touching on this subject is in chapter Spring Security integration.

AngularJS and Spring Security. How to handle AngularJS Urls with Spring Security

Let me explain my problem.
I have implemented a site in AngularJS that is accessed like this:
http://localhost:8080/example/resources/#/
Here we can call different pages, for example a Login page:
http://localhost:8080/example/resources/#/login
admin page:
http://localhost:8080/example/resources/#/admin
user page:
http://localhost:8080/example/resources/#/user
Now, I have implemented spring security in the example in order to catch every call and check if it has ROLE_USER privileges. So far so good, I have done it like this configuration in Spring security context file:
<security:http create-session="stateless" entry-point-ref="restAuthenticationEntryPoint"
authentication-manager-ref="authenticationManager">
<security:custom-filter ref="customRestFilter" position="BASIC_AUTH_FILTER" />
<security:intercept-url pattern="/**" access="ROLE_USER" />
</security:http>
This configuration checks for every url called, if the user has the proper ROLES, and it works fine, throws 401 Unauthorized page.
The problem I`m having is that when I put the login page to be accessed by everybody I'll do it this way:
<security:http create-session="stateless" entry-point-ref="restAuthenticationEntryPoint"
authentication-manager-ref="authenticationManager">
<security:custom-filter ref="customRestFilter" position="BASIC_AUTH_FILTER" />
<security:intercept-url pattern="/login**" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/**" access="ROLE_USER" />
</security:http>
But I dont know why spring security is not catching this URL. Maybe Angular manages the URL differently.
Finally i have tried deleting the <security:intercept-url pattern="/**" access="ROLE_USER" /> and giving /login** access to ROLE_USER only, but this page was not found. Does anybody know what could be happening here?
Thanks in advance!!!
I wrote a little sample application that illustrates how to integrate AngularJS with Spring Security by exposing the session id as an HTTP header (x-auth-token). The sample also provides some (simple) authorization (returning the roles from the server) so that the client AngularJS application can react to that. This is of course primarily for user-experience (UX) purposes. Always make sure your REST endpoints have property security.
My blog post on this is here.

Resources