Spring Boot MongoDB connection bean - spring

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.

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

Authorization Server

I am using Spring Rest + OAUTH2 + React in my project. For creating authorization server I got some code from an example. But the problem is I am not able to understand the code. Can someone explain me this code:
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(
new ClassPathResource("keystore.jks"), "suleman123".toCharArray())
.getKeyPair("resourcekey");
converter.setKeyPair(keyPair);
return converter;
}
/**
* This method configure client details service by using inMemory implementation. JDBC Implementation can also used
*/
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("acme") // client id
.secret("acmesecret") // required for trusted clients
.authorizedGrantTypes("authorization_code", "refresh_token",
"password") // Grant types that are authorized for the client to use
.scopes("openid") // scope to which the client is limited
.autoApprove(true);
}
/**
* This method configure the grant types. By default all grant types are supported except password
*/
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.authenticationManager(authenticationManager).accessTokenConverter(
jwtAccessTokenConverter());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess(
"isAuthenticated()");
}
}
Spring boot works with auto-configuration. What you see here is someone extending a spring auto-configuration class in order to customize it to his needs.
TL;DR:
They set a JWT based oauth2 authorization server.
Detailed Answer:
In this case, by combining #EnableAuthorizationServer and extending AuthorizationServerConfigurerAdapter, you can enable, manipulate and modify your authorization server.
In this example, instead of using normal string tokens, they want to use JWT. For that reason the first bean initialized is JwtAccessTokenConverter. More on JWT.
configure(ClientDetailsServiceConfigurer clients) - They configure one in-memory client to use in the application.
configure(AuthorizationServerEndpointsConfigurer endpoints) - They configure the default authenticationManager as the one initialized by spring and injected in the top of your configuration class and set the accessTokenConverter to use jwtAccessTokenConverter mentioned in #1. Doing that will allow them to generate JWT tokens when queering for a new token.
configure(AuthorizationServerSecurityConfigurer oauthServer) - They set all endpoints to allow access to everything when there is a token authenticated user (oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");).

Combining Spring Security and Active Directory with JWT-Tokens

I am currently working on building an Angular2-Application accessing a Spring Boot backend server for authentication and editing database data via REST-APIs. My current basic configuration to authenticate against our Active Directory looks like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().formLogin();
}
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder.authenticationProvider(activeDirectoryLdapAuthenticationProvider()).userDetailsService(userDetailsService());
}
#Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
}
#Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(AD_DOMAIN, "ldap://" + AD_URL);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
return provider;
}
This works so that I can access the basic Spring Boot Actuator-APIs after logging in using the default Boot Login Form.
The next step would be intertwining the activeDirectoryLdapAuthenticationProvider with a token-based authentication solution that can be accessed by Angular2 - for that, i found an example repository on gitHub. It implements HMAC-based authentication using JWT tokens with a custom service structure.
My issue now comes in understanding how the components of Spring Security work together in the background. As i understand the example, it implements a customised version of UserDetailsService and its environment using the UserDTO and LoginDTO. These access a MockUser-Service for example user data - which is what I want to avoid, instead accessing our Active Directory to authenticate users.
I am still digging through the repository trying to understand every customised class implementation and if I can customise the AuthenticationService to fit my needs, but I feel relatively lost.
What I am looking for are experiences in combining these three components, or with Spring Security and how exactly the default UserDetailsService and AuthenticationProviders interact, so I can try and fit the ActiveDirectory-logic into the token solution.
Alternatively, is there a way to combine the default-LDAP/AD-Configuration with a default JWT-Solution such as this?

Spring Security: Authenticate against multiple LDAP servers & DAO-based authentication

I'm working on a Springboot application which has a requirement to support authentication locally (through a DAO-based provider) and through multiple LDAP servers (administratively configured, stored in the database).
With a single LDAP provider my configure method looks like:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
auth.ldapAuthentication()
.userSearchBase(userSearchBase)
.groupSearchBase(groupSearchBase)
.userSearchFilter(userSearchFilter)
.userDetailsContextMapper(new DaoUserDetailsContextMapper())
.contextSource().url(url+"/"+base)
.managerPassword(managerPassword)
.managerDn(managerDn);
}
Through other similar posts it appears this could be accomplished through creating multiple LDAP providers, and Spring security will cycle through each one until a successful login is found. I have the associated LDAP configuration record associated as a foreign key on the User table.
Is there a more efficient way to try the specific LDAP endpoint associated with the user, or is it best to let Spring iterate through the available providers?
Thanks for any input!
after long search in my way, I found something interesting about how Spring Security authentification works (there is a video : https://youtu.be/caCJAJC41Rk?t=781)
After that, you can use the system that Spring has implemented which is to override the supports(class<?> authenticationClass) method. This method works as "Can you, AuthenticationProvider, manage this kind of AuthenticationClass ?" if true, the provider will try to authenticate the user, if not, never execute any tasks.
In that way, you can implement your own CustomAuthentificationProvider which implements the AuthenticationProvider interface.
public class LocalUserAuthenticationProvider implements AuthenticationProvider {
private final UserRepository;
public LocalUserAuthenticationProvider(UserRepository userRepository){
this.userRepository = userRepository;
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
/*my jobs*/
throws new AuthenticationException("Cannot authenticate");
}
#Override
public boolean supports(Class<?> aClass) {
return MyUsernameAuthenticationToken.class.isAssignableFrom(aClass);
}
}
with your own AuthenticationToken
public class StringUsernameAuthenticationToken extends UsernamePasswordAuthenticationToken {
public StringUsernameAuthenticationToken(Object principal, Object credentials) {
super(principal, credentials);
}
public StringUsernameAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(principal, credentials, authorities);
}
}
Actually I don't find any solutions with the LDAP authentication in the AuthenticationManagerBuilder implemented by Spring Security (ref : https://spring.io/guides/gs/authenticating-ldap/)
Hope this could help people

Spring Boot security - multiple authentication providers

My problem is that I would like to have two Authentication providers
BEFORE:
I have my UserDetailServiceImpl and I validated the users against DB(not sure what provider is it) The user got role according to the data in DB
NOW:
I have used ActiveDirectoryLdapAuthentication provider as follows
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider()).userDetailsService(userDetailService);
}
#Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
}
#Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
MyActiveDirectoryLdapAuthenticationProvider provider = new MyActiveDirectoryLdapAuthenticationProvider(domain, url, rootDN);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
return provider;
}
I made it work, so I'm able to authenticate.
THE PROBLEM:
I'm unable now to login with the database users anymore, only LDAP now.
The UserDetailsService is not used, so which role the user has?
Is there way how to add some default role to LDAP authenticated user?
So how to enable both providers?
How to add roles to user, authenticated through LDAP auth.provider?
I would also really appreciate "big picture" description of what is going on here(under the hood). What is the role of each of the classes used here, it is really unclear how does it work(AuthenticationManager, AuthenticationManagerBuilder, AuthenticationProvider etc.) Maybe it is just hidden by autoconfiguration and so, but even looking to Spring Security directly does not make me any wiser.
Thanks for any hints
UPDATE
This code seems to be working properly
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider()).userDetailsService(userDetailService);
}
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
MyActiveDirectoryLdapAuthenticationProvider provider = new MyActiveDirectoryLdapAuthenticationProvider(domain, url, rootDN);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setAuthoritiesMapper(new SimpleAuthorityMapper());
return provider;
}
Too many questions!
Both providers are enabled since you add them both to the AuthenticationManagerBuilder. But you add them both to the same filter chain and both accept the same kind of Authentication as inputs, so one of them always masks the other.
The standard LdapAuthenticationProvider has an authoritiesMapper that you can use to map authorities from the directory entries to your users (normally it is done out of the box using directory groups, e.g. see sample). I suppose if your directory doesn't contain groups you could make all users have the same authorities or something with a custom mapper.
Your #Beans of type AuthenticationManager and AuthenticationProvider look suspiciously redundant (and possibly harmful since they are global, and you are configuring the AuthenticationManagerBuilder for a single filter chain). I doubt you need that AuthenticationManager method at all and the other one doesn't need to be public or a #Bean (probably).

Resources