Does anyone know in Spring a way to implement a user-service or authentication provider that will accept any user when logging in?
This is further to my previous question: spring-ws get username & password
I have a basic security setup in my spring-ws project:
<security:http auto-config="true">
<security:intercept-url pattern="/**" access="ROLE_USER" />
<security:intercept-url pattern="/*.wsdl" access="ROLE_USER" />
<security:http-basic/>
</security:http>
<security:authentication-manager erase-credentials="false">
<security:authentication-provider user-service-ref="userService">
<security:user-service>
<security:user name="me" password="mypass"
authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
I don't want to specify users in the user-service, I want a user with any details to have access, I simply want to make sure the user gives a username and password and to ensure that I can access this from the SecurityContextHolder.
Is it necessary to implement my own user-service or authentication-provider to do this and if so can anyone point in the direction of an example or provide me with one?
Thanks!
You need to provide your own AuthenticationProvider i.e. an implementation of the org.springframework.security.authentication.AuthenticationProvider interface.
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="myProvider" />
</security:authentication-manager>
<bean id="myProvider" class="MyProvider"/>
MyProvider can then either delegate to a custom UserDetailsService to set the authorieties (the roles) or set a ROLE_USER directly.
if you change
<security:http auto-config="true">
to
<security:http auto-config="true" use-expressions="true">
you can then set your intercepts from
<security:intercept-url pattern="/**" access="ROLE_USER" />
<security:intercept-url pattern="/*.wsdl" access="ROLE_USER" />
to
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:intercept-url pattern="/*.wsdl" access="isAuthenticated()" />
that will allow any authenticated user access to those url patterns.
You need to do the following:
Configure your intercept URL to provide access to any role names. You can do this by doing the following:
<security:http auto-config="true">
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_REMEMBERED" />
<security:intercept-url pattern="/*.wsdl" access="IS_AUTHENTICATED_REMEMBERED" />
<security:http-basic/>
</security:http>
Create your own user service which grants at least one authority to the user for any username and password combination.
Configure spring security to use the service you created.
<bean id="userService" class="com.ek.UserService" />
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userService" />
</authentication-manager>
I hope this gives you the idea on what you need to do. Else, we can work on creating a sample code for you.
Related
I created a spring mvc application with spring security. I tried to set authentication for all url with spring security.
Springsecurity.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-page="/login"
default-target-url="/welcome"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/login?logout" />
<!-- enable csrf protection -->
<csrf />
</http>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService" >
<password-encoder hash="bcrypt" />
</authentication-provider>
</authentication-manager>
When I giving intercept-url to /** the page doesnot loading. It makes a timeout.
But when giving intercept-url to /admin it works perfectly. Why this happens?
Your intercept pattern for all request is OK, but you need to include an exception for your login page, try adding
<http security="none" pattern="/login"/>
UPDATE with respect to the comment
The approach above completely switches off Spring security for the given URL. As you're using CSFR, it means that spring security filter should attend to this URL as well, but not for the sake of the authentication, rather for the sake of including the unpredictable token that can secure from session fixation attacks. In any case, here's a way to process the URL with spring security, without prompting for authentication. Instead of using the above, use the following
<intercept-url pattern="/login" access="isAnonymous()"/>
inside the
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/login" access="isAnonymous()"/>
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
...
I am currently exploring the possibility of having two separate log in page for different users.
I am now able to to set most urls according to the two pages. However, i am now having a configuration issue for the entry-point-ref and CONCURRENT_SESSION_FILTER.
As for this security version, ( LoginUrlAuthenticationEntryPoint.class - loginFormUrl ConcurrentSessionFilter.class - expiredUrl ) the setter method for the property are deprecated, left with the constructor injection that is set in the xml.
So I am thinking of two ways to solve this problem:
1. Override or Inject the two classes and change the url base on condition ?
2. Write a seperate http tag that reads in the specific url pattern and apply the configurations accordingly.
Thanks in advance. The working code is below:
<security:global-method-security pre-post-annotations="enabled" />
<security:http auto-config="false" use-expressions="true" entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:intercept-url pattern="/*" requires-channel="any"/>
<security:intercept-url pattern="/**/*.json*" requires-channel="any"/>
<security:intercept-url pattern="/**/dashboard/**" requires-channel="https"/>
<security:intercept-url pattern="/**/rest/**" requires-channel="https"/>
<security:intercept-url pattern="/**/cart/**" requires-channel="https"/>
<security:intercept-url pattern="/**/customer/**" requires-channel="any"/>
<security:intercept-url pattern="/**/api/**" requires-channel="any"/>
<security:intercept-url pattern="/api/**" access="permitAll"/>
<security:intercept-url pattern="/dashboard/signin" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/dashboard/signup" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/rest/signin" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/rest/signup" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/denied" access="permitAll"/>
<security:access-denied-handler error-page="/denied"/>
<security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<security:custom-filter before="FORM_LOGIN_FILTER" ref="customDeveloperPasswordAutenticationFilter"/>
<security:custom-filter after="FORM_LOGIN_FILTER" ref="customUsernamePasswordAuthenticationFilter"/>
<security:logout logout-url="/j_spring_security_logout" success-handler-ref="customLogoutSuccessHandler"/>
</security:http>
The code i'm trying to achieve is:
<security:global-method-security pre-post-annotations="enabled" />
<security:http auto-config="false" use-expressions="true" entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:intercept-url pattern="/*" requires-channel="any"/>
<security:intercept-url pattern="/**/*.json*" requires-channel="any"/>
<security:intercept-url pattern="/**/dashboard/**" requires-channel="https"/>
<security:intercept-url pattern="/**/cart/**" requires-channel="https"/>
<security:intercept-url pattern="/**/customer/**" requires-channel="any"/>
<security:intercept-url pattern="/**/api/**" requires-channel="any"/>
<security:intercept-url pattern="/api/**" access="permitAll"/>
<security:intercept-url pattern="/dashboard/signin" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/dashboard/signup" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/denied" access="permitAll"/>
<security:access-denied-handler error-page="/denied"/>
<security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<security:custom-filter position="FORM_LOGIN_FILTER" ref="customUsernamePasswordAuthenticationFilter"/>
<security:logout logout-url="/j_spring_security_logout_user" success-handler-ref="customLogoutSuccessHandlerUser"/>
</security:http>
<security:http auto-config="false" use-expressions="true" entry-point-ref="restUrlAuthenticationEntryPoint">
<security:intercept-url pattern="/**/rest/**" requires-channel="https"/>
<security:intercept-url pattern="/rest/signin" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/rest/signup" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/denied" access="permitAll"/>
<security:access-denied-handler error-page="/denied"/>
<security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="restConcurrencyFilter" />
<security:custom-filter position="FORM_LOGIN_FILTER" ref="customDeveloperPasswordAutenticationFilter"/>
<security:logout logout-url="/j_spring_security_logout_developer" success-handler-ref="customLogoutSuccessHandlerDeveloper"/>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="customUserDetailsService">
<security:password-encoder ref="customPasswordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<bean id='customUserDetailsService' class='sg.oddlefnb.common.security.CustomUserDetailServiceImpl'>
<!-- use to DAO to switch for different condition -->
<property name='userDao' ref='userDao' />
<property name='developerDao' ref='developerDao' />
</bean>
However, this could not run.. Any advice?
You should not try to do it that way, it is not the spring security way. Maybe you could succeed (even if I doubt you can ...) but it will be hard to write and to maintain.
You can have multiple <http> blocs in a single config, but it is when you want to apply different filter chains to different URL blocs.
You may have different login pages (and also different authentication methods : login page, basic authentication, ldap, custom ...). But the spring way is to separate authentication and access control. So when a user is authenticated, his authentication is stored in session and will be used for all following requests (until end of session). In your example if someone asks for a user page before authentication, if will be redirected to user login page, authenticated as a user and he will get its page. But if he asks for a developper page on next request, spring security will find a valid authentication in session a permitAll as access rule and will allow the page ... which I assume is not what you want !
The spring security way to do what you want is to use roles. The simple way is to have one single page, and store the roles in a database (or in a in-memory store for developpement and tests). You the use the roles in the access rules. You will find many examples for that in Spring Security Reference Manual.
Edit per OP comment :
It is rather uncommon to assign roles depending on used login page, but it can be done. You simply need to define two different AuthenticationManager beans, and explicitely assign them to the two different <http> blocs where you declare your login pages. In one you explicitely affect a ROLE_USER granted authority, and in the other a ROLE_DEVELOPPER one. You may do it by hand by subclassing a ProviderManager and using same AuthenticationProviderS in both, or you can use plain ProviderManager and customize the UserDetailsService beans of the AuthenticationProviderS. If you showed your current <authentication-manager> bloc, I could easily propose a full solution.
Once you have different roles, it is easy to put all access control in one single <http> bloc, with all the <security:intercept-url .../> inside it.
I am using Spring security within my web application, and I am utilising the 2 standard authorisation levels 'ROLE_USER', and 'ROLE_ADMIN'. Is there any possibility that I can add another level?
Simply add them to your intercept-url tag. For example I have the following configuration:
<security:http auto-config="false" use-expressions="true" access-denied-page="/denied.do"
entry-point-ref="authenticationEntryPoint">
<security:intercept-url pattern="/index.do" access="hasAnyRole('PROGRAM_VIEW', 'PROGRAM_ADMIN')"/>
<security:intercept-url pattern="/**" access="hasAnyRole('PROGRAM_VIEW', 'PROGRAM_ADMIN)"/>
<security:custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER"/>
<security:logout invalidate-session="true" logout-success-url="/" logout-url="/logout.do"/>
</security:http>
My additional roles are PROGRAM_VIEW and PROGRAM_ADMIN (I'm not using ROLE_ADMIN and ROLE_USER).
These additional roles are coming from database.
I have this spring security configuration:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/home.jsp" access="permitAll" />
<intercept-url pattern="/loginFailed" access="permitAll" />
<intercept-url pattern="/logOut" access="permitAll" />
<intercept-url pattern="/*" access="isAuthenticated()" />
<form-login login-page="/home.jsp" default-target-url="/index"
authentication-failure-url="/loginFailed" />
<logout logout-success-url="/logOut"/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="N_a" password="12" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
If I type url, that need access="isAuthenticated() I redirect to home.jsp.
I want to see 403 error.
How to change it ?
You are using a form-based login and as such, when not authenticated, you will be prompted with the login-page. This is what you have configured and this is how, by default, Spring Security works.
If you want to override this you need to explicitly configure an AuthenticationEntryPoint to be precise the Http403ForbiddenEntryPoint. This basically always gives a 403 if someone isn't authenticated or doesn't have access. This disables the ability to be prompted with a login-form to give a user the change to login after all.
<beans:bean id="entryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
<http auto-config="true" use-expressions="true" entry-point-ref="entryPoint">
<!-- Your other elements here -->
</http>
use access-denied-handler tag in http tag.
http://www.mkyong.com/spring-security/customize-http-403-access-denied-page-in-spring-security/
or use access-denied-page property.
<http auto-config="true" access-denied-page="/403"></http>
I have a simple authentication provider that I'm trying to use with Spring Security.
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>
<security:authentication-manager>
<security:authentication-provider
ref="ipAddressAuthenticationProvider" />
</security:authentication-manager>
Currently, with the above configuration, the user is redirected to a logon page when the first visit. I do not want this redirect. I'm trying to hit this authentication provider on every page visit. Any way to make this work without writing additional custom code?
I'm guessing I need to cleanly get rid of form filter and basic filter somehow.
Result
I got it working with the config below. I had to extend AbstractPreAuthenticatedProcessingFilter and simply return ""; for both of its abstract methods.
<security:http use-expressions="true" entry-point-ref="http403ForbiddenEntryPoint">
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter" />
</security:http>
<bean id="preAuthFilter" class="com.hercules.ratinggame.business.security.IpAddressPreAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<bean id="http403ForbiddenEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="ipAddressAuthenticationProvider" />
</security:authentication-manager>
Currently you use auto-config="true" which means you get few filters configured iunder the hood, including <form-login> element with UsernamePasswordAuthenticationFilter filter.
Also, to hit this authentication provider on every page visit you'll need a filter which can obtain data from request (IP address as far as I can see). The filter will probably be RequestHeaderAuthenticationFilter or more likely your own AbstractPreAuthenticatedProcessingFilter implementation which will have access to your autentication-manager.
To sum up, configuration will look like:
<security:http use-expressions="true">
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:logout /> <!-- optional -->
<security:custom-filter position="PRE_AUTH_FILTER"
ref="ipFromRequestPreAuthenticationFilter" />
</security:http>
<!-- this will probably extend AbstractPreAuthenticatedProcessingFilter -->
<bean id="ipFromRequestPreAuthenticationFilter"
class="com.example.IpFromRequestPreAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="ipAddressAuthenticationProvider" />
</security:authentication-manager>