I'm new at spring security. I want to have two different login forms for two different type of users. I have a package called /admin which is contained my main project for system users and /portal for other users./portal users will work on their tenant and won't know anything about /admin and vice versa.Each user group has its own database too.
In spring-security.xml I defined two authentication managers,but when I login from both login forms it goes to 'AuthenticatingManager' but as I mentioned in xml file, for /portal users it should goes to PortalAuthenticatingManager. what shall I do? or what did I miss?
<security:http use-expressions="true" pattern="/portal/**" authentication-manager-ref="portalAuthMgr" access-denied-page="/unauthorized.jsp">
<form-login login-page="/plLogin.jsp" default-target-url="/portal/portal" />
<security:intercept-url pattern="/plLogin.jsp" access="permitAll"/>
<security:intercept-url pattern="/portal/**" access="hasRole('ROLE_PORTAL')" />
</security:http>
<security:http authentication-manager-ref="adminAuthMgr" access-denied-page="/unauthorized.jsp">
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
<security:form-login login-page="/login.jsp" authentication-failure-handler-ref="authenticationFailureHandler"/>
</security:http>
<security:authentication-manager id="adminAuthMgr">
<security:authentication-provider ref="produxAuthenticationProvider"/>
</security:authentication-manager>
<security:authentication-manager alias="portalAuthMgr">
<security:authentication-provider ref="portalAuthenticationProvider"/>
</security:authentication-manager>
<beans:bean id="produxAuthenticationProvider" class="com.spring.AuthenticatingManager">
</beans:bean>
<beans:bean id="portalAuthenticationProvider" class="com.spring.PortalAuthenticatingManager">
</beans:bean>
Your "portal" login form needs to post to a URL beginning with /portal/**, otherwise the login request will be handled by the second filter chain. It should work if you use/portal/j_spring_security_check
Note that you can also use the login-processing-url attribute on form-login element to control which URL the filter responds to. Using different URLs for each would avoid the issue where one accidentally processes a request meant for the other.
Related
We have a web application, and we're want to use spring security to secure it in 2 different ways:
1) Users that are authenticate using login form and have access to certain services.
2) Other services that are secured using digest authentication (user + password are passed in the request's header) - used by other webapps so there's no login form.
Each of these works on it's own, but we weren't able to get them to work in the same web app.
When we try to run a webapp with both xmls we get the following error:
A universal match pattern ('/**') is defined before other patterns in the filter chain, causing them to be ignored. Please check the ordering in your <security:http> namespace or FilterChainProxy bean configuration
The security.xml for users:
<security:http use-expressions="true">
<security:intercept-url pattern="/user/login"
access="permitAll" />
...
<security:intercept-url pattern="/**"
access="isAuthenticated()" />
<security:form-login
authentication-success-handler-ref="userAuthenticationSuccessHandler" />
<security:logout logout-url="/user/logout"
logout-success-url="/demo/user/logoutSuccess" />
</security:http>
<bean id="bCryptPasswordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="authenticationProvider">
</security:authentication-provider>
</security:authentication-manager>
The rest-security.xml for web services:
<security:http create-session="stateless"
entry-point-ref="digestEntryPoint">
<security:intercept-url pattern="/provider/**"
access="ROLE_WEBAPP" />
<security:http-basic />
<security:custom-filter ref="digestFilter"
after="BASIC_AUTH_FILTER" />
</security:http>
<bean id="digestFilter"
class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
<property name="userDetailsService" ref="webappDetailsServiceImpl" />
<property name="authenticationEntryPoint" ref="digestEntryPoint" />
</bean>
<bean id="digestEntryPoint"
class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
<property name="realmName" value="Contacts Realm via Digest Authentication" />
<property name="key" value="acegi" />
</bean>
<security:authentication-manager>
<security:authentication-provider
ref="restAuthenticationProvider">
</security:authentication-provider>
</security:authentication-manager>
Does anyone has experiences with this kind of scenario?
I found the solution here: https://blog.codecentric.de/en/2012/07/spring-security-two-security-realms-in-one-application/
This post details exactly what I wanted to do.
The trick seems to be adding pattern="/provider/**" to the rest http element. So the correct rest-security configuration is:
<security:http create-session="stateless"
entry-point-ref="digestEntryPoint" pattern="/provider/**"
use-expressions="true">
<security:intercept-url pattern="/provider/**"
access="isAuthenticated()" />
<security:http-basic />
<security:custom-filter ref="digestFilter"
after="BASIC_AUTH_FILTER" />
</security:http>
This might not be quite what you're looking for, but I would consider breaking the two apis apart. One for humans and one for web services.
We have our human interface right off the root context:
http(s)://your.website.com/...
We then have our web service interface off of the api context:
http(s)://your.website.com/api/v1/...
This makes it easy to handle the two different types of security you're looking for with spring.
The error message
A universal match pattern is defined before other patterns in the filter chain, causing them to be ignored.
is very concise.
You should check the order of bean definition files of your contextConfigLocation context parameter in your web.xml.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>security.xml,rest-security.xml</param-value>
</context-param>
should reproduce the above error message.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>rest-security.xml,security.xml</param-value>
</context-param>
should solve the issue.
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.
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>
I have spring-security configured using basic and form based authentication as per auto-config='true'.
I would like the endpoints under /api/** to NOT use form based security. Other endpoints outside of /api/** should use form based login. I would like a 401 response sent to any call for these endpoints who did not provide credentials under /api/**.
UPDATE: Thanks to Luke Taylor's comment below I have come up with the following solution.
NOTE: This technique can only be applied as of spring-security 3.1.
First I single out /api/**. We never create a session though use one if available, this is handled by create-session="never" and the use of <session-management/>.
<http pattern="/api/**" create-session="never" use-expressions="true">
<http-basic />
<session-management />
<intercept-url pattern="/api/**" access="hasRole('API_ACCESS')"/>
</http>
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/" access="permitAll"/>
<intercept-url pattern="/**" access="isAuthenticated()"/>
</http>
With Spring Security 3.1, your best option is to split the restful and non-restful parts of your application into separate filter chains by using two separate <http> elements. The restful API chain can then be configured to be stateless and use basic authentication, while the default chain can use a normal form-login configuration.
You would then have something like:
<http pattern="/api/**" create-session="stateless">
<intercept-url pattern="/api/**" access="ROLE_API_USER" />
<http-basic />
</http>
<!-- No pattern attribute, so defaults to matching any request -->
<http>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login />
</http>
The chain definitions must be ordered from most specific pattern to most general, so the default chain comes last.
I am attempting to enable remember me functionality using spring security
<bean id="userService" class="mypath.service.UserDetailsServiceImpl" />
<security:http auto-config='true'>
<security:intercept-url pattern="/Login" filters="none" />
<security:form-login login-page='/Login' authentication-failure-url="/Login?login_error=1"/>
<security:remember-me data-source-ref="dataSource" />
</security:http>
However, I seem to have specify the userService somewhere in the remember-me element ? How do I do this.
The error I am getting on starting tomcat is
More than one UserDetailsService registered.
Please use a specific Id reference in <remember-me/> <openid-login/> or <x509 /> elements.
Ok it wasn't that hard, just in case anyway else finds the spring documentation rather challenging to navigate:
<security:remember-me data-source-ref="dataSource" user-service-ref="myUserService"/>