I am trying to get my spring + hibernate + spring-security and tiles2 - "HelloWorld" application to work, following this guide (its in german unfortunately).
My problem is that I get a "404" error message when logging into my application. Redirection to the login page works as intended, but I can't reach "http://localhost:8080/App/j_spring_security_check" when I hit the login button.
My web.xml looks this way:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/defs/applicationContext.xml
/WEB-INF/defs/applicationContext-security.xml
</param-value>
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
and applicationContext-security.xml file looks this way ...
<http use-expressions="true">
<intercept-url pattern="/index.html" access="permitAll" />
<intercept-url pattern="/timeout.html" access="permitAll" />
<intercept-url pattern="/redirect.html" access="permitAll" />
<intercept-url pattern="/media/**" access="permitAll" />
<intercept-url pattern="/includes/**" access="permitAll" />
<intercept-url pattern="/office/**" access="hasRole('ROLE_USER')" />
<intercept-url pattern="/office/admin/**" access="hasRole('ROLE_ADMIN')" />
<form-login login-page="/index.html"
authentication-failure-url="/index.html?login_error=1"
default-target-url='/office/kunden.html'
always-use-default-target='true'
/>
<logout logout-success-url="/index.html" />
<remember-me />
<session-management invalid-session-url="/index.html">
<concurrency-control max-sessions="2" error-if-maximum-exceeded="true" />
</session-management>
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="mysqldataSource"
authorities-by-username-query="select username, authority from benutzer where username = ?"
users-by-username-query="select username, password, enabled from benutzer where username = ?"/>
</authentication-provider>
</authentication-manager>
The database connection seems to be O.K.
I would be very glad if someone could give me a hint on that, because I already did a lot of googling, but didn't find a solution yet.
I use spring 3.1 and tomcat 7.0.23
I would check two things:
Request dispatch
Spring-security config
To check request dispatch just make sure that your application is accessible in the servlet container in the first place. Meaning, you have mentioned http://localhost:8080/App/j_spring_security_check. Is your application accessible under that URL? Does http://localhost:8080/App show proper content (HTTP 200)?
Also make sure that dispatcher servlet is configured properly. In tutorial you have provided, there is this section:
<!-- Spring Hauptteil -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
If you have not provided it in your web.xml, then your request might not even be dispatched properly before it ends up being examined via spring-security.
If this doesn't help you, try this.
Following documentation, the minimal configuration should be enough to check if your setup is correct. If you have followed tutorial, you might make some minor mistake (typeo, for instance) that will cause spring-security not to launch properly. Then it is easy to skip some error info in logger output.
I suggest you do the following.
Change your applicationContext-security.xml to support minimal configuration provided in documentation.
Launch the application and go to http://localhost:8080/App/j_spring_security_check
If you get proper response - try modifying config until you are done.
Point to learn
What DelegatingFilterProxy (defined in web.xml) really does is delegating request to some other filter managed by Spring's IoC. This filter is being defined in applicationContext-security via security namespace. If this won't work for some reason, the filter will not be initialized, and you may end up in seeing http 404 regardless the fact, that the rest of application starts properly.
Uffff, lots of text ;)
Your configuration looks ok. One thing that can case the 404 is if the default-target-url='/office/kunden.html' points to an controller or view that does not exist.
Check that the url /office/kunden.html works -- therefore deactivate the security stuff (just add <security:intercept-url pattern="/**" access="permitAll" />) and try it.
An other thing that may goes wrong, is that the tutorial is for spring 3.0 but not spring 3.0. I would not expect that this is the cause, but give it a try and downgrade.
For those people who face the same symptoms, but for a different situation, those who are behind a load balancer which does SSL offloading, the following answer might put you in the right direction. I had a similar problem and it turned out that the incoming request was handled correct, however as a response spring security sends a redirect to an absolute URL which is defined by the default-target-url attribute (starting with http instead of https)
<security:form-login login-page="/login.jsp" default-target-url="/index.jsp" authentication-failure-url="/login.jsp?error=true" />
Now the client browser tries to open the redirected location on http, fails on the loadbalancer (which only accepts https traffic) and reports a 404 NOT FOUND
We solved this problem by adding the following mod_header directive for all incoming requests on port 443 (https) in the load balancer:
RequestHeader set X-Forwarded-Proto "https"
The will add an extra header. If you run an application server like Jetty, it will recognize this header and translate the incoming request. (see http://www.gossamer-threads.com/lists/apache/users/407272)
Related
I am facing this problem...
I have the spring security filter
on my web.xml
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I am using spring security and I have this at my springSecurity-applicationContext.xml
<http
authentication-manager-ref="myAuthManager"
access-decision-manager-ref="accessDecisionManager"
entry-point-ref="authenticationEntryPoint"
create-session="ifRequired"
access-denied-page="/unauthorized">
<custom-filter ref="myPreAuthenticatedFilter" position="PRE_AUTH_FILTER"/>
<logout logout-success-url="/page/home"/>
<anonymous key="anonymous"/>
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/method/do" access="IS_AUTHENTICATED_ANONYMOUSLY()"/>
</http>
So, at myPreAuthenticationFilter I have a filter that extends of AbstractPreAuthenticatedProcessingFilter
I am trying to execute /method/do with a DELETE or a POST without success.
I am wondering what would be the best way to do it?
For some reason when I put a break point on myPreAuthenticationFilter at doFilter and make the request with DELETE nothing happens, only when I do the GET.
I want that endpoint to have no security.
I made this and worked
<http pattern="/method/do" security="none"/>
Not sure why this works and others dont or where I should look for.
Any idea?
The errors I get are Forbidden
If using spring-security 4 or above, csrf filter is enabled by default and it actually blocks any POST, PUT or DELETE requests which do not include de csrf token.
If you are not sending the csrf token in any of this kind of requests, you should make a test just disabling it configuring <csrf disabled="true"/> in your secured <http> section in your security xml, this way:
<http
authentication-manager-ref="myAuthManager"
access-decision-manager-ref="accessDecisionManager"
entry-point-ref="authenticationEntryPoint"
create-session="ifRequired"
access-denied-page="/unauthorized">
<custom-filter ref="myPreAuthenticatedFilter" position="PRE_AUTH_FILTER"/>
<logout logout-success-url="/page/home"/>
<anonymous key="anonymous"/>
<intercept-url pattern="/method/do" access="IS_AUTHENTICATED_ANONYMOUSLY()"/>
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<csrf disabled="true"/>
</http>
Edit
I have just realized that the order of the intercept-url should be just the opposite, starting from the most specific and ending with the most generic (I have already modified in the sample configuration I suggested)
In your case, it does not affect the behaviour given that both mappings have same access policy, but it should be this way.
We are using the web.xml version of session-timeout, and are stumped on having it redirect to either the login page, or the logout page forcing the user to re-authenticate.
Currently we have this defined in our web.xml
<session-config>
<session-timeout>30</session-timeout>
</session-config>
Which used in conjunction with our spring security core jars, works fine for invalidating the session after the timeout, but there is no redirecting of the screens, you can still browse through the application with no session.
How do we tell Spring to redirect at the end of that timeout?
URL mapping for intercepting the user
<security:http entry-point-ref="casProcessingFilterEntryPoint" pattern="/*">
<security:custom-filter ref="casProcessingFilter" after="CAS_FILTER"/>
<security:intercept-url pattern="/**" access="ROLE_USER"/>
<security:logout logout-url="/logout" logout-success-url="http://login..edu/logout" invalidate-session="true"/>
</security:http>
I noticed if i mention a pattern or enter a RequestMatcher reference to the HTTP container, the spring_security_login default page isn't generated. I would like to know why. Is it expected that in such scenarios (which drive to multiple http config elements) we need to provide our own login pages and authentication logic?
This is the config I am referring to.
<http pattern="/somearea/**" authentication-manager-ref="authMgr" use-expressions="true" auto-config="true" request-matcher="ant">
This is how my web.xml looks like, if that is of interest. Not very fancy. :-)
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Also, if i make my own login page which calls j_spring_security_check, the j_spring_security_check mapping isn't found as well. Please let me know if any more config info is needed.
The reason is that both http#pattern and http#request-matcher-ref both decide if the block is used. Since neither /spring_security_login or /j_spring_security_check match the provided pattern (/somearea/) the block will not be used.
To resolve this, you need to ensure your form-login#login-processing-url is configured to look at a request that matches your http#pattern. You will also need to specifying a login page and ensure you render the custom login page. For example, assuming you ensure the URL /login renders a login page the following configuration will work:
<http pattern="/somearea/**" authentication-manager-ref="authMgr" use-expressions="true" auto-config="true" request-matcher="ant">
<form-login login-processing-url="/somearea/login" loginPage="/login"/>
</http>
Alternatively, you could create a separate block that just performs the authentication:
<http pattern="/somearea/**" authentication-manager-ref="authMgr" use-expressions="true" auto-config="true" request-matcher="ant">
</http>
<http authentication-manager-ref="authMgr" use-expressions="true" auto-config="true" request-matcher="ant">
</http>
Keep in mind that each configuration is distinct and is only applicable when the pattern or request-matcher-ref matches.
I am using session management in spring security to limit number of concurrent users per username.
Although it perfectly works but after few minutes of using the application without logging out, it redirects to index page and does not allow the same user to log-in again. To log-in again I need to re-run the application.
<session-management invalid-session-url="/index">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>
<logout delete-cookies="JSESSIONID" />
After adding the following to web.xml also it runs into following error
web.xml
<listener>
<listener-
class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class>
</listener>
Error
SEVERE: Exception while loading the app : java.lang.IllegalStateException:
ContainerBase.addChild: start: org.apache.catalina.LifecycleException:
java.lang.IllegalArgumentException: java.lang.ClassNotFoundException:
org.springframework.security.ui.session.HttpSessionEventPublisher
You are using the wrong classname (it's from an outdated version of Spring Security). Your web.xml should contain
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>
This is covered in the namespace chapter of the manual, and also in the chapter on session management.
According to documentation
If you use this mechanism to detect session timeouts, it may falsely report an error if the user logs out and then logs back in without closing the browser. This is because the session cookie is not cleared when you invalidate the session and will be resubmitted even if the user has logged out. You may be able to explicitly delete the JSESSIONID cookie on logging out, for example by using the following syntax in the logout handler:
<http>
<logout delete-cookies="JSESSIONID" />
</http>
web.xml
<listener>
<listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class>
</listener>
Unfortunately this can't be guaranteed to work with every servlet container, so you will need to test it in your environment
I'm some what lost as to why spring isn't enforcing the #Secured("ROLE_USER") on my service interface. My controllers are established using annotations.
An example of my service Interface
public interface MyServiceManager {
#Secured("ROLE_USER")
public void delete(int cid);
#RolesAllowed({"ROLE_USER"})
public Contact getContact(int contactId);
}
my security-context:
<global-method-security secured-annotations="enabled" jsr250-annotations="enabled">
</global-method-security>
<http auto-config="true" >
<intercept-url pattern="/secure/**" access="ROLE_SUPERVISOR" />
<intercept-url pattern="/addcontact**" access="IS_AUTHENTICATED_REMEMBERED" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<concurrent-session-control max-sessions="1"
exception-if-maximum-exceeded="true"/>
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1"/>
<logout logout-success-url="/welcome.do" logout-url="/logout"/>
</http>
<authentication-provider>
<password-encoder hash="md5"/>
<user-service>
<user name="rod" password="a564de63c2d0da68cf47586ee05984d7" authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
</user-service>
</authentication-provider>
Do you have the statement
<global-method-security secured-annotations="enabled" jsr250-annotations="enabled" />
in the same configuration file as the one you defined the MyServiceManager bean? I had the same problem until I turned on debug for org.springframework, and noticed that spring security was only applied on the same file as the ones where global-method-security was defined in.
In my case, the exact location of this statement:
<global-method-security secured-annotations="enabled" >
proved to be very important. Make sure that you put it after you declare which classes should be scanned and used as controllers.
<context:component-scan base-package="com.test.controller" />
This is the way to make sure that the #Secured annotations will also get into the game
After doing more research on this problem I came to the following conclusion/solution. I'm not sure if it's 100% correct..but it works.
I put all of my configuration in the dispatcher-servlet.xml file. So instead of having a disptacher-servlet.xml and application-context.xml. The dispatcher-servlet.xml is loaded by the application (contextConfigLocation). Within the dispatcher-servlet.xml I import my security-context.xml and datasource-context.xml. Afer that, everything works.
I had this same problem. Using the information from Kent Lai's reply here, I was able to fix it.
I put the <global-method-security> element in my app-servlet.xml but kept the security definitions separate in security.xml, where web.xml has contextConfigLocation for app-servlet.xml and security.xml.
Works like a charm now!
Try putting the annotations on the implementation class instead of the interface and see if that works. I ended up doing that on a recent project because I was also using the #Transactional attribute on my service layer, and the Spring docs recommend putting those on the class and not the interface. I don't know if the same issue might apply to #Secured, but I wanted to keep the annotations in the same place. See the Spring Docs
Regarding Kent Lai's answer...that is a good idea...make sure that your security config file is actually being included by Spring.
Did you use something like this in your web.xml
<servlet>
<servlet-name>name</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I'm not sure why, but if I use the DispatcherServlet I was not able to enforce Security annotations
I had this same problem.
After I added:
<context:annotation-config />
in my spring-security.xml file it disappeared.
Hope this will help someone :)