Spring Security Stored Procedures - spring

Can I use stored procedures for login in Spring Security? If possible can you give an example?
Now I can login with this queries
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery( "select login, password, 'true' from my_user " +"where login=?")
.authoritiesByUsernameQuery("select login, authority from my_user " + "where login=?");
}

Related

Authentication with Spring-Security via Active Directory LDAP

I can't authenticate using a real active directory, let me explain better I tried to authenticate using the example proposed by spring.io without problem where a internal service is started without any problem.
reference https://spring.io/guides/gs/authenticating-ldap/
I tried to modify the code below by inserting the configuration of my active directory without success. Can you kindly guide me or show me a real case where a true connection is made without using internal services like those in the examples? I looked on the net but found everything similar to the official example without any real case
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userDnPatterns("uid={0},ou=people")
.groupSearchBase("ou=groups")
.contextSource()
.url("ldap://localhost:8389/dc=springframework,dc=org")
.and()
.passwordCompare()
.passwordEncoder(new LdapShaPasswordEncoder())
.passwordAttribute("userPassword");
}
Error show:
Uncategorized exception occured during LDAP processing; nested exception is javax.naming.NamingException: [LDAP: error code 1 - 000004DC: LdapErr: DSID-0C0907C2, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v2580
Yeah, authentication via LDAP that's too painful. In order to be able to perform authentication to AD you need to use the ActiveDirectoryLdapAuthenticationProvider.
Here is the working sample:
#Override
protected void configure(AuthenticationManagerBuilder auth) {
ActiveDirectoryLdapAuthenticationProvider adProvider =
new ActiveDirectoryLdapAuthenticationProvider("domain.com", "ldap://localhost:8389");
adProvider.setConvertSubErrorCodesToExceptions(true);
adProvider.setUseAuthenticationRequestCredentials(true);
auth.authenticationProvider(adProvider);
}
And to save your time just read the following, that's really important:
AD authentication doc
I found a sample over here, which was useful:
https://github.com/sachin-awati/Mojito/tree/master/webapp/src/main/java/com/box/l10n/mojito/security
You can optionally implement UserDetailsContextMapperImpl which overrides mapUserFromContext to create the UserDetails object if the user is not found during the Active Directory lookup - loadUserByUsername.
#Component
public class UserDetailsContextMapperImpl implements UserDetailsContextMapper {
#Override
public UserDetails mapUserFromContext(DirContextOperations dirContextOperations, String username, Collection<? extends GrantedAuthority> authorities) {
UserDetails userDetails = null;
try {
userDetails = userDetailsServiceImpl.loadUserByUsername(username);
} catch (UsernameNotFoundException e) {
String givenName = dirContextOperations.getStringAttribute("givenname");
String surname = dirContextOperations.getStringAttribute("sn");
String commonName = dirContextOperations.getStringAttribute("cn");
userDetails = userDetailsServiceImpl.createBasicUser(username, givenName, surname, commonName);
}
return userDetails;
}
Ensure you are using the ActiveDirectoryLdapAuthenticationProvider spring security class as Active Directory has its own nuances compared to other LDAP servers. You'll probably need to be using the #EnableGlobalAuthentication annotation in your security configuration class as you can have multiple AuthenticationManagerBuilders which confuses things a lot.
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
ActiveDirectoryLdapAuthenticationProvider adProvider =
new ActiveDirectoryLdapAuthenticationProvider("domain.com", "ldap://primarydc.domain.com:389");
adProvider.setConvertSubErrorCodesToExceptions(true);
adProvider.setUseAuthenticationRequestCredentials(true);
auth.authenticationProvider(adProvider);
}
More details here:
https://github.com/spring-projects/spring-security/issues/4324
https://github.com/spring-projects/spring-security/issues/4571

Basic jdbc authentication, authorization not working

I am novice in spring security. Just added simple basic authentication to my project using jdbcauthenticationmanager and it is not working.
SpringSecurityConfig
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource ds;
#Bean
public BCryptPasswordEncoder getEncoder() {
return new BCryptPasswordEncoder(12);
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(ds).usersByUsernameQuery("select * from users where username = ?")
.authoritiesByUsernameQuery("select username, authority from roles where username = ?")
.passwordEncoder(getEncoder());
;
}
#Override
public void configure(HttpSecurity http) throws Exception {
// Spring Security 4 automatically prefixes any role with ROLE_.
http.authorizeRequests().antMatchers("/").permitAll().anyRequest()
.hasAnyRole("ADMIN","USER").anyRequest().authenticated().and().httpBasic();
}
}
Data in table:
insert into users ( username, password)
values ( 'payal', '$2a$12$YcoYj8Si2mbx.gYTLWwPeu51cfI2bTJlWBnnpaI2uYitfQtKzjPxm');
insert into users ( username, password)
values ( 'admin', '$2a$12$vhk1ELFdkwuvtAb8HrnUzOHEGJsnqX5ZX.C3TV3Q4Vuu9dsDcRH8e');
insert into roles ( username, authority)
values ( 'payal', 'ROLE_USER');
insert into roles ( username, authority)
values ( 'admin', 'ROLE_ADMIN');
The entire code can be found at https://github.com/payalbnsl/SpringMvcSecurity_err
This is using in-memory database with db scripts, so can just run without any extra set-up needed.
It will be of great help if someone can point out why it is not authenticating successfully. Every username, password, it is saying 401, not authorized
However it works if i change it to inMemoryAuthentication, hardcoding the username, password.
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("payal").password("$2a$12$YcoYj8Si2mbx.gYTLWwPeu51cfI2bTJlWBnnpaI2uYitfQtKzjPxm").roles("USER");
}
Worked if changed
auth.jdbcAuthentication().dataSource(ds).usersByUsernameQuery("select * from users where username = ?")
.authoritiesByUsernameQuery("select username, authority from roles where username = ?")
.passwordEncoder(getEncoder());
;
to
auth.jdbcAuthentication().dataSource(ds).usersByUsernameQuery("select username, password, 'true' as enabled from users where username = ?")
.authoritiesByUsernameQuery("select username, authority from roles where username = ?")
.passwordEncoder(getEncoder());
;
Adding "'true' as enabled" fixed it.
You have to store encrypted password using the default method, bcrypt, not plaintext.
Use this to encrypt your passwords and store the encrypted format
System.out.println(new BCryptPasswordEncoder().encode("payal123"));
System.out.println(new BCryptPasswordEncoder().encode("admin"));
// . . .

Spring Boot MongoDB connection bean

I have situation like this.
I'm using Spring boot 1.3.2, and I have installed MongoDB on my pc
I have added dependency
org.springframework.boot:spring-boot-starter-data-mongodb
And when I run my web application, database connection automatically start working.
I didn't configure a thing.
Now I want to connect spring security like this:
#Override
protected void configure(AuthenticationManagerBuilder auth)
                                                   throws Exception {
  auth
    .jdbcAuthentication()
      .dataSource(dataSource);
}
My question is what is default bean name for Spring Boot DataSource and can I override it?
If you're planning to use Mongodb as your user details storage, i.e. username, password, etc. , then you can't use the jdbcAuthentication(). Instead, You could use a UserDetailsService in order to achieve the same:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired private MongoTemplate template;
#Override
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService((String username) -> {
User user = template.findOne(Query.query(Criteria.where("username").is(username)), User.class, "users");
if (user == null) throw new UsernameNotFoundException("Invalid User");
return new UserDetails(...);
});
}
}
In the prceeding sample, i supposed that you have a users collection with a username field. If exactly one user exists for the given username, you should return an implementation of UserDetails corresponding to that user. Otherwise, you should throw a UsernameNotFoundException.
You also have other options for handling user authentication but jdbcAuthentication() is off the table, since you're using a NoSQL datastore for storing user details and JDBC is an abstraction for handling all the talkings with Relational databases.

How to use Spring Security's JDBC authentication without using "authorities"?

I have problem with authorities.
Reason: PreparedStatementCallback; bad SQL grammar [select
username,authority from authorities where username = ?]; nested
exception is org.postgresql.util.PSQLException: ERROR: relation
"authorities" does not exist Position: 32
I don't want to implement authorities, but don't know how to disable it in JavaConfig in Spring.
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(
"select username,password,'true' as enabled from users where username=?")
.passwordEncoder(new ShaPasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
}
As far as I know, you can't deactivate the authorities mechanism with JavaConfig in Spring Security but you can override the query used to fetch the authorities data to achieve the same effect.
When using Spring Security's JDBC authentication, it makes certain assumptions about the database scheme to retrieve authentication data. You already override the query used to fetch the user data in your example with the the call to usersByUsernameQuery().
I managed to effectively disable the whole authorities check by also overriding the query to fetch authorities data like this (as described in "Spring in Action" by Craig Walls):
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder)
throws Exception {
authenticationManagerBuilder.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery(
"SELECT username, password, enabled FROM users WHERE username=?")
.authoritiesByUsernameQuery(
"SELECT username, 'ROLE_USER' FROM users WHERE username=?");
}

Spring Security / rolesAllowed / antMatchers

I am using Spring Data REST and I have a find method in my repository:
public List<Contact> findByLastNameOrderByLastNameAsc(#Param("lastName") String lastName);
I am trying to add security to the method, but no luck. In my DB, I have 1 user with the role 'ROLE_USER'. When the service starts, the login form comes up and I am able to login with the credentials in the DB.
Here is my web security config:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select username,identification,enabled from users where username = ?");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/contacts/findByLastNameOrderByLastNameAsc").hasRole("ADMIN")
.antMatchers("/contacts/**").fullyAuthenticated()
.antMatchers("/contacts/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin();
}
When I try to invoke the service in my repository, I am not seeing any authentication error. Using my browser, the URL comes up fine, even though the user in the DB does not have the 'ADMIN' role.
I tried adding 'RolesAllowed' to the method in my repository, but no luck:
#RolesAllowed(value = { "ADMIN" })
public List<Contact> findByLastNameOrderByLastNameAsc(#Param("lastName") String lastName);
Am I going about adding security to the REST API provided by Spring Data correctly? Ideas on how to get this to work?
thanks
FWIW: I forgot to add the jsr250 support. So, I added this config:
#Configuration
#EnableGlobalMethodSecurity(jsr250Enabled = true)
public class MethodSecurityConfig {
}
Now the RolesAllowed annotation is working fine.

Resources