I am new in ss3,and I have read its reference,also I read the spring security book.
However I do not find anything about the role-permission.
For example,here is the config for form-based authentication.
<http auto-config='true'>
<intercept-url pattern="/user/add/**" access="hasRole('USER_ADMIN')"/>
<intercept-url pattern="/user/delete/**" access="hasRole('USER_ADMIN')"/>
<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page='/login.jsp'/>
</http>
I want to control the user operation(add/delete):
<intercept-url pattern="/user/add/**" access="hasRole('USER_ADMIN')"/>
<intercept-url pattern="/user/delete/**" access="hasRole('USER_ADMIN')"/>
I define the role of 'USER_ADMIN',but this is not enough,since I want to differ the user who have 'add' permission from user who have 'delete' permission.
Maybe I can add more roles like 'user_admin_add' and 'user_admin_delete'.
But I do not think this is a good idea since the 'add' or 'delete' are permissions,not roles.
How to make it?
Also,it seems that all the roles should be configed to the xml file,I wonder if I can add new roles and permissions dynamically(in the administrator page)?
Think of roles as a privileges. And granulate them as much as you need. Another thing is that maybe you should make a more RESTFul implementation. But this is another thread.
For example, your "delete" could be a "DELETE" HTTP method. Then you could be:
<security:intercept-url pattern="/users/*" method="DELETE" access="ROLE_DELETE_USER" />
and a curl -X DELETE -u login:password 'http://example.com/users/1'
would delete the user with id 1.
By a RESTFul, since uris are either identifiers or actions, there is no use in add roles (privileges) dinamically. Since those roles are meant to be used against a new resource that should contain the xml file.
I'm afraid you cannot do this, unless you use ** wildcards. Which in my opinion if used uncarefully can lead to troubles.
Maybe I can add more roles like 'user_admin_add' and 'user_admin_delete'.
This is the way. Permissions are roles and generally there are people who view differentiation between them as unneeded.
I don't think there is much difference in having a role ROLE_USER_ADDER or a permission PERMISSION_ADD_USERS.
You can however use roles as a concept to group permissions if you need to. For instance you can have a role admin which can add and remove users. So the role ROLE_ADMIN will have PERMISSION_ADD_USER and PERMISSION_REMOVE_USER. Still spring will view both roles and permissions simply as authorities.
As for dynamic roles adding you can do it by loading the current user permission from your DB for instance. Have a look at the UserDetailsService of spring security. The UserDetails object it returns has a getAuthorities() method which you can populate from your DB.
/**
* Returns the authorities granted to the user. Cannot return <code>null</code>.
*
* #return the authorities, sorted by natural key (never <code>null</code>)
*/
Collection<GrantedAuthority> getAuthorities();
Here is a very good example of implementing your own UserDetailsService.
In my personal opinion spring security has several (lets say) unfortunately chosen names. So do not pay so much attention to the Term "Role" it works perfectly if you use it for privileges.
In my applications a use a naming convention to choose between Roles ans Privileges. (roles are written upper case, privileges lower case). But pay attention the Role Voter will pay attention only the the strings that starts with "ROLE" (Default configuration, can be changed.)
See also Spring security group based authorization
You should be thinking of roles more along the lines of, well, roles, rather than permissions. If you want to differentiate between adding and removing users, you might define roles described as ROLE_SALES and ROLE_USER_ADMIN. Sales staff might well need to be able to add new users into a system.
Regarding the dynamic application of roles, you should look at the architecture of Spring Security. You'll most likely want to use, or implement, a suitable UserDetailsService. See the UserDetailsService reference documentation.
If you're storing your user authorization information in a JDBC database, for example, you might want to use the JdbcDaoImpl.
There are some examples of using different authentication providers in the namespace introduction.
Related
I came across this code snippet while debugging an authentication problem :
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder hash="sha-256">
<security:salt-source user-property="dateCreated" />
</security:password-encoder>
</security:authentication-provider>
<security:authentication-provider ref="ldapAuthProvider" />
</security:authentication-manager>
What I have noticed while debugging and playing around with the user credentials is that if the first authentication-provider (i.e. userDetailsService) fails to authenticate my user, a remote call is then made to my LDAP server to try to authenticate my user. However if the first authentication-provider manages to authenticate my user successfully, the second authentication-provider is never called.
My question is does the listing of these authentication providers work in a way that if one fails we should jump to the next? I also wonder if the order of them authentication providers listed within the authentication manager plays a role (from a priority standpoint)? An extra reference from Spring Security's official documentation will be more than appreciated.
From the Spring Security reference documentation:
Each AuthenticationProvider has an opportunity to indicate that authentication should be successful, fail, or indicate it cannot make a decision and allow a downstream AuthenticationProvider to decide. If none of the configured AuthenticationProviders can authenticate, then authentication will fail (...)
In practice each AuthenticationProvider knows how to perform a specific type of authentication. For example, one AuthenticationProvider might be able to validate a username/password, while another might be able to authenticate a SAML assertion.
When multiple AuthenticationProviders are defined, they will be queried in the order they are declared.
If the first AuthenticationProvider cannot come to a conclusion it will allow the next AuthenticationProvider to try.
I have searched enough but I haven't got a clear answer and thus posting this question.
I have an existing application which uses spring security for authentication.
Current implementation uses a custom implementation of UsernamePasswordAuthenticationFilter for doing this.
Thus the flow is something like below(in very simple terms):
inputrequest>DelegatingFilterProxy>LoginUrlAuthenticationEntryPoint>CustomUsernamePasswordAuthenticationFilter>AuthenticationManager>CustomAuthenticationProvider
Now I have a requirement to implement SSO (since the user is already asusmed to be authenticated) in some scenarios.
The requirement states that if I have a specific request parameter present then I need to automatically authenticate the request without bothering about user/password.
So it is same set of resources and I do not have to authenticate user/password if the specific SSO related request parameter is present.
e.g
suppose a resource \test\bus is a secure resource.
if I come from normal way then we need to check if the user is authenticated or nor and force user to put valid user/password
if I come from SSO channel then I need to show the \test\bus resource as the user is already authenticated.
currently all the access restrictions are put through <http> element
e.g the snippet of security-config.xml is as follows:
Query: What options do I have in this case. I can think of below options:
Pre-authenticate the user before spring security framework kicks in. This will mean creating an authentication token and putting in spring context before spring security filter is called. This can be done through another filter which is called before spring security filter chain. I have tested it and it works.
Create another custom security filter which set-up the authentication token. I am not clear if this is correct approach as not sure when do we create multiple custom security filter
Create another custom authentication provider e.g SSOCustomAuthenticationProvider. This provider will be called in the existing current flow as we can have multiple authentication providers to a authentication manager. The only issue is that in order to achieve this I have to change the request url to authentication filter's target url so that spring security doesn't check for authentication.
to explain more,
let's say request uri is /test/bus, I will write a filter which will intercept the request and change it to /test/startlogin. This is currently my CustomUsernamePasswordAuthenticationFilter's target url i.e
<property name="filterProcessesUrl" value="/test/startlogin"/>
The flow will be
inputrequest>DelegatingFilterProxy>LoginUrlAuthenticationEntryPoint>CustomUsernamePasswordAuthenticationFilter>AuthenticationManager>SSOCustomAuthenticationProvider
I have tested this and this works. Is this a valid approach or a hack.
Is there any other viable option available with me.
Thanks for reading this.
In Spring Security we can have roles but this is not sufficient for my case. For example if User A log in he can't view/change User B's data and both users will have same role like ROLE_USER. Is there any built in mechanism for this in Spring Security ?
You can add method level security in that you check if that user with ROLE_USER can access particular resource with help some expression as given here
And configuration can be done as given here
I am using spring security 4 and I realized that if I add a url handler in the controller and forget to specify access rights in spring security xml , this page will not be secured and will be accessible to all. I was trying to use:
<intercept-url pattern="/**" access="denyAll" />
But it bans all users, even those I specifically open access to in other tags.
Maybe you think about something like that?
access="isAuthenticated()"
as said here it returns true if the user is not anonymous.
I think the main idea of keeping app secure is not to make mistakes by human too... Even the best security system is not secure when human forgot to set a password.
Let's say I have users and articles.
Anonymous can list and read articles.
Only registered and logged user can create articles.
User can edit only own articles.
And, of course, admin can do anything.
I've looked at spring security, but didn't found a way to do that. My app don't need roles, and ACL will be too "heavy" for that.
Maybe I should implement my own security?
You're right, ACL would be too much for the task.
You can use Spring Security's authorize tag in JSP, which provides access to the logged in user via the principal object. Example to limit access to editing an article to the user with a given username:
<sec:authorize access="hasRole('SOME_PRIVILEGE_OR_ROLE') and ${someArticle.username} == principal.username">
...
</sec:authorize>
Note that SOME_PRIVILEGE_OR_ROLE could be some role like 'LOGGED_IN_USER', but could also rather specify a certain privilege, e.g. 'READ_ARTICLE' or 'UPDATE_ARTICLE'. Spring Security is flexible here. Whatever you choose, it needs to be in the GrantedAuthorities collection of your user object.
Note also that you can implement your own user object, adding further info to what the UserDetails interface provides, e.g. comparing the user's id rather than the username.
Finally, note that you need a recent version of Spring Security (>=3.1) for the Spring EL to work as in the example.