Reputation: 187
I'm trying to integrate SAML SSO into an existing application that uses Spring Security with users, groups, and roles/permissions stored in a MySQL database. The application currently uses <security:jdbc-user-service>
to get users and roles from the DB. The IDP in question offers only a unique username and an email address as attributes, so the application still has to store groups and roles associated with each user itself (as far as I understand).
So, I trying using both SAML and the DB by hooking the jdbc-user-service
up with the samlAuthenticationProvider
through the context configuration and a custom SAMLUserDetailsService
.
Here's the relevant part of my applicationContext.xml
:
<bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
<property name="userDetails" ref="customUserDetailService" />
</bean>
<bean id="customUserDetailService" class="org.myapp.CustomUserDetailsService">
<property name="jdbcUserService" ref="jdbcUserDetailService" />
</bean>
<bean id="jdbcUserDetailService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource" />
<property name="usersByUsernameQuery" value="select username,username as password,enabled from person where username=?" />
<property name="authoritiesByUsernameQuery" value="select u.username, p.name as authorities
from person u, group g, group_permissions up, permission p
where u.group = g.id and g.id = up.group and up.permissions = p.id and
u.username=?" />
</bean>
And this is the relevant part of CustomUserDetailsService
:
public class CustomUserDetailsService implements SAMLUserDetailsService {
private JdbcDaoImpl jdbcUserService;
@Override
public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException {
UserDetails user = null;
String username = credential.getAttributeAsString("urn:mace:dir:attribute-def:cn");
try {
user = jdbcUserService.loadUserByUsername(username);
} catch (UsernameNotFoundException e) {
System.out.println("User not found in DB");
// TODO
}
return user;
}
@Autowired
public void setJdbcUserService(JdbcDaoImpl jdbcUserService) {
this.jdbcUserService = jdbcUserService;
}
public JdbcDaoImpl getJdbcUserService() {
return jdbcUserService;
}
}
My question is: Is this a good idea to use org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl in this way?
I figured that the official Spring Security implementation (JdbcDaoImpl) of role retrieval from a DB is much more well-maintained, flexible, and bug-free than what I would come up with myself.
My second question is: Will using select username, username as password
create a security problem in the app somehow?
Since my app never gets to see the password (because the user only enters it at the IDP), I have to replace it with something in the query. Should I take care to make this something hard to guess or is the password in the UserDetails not re-used anyway?
Upvotes: 4
Views: 4856
Reputation: 13637
Consider the diagram as follows:
It describes all the typical steps for SAML-based Authentication process.
At this point, the IdP is guarantying for the user identity due to the trust relationship between the two parties. You don't need anymore to ask for a password because the AuthN process is completed. What you typically need at this point are the information to manage the resource access control, hence the Authorization (AuthZ). Generally the AuthZ is performed using a role model (RBAC):
The user "jdoe" is authenticated.
The user "jdoe" has "StandardUser" as role.
The resource A is available only for "Administrator".
The user "jdoe" is not authorised to access to the resource A.
As well:
The user "jdoe" is authenticated.
The user "jdoe" has "StandardUser" as role.
The resource B is available only for "StandardUser".
The user "jdoe" is authorised to access to the resource B.
Considering that all the users' roles are stored in a local DB, you have to retrieve those information performing a data-access in order to match identities and roles.
So:
Is this a good idea and/or the way it's meant to be used?
The method loadUserBySAML
is supposed to identify local account of user referenced by data in the SAML assertion and return UserDetails
object describing the user. At this point, you should also grant the proper authorities to a certain user, according to his role inside your application domain.
The local data retrieval implementation is up to you. You could use a standard access, performing a direct query on your database, or implement a modern data access model according to the JPA specifications (see Spring Data), by using as well an ORM.
Will using select username, username as password create a security problem in the app somehow?
As already said, you don't need to perform user credential verification on you application since you're using a SAML-based Authentication. The SSO is actually designed to not share critical information such as a password.
Upvotes: 1
Reputation: 569
1. Is this a good idea and/or the way it's meant to be used?
Yes, You can have custom user object in spring and populate the user details.
2.Will using select username, username as password create a security problem in the app somehow?
No , Spring SAML doesnt expect user password to be stored in user object (rather saml response will be validted by spring). spring will validate username and authority alone. I advise you to just set username and Granted Authorities in user object.
Upvotes: 1