I use Spring and Spring Security 3 at my application. All my clients side are static HTML files. I have a navigation bar that includes buttons like:
List
Edit
Delete
Update
When a user clicks any of them another page loads at bottom. Users have roles at my application. Some users do not have edit and delete authorization, while others do. That buttons should be visible to users which have the authorization. If a user doesn't have edit the correct permission he/she must not see the edit button. I have the buttons defined in an HTML file: navigation.html. I figured out that: there will be many navigation.html files. One of them includes all buttons(for admin) one of them just includes list button. If a user requests that navigation.html I want to send the correct one. So I can have that ability:
<logout logout-url="/j_spring_security_logout" logout-success-url="/login.html"/>
similar to that user will request that file from an URL(as like /navigation). There will be a controller to handle it so will return any of that navigation files.
Does that design sound correct? If so, how can I implement that? Any other simple solutions are welcome I am new to Spring and Spring Security.
For general Spring Security use, you don't need to write your own code to enable authorization. I generally configure Spring Security in XML to control access at a gross level to various resources based on Roles. Then, I annotate the controllers and/or handler methods to restrict more precisely.
Example:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns:security="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<security:global-method-security secured-annotations="enabled">
</security:global-method-security>
<security:http auto-config="true" disable-url-rewriting="true">
<security:intercept-url pattern="/*.do" access="ROLE_USER" />
<security:intercept-url pattern="/index.jsp" access="ROLE_USER" />
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/login.jsp" filters="none" />
<security:form-login login-page="/login.jsp" />
<security:logout />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:password-encoder hash="md5" />
<security:jdbc-user-service data-source-ref="my-ds"/>
</security:authentication-provider>
</security:authentication-manager>
</beans:beans>
And then in the Controller:
#Secured({"ROLE_SPECIAL_USER"})
#RequestMapping("/somespecial.do")
Within a JSP:
<%# taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<authz:authorize ifAnyGranted="ROLE_SPECIAL_USER">
...some special JSP code...
</authz:authorize>
Based on your using static HTML, I would think that the design you specify would be reasonable.
Have a Controller that maps to navigation.html, and it would simply look at the granted authorities of the current user and return the correct static html view name for the html file that has all (and only) the appropriate controls.
Related
it's my first question here in stackoverflow.
I'll try to explain my problem as much comprensible as possible.
I'm trying to develop a web-app with Java 8 using spring(not spring-boot), hibernate and angular 6. I already wrote back-end side (spring and hibernate), my entities work perfectly with my db (MySQL). I divided the back-end side into 3 maven modules (persistance (entities-repositories), service, web(controllers)) and added a front-end maven module with Angular 6.
And here there is my problem.
I am not able to connect angular with spring, in particular with spring security. I cut and paste the dist folder of angular inside src>main>webapp package and i cant and/or i dont know how to reach the angular's login page using spring security. I mean, i dont know how to relate angular login with spring login.
In the spring security config xml i wrote
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<http>
<intercept-url pattern="/home" access="permitAll" />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/signup" access="permitAll" />
<intercept-url pattern="/logout" access="isAuthenticated()" />
<intercept-url pattern="/**" access="hasRole('USER')" />
<form-login />
<logout />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="{noop}admin" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="user" password="{noop}user" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
i don't know how to relate the spring login page with my angular's login page, because the angular login page is not inside into dist folder.
Here there is the structure of my project:
myproject
----myproject-ng (angulars folder)
----myproject-persistence
--------entities
--------repositories
----myproject-service
--------serivices
----myproject-web
--------controllers
--------webapp
------------myproject-ng(angulars dist folder)
Ideally AngularJs 6 Project should run independent of the backend microservice. You will have to enable Cross Origin request in controller by #CrossOrigin annotation.
Recently I am using Spring Security basic authentication for my REST services.
Below is the security xml configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<security:http pattern="/rest/**" create-session="never" use-expressions="true">
<security:http-basic />
<security:intercept-url pattern="/rest/auth/**" access="isAuthenticated()"/>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider>
<security:user-service>
<security:user name="admin" password="admin" authorities="ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder hash="sha-256" />
</security:authentication-provider>
</security:authentication-manager>
<security:global-method-security jsr250-annotations="enabled" pre-post-annotations="enabled"/>
</beans>
Spring framework and Spring Security that I use:
<springframework.version>4.1.0.RELEASE</springframework.version>
<spring.security.version>3.2.5.RELEASE</spring.security.version>
I map my REST services to URL prefixed with "rest/" and when I access the URL for the first time, the browser prompt the username and password field of basic authentication. I fill it with the right credential and my controller accessed successfully.
However if I try to access the same URL with browser again, it will not prompt me the username and password field of basic authentication again and directly access the URL.
I expect that browser always prompt me with basic authentication because I set create-session attribute to never.
So, am I missing something?
Browser caches credentials. Sometimes clearing the cache doesn't help. The only reliable way how to fake it is use Chrome's incognito window (Ctrl+N). But one prompt per one incognito window. So you need new incognito window when you want to enter them again.
This is the only way I found to test basic authentication manually.
From the javadoc for create-session. I think your application is creating a sessions and that session is being used.
Attribute : create-session Controls the eagerness with which an HTTP
session is created by Spring Security classes. If not set, defaults
to "ifRequired". If "stateless" is used, this implies that the
application guarantees that it will not create a session. This
differs from the use of "never" which mans that Spring Security will
not create a session, but will make use of one if the application
does.
Data Type : string Enumerated Values :
- ifRequired
- always
- never
- stateless
You should try using
"stateless"
instead of
never
I am trying to find a way just to setup a URL that will logout my user from the system. this is only for testing. Right now we are using the default login page in spring secuirty
here is my spring-secuirty.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<global-method-security pre-post-annotations="enabled" />
<http use-expressions="true">
<intercept-url access="hasRole('ROLE_VERIFIED_MEMBER')" pattern="/ask-union**" />
<intercept-url access="hasRole('ROLE_VERIFIED_MEMBER')" pattern="/ask-welfare**" />
<intercept-url pattern='/*' access='permitAll' />
<form-login default-target-url="/ask-union" />
<logout logout-success-url="/" />
<session-management session-fixation-protection="newSession">
<concurrency-control max-sessions="1"/>
</session-management>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="xxxxx#aol.com.dev" password="testing" authorities="ROLE_VERIFIED_MEMBER" />
ser-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Add this line to your config
<logout logout-url="/sign-out"/>
Then if you have a link to that URL, then it will sign you out
(Add it just below your logout success config)
I am a bit late on this. But answer may help others.
Use following code. logout-success-url is the URL you want take user after logging out.
<http auto-config="true" use-expressions="true" access-denied-page="/denied">
<logout invalidate-session="true" logout-success-url="/landing" delete-cookies="JSESSIONID" />
</http>
Double-check the URL you're using -- the absolute path should be your-domain/projectPath/sign-out, per SJS's example. If the relevant portion of your spring-security.xml file looks like the following, it should work:
<http use-expressions="true">
. . .
<logout
logout-success-url="/"
logout-url="/sign-out"/>
If you're able to authenticate, then simply browse to that path, and it should log you out. If it still doesn't try experimenting with the intermediary subdirectories specified in the URL, i.e. your-domain/projectPath/some-subdirectory/log-out.
Are you able to authenticate? It may not just be the logout aspect that's failing...
Late to the party, but for future reference -- if you are interested in seeing how the security filters are instantiated and configured from XML, take a look at the following package:
org.springframework.security.config.annotation.web.configurers
For the logout filter configuration, this will be the LogoutConfigurer class. If you review the LogoutConfigurer.createLogoutFilter() method, you'll see how the default Logout filter is created. This implies that you can do the following in an #Configuration class:
#Bean
public LogoutFilter logoutFilter() {
// NOTE: See org.springframework.security.config.annotation.web.configurers.LogoutConfigurer
// for details on setting up a LogoutFilter
SecurityContextLogoutHandler securityContextLogoutHandler = new SecurityContextLogoutHandler();
securityContextLogoutHandler.setInvalidateHttpSession(true);
LogoutFilter logoutFilter = new LogoutFilter("/", securityContextLogoutHandler);
logoutFilter.setLogoutRequestMatcher(new AntPathRequestMatcher("/logout"));
return logoutFilter;
}
If you have that, you can then either configure further by beans or have that bean picked up automatically since its method name is logoutFilter()
Want to login using Email OR mobile number using spring security.
Here is my code:--
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http pattern="/admin" security="none" />
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/admin*" access="hasRole('SYS_ADMIN')" />
<intercept-url pattern="/cab-stop-admin*" access="hasAnyRole('SYS_ADMIN','CABSTOP_ADMIN')" />
<intercept-url pattern="/driver*" access="hasAnyRole('DRIVER','SYS_ADMIN','CABSTOP_ADMIN')" />
<intercept-url pattern="/customer*" access="hasAnyRole('CUSTOMER','SYS_ADMIN','CABSTOP_ADMIN')" />
<form-login login-page="/login" default-target-url="/role-check"
authentication-failure-url="/login?error=true" />
<remember-me key="_spring_security_remember_me" data-source-ref="fmsDataSource" authentication-success-handler-ref="loginSuccessHandler"/>
<logout logout-success-url="/" />
<access-denied-handler error-page="/login"/>
</http>
<beans:bean id="loginSuccessHandler" class="com.cabfms.authentication.LoginSuccessHandler"></beans:bean>
<authentication-manager>
<authentication-provider>
<!-- <password-encoder hash="md5" /> -->
<jdbc-user-service data-source-ref="fmsDataSource"
users-by-username-query="select Email,Password, 'true' as enabled from login_details where Is_Blocked = 'N' and Deleted='N' and Email=?"
authorities-by-username-query="select u.Email, ur.Role_Name from login_details u, role_master ur where u.Role_Master_Id = ur.Role_Master_Id and u.Email =?" />
</authentication-provider>
</authentication-manager>
</beans:beans>
In this code I have a query like
select Email,Password, 'true' as enabled from login_details where Is_Blocked = 'N' and Deleted='N' and Email=?
where I match only email but I want to match mobile number also.** means I want to match Email OR Mobile number (Any One) because I pass any one from tha JSP (Email OR Mobile)
So please Suggest your answer
Thanks In Advance
How does your JSP look like? Do you have a form with a j_username or are using two separate fields for email and mobile?
If you're passing both you'll have to implement your own authentication manager. The concrete user details service used by Spring Security when you declare jdbc-user-service> is a JdbcDaoImpl which implements UserDetailsService. That interface has a loadUserByUsername(String) method which obviously only accepts a username.
If you want to allow your users to enter either email or mobile in a single text input named j_username it might work if your query is
... where Is_Blocked = 'N' and Deleted='N' and (Email=? or Mobile=?)
I have problems with double authentication. I have implemented the authentication form through pop-up window which is always on top. But I have problem probably with interceptors that cause the authentication request by Tomcat even before the start of application:
A username and password are being requested by http://127.0.0.1:8888.
The site says: "Spring Security Application"
If I disable interceptors, I see in log that SecurityContextHolder treats user as Anonymous.
So my question is:
Can I somehow disable that first Tomcat login screen?
My Spring-security configuration XML is:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<authentication-manager alias="authenticationManager">
<authentication-provider ref="customAuthenticationProvider"/>
</authentication-manager>
<beans:bean id="customAuthenticationProvider" class="com.myCompany.model.security.CustomAuthenticationProvider" >
<beans:property name="databaseId" value="${configuration.databaseId}" />
<beans:property name="applicationId" value="${configuration.applicationId}" />
</beans:bean>
<http auto-config="true" >
<intercept-url pattern="/myApp/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/MyApp.html*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/gwt/**" access="ROLE_USER"/>
<intercept-url pattern="/**/*.html" access="ROLE_USER"/>
<intercept-url pattern="/css/**" filters="none"/>
<intercept-url pattern="/**" access="ROLE_USER" />
<http-basic />
</http>
<global-method-security secured-annotations="enabled" />
</beans:beans>
In case I understand your question in a correct way you have a problem with double authentication e.g. a Tomcat authentication or an Apache Basic Auth and the Spring authentication mechanism.
While the last project I had related problems with an Apache Basic Auth and the Spring security mechanism. Before launch I had the task to "protect" the access to the site by an simple Apache Basic Auth. By enabling this in the Apache configuration Spring started to do the same: "Spring Security Application" has been shown all the time
The solution for this behaviour was to disable the auto-config:
<security:http auto-config="false" ...>
...
</security:http>
Your question is not too clear. You mention a Tomcat login screen, which I assume is the first screen of your web application, to allow a user to sign in.
If this is correct, and your login page is named, say login.html, all you have to do is configure the interceptors to allow anonymous access to this page-
<intercept-url pattern="/**/login.*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/gwt/**" access="ROLE_USER"/>
<intercept-url pattern="/**/*.html" access="ROLE_USER"/>
<intercept-url pattern="/css/**" filters="none"/>
<intercept-url pattern="/**" access="ROLE_USER" />