spring boot ldap additional details - spring

I have an application configured with LDAP and it works perfectly fine. But now I would need to pull details of users manager. I am not able to get the details please find the details
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws
Exception {
auth
.ldapAuthentication()
.userSearchBase("dc=ab,dc=test,dc=com")
.userSearchFilter("TestName={0}")
.groupSearchBase("ou=Groups,dc=ab,dc=test,dc=com")
.groupSearchFilter("member={1}")
.groupRoleAttribute("cn")
.userDetailsContextMapper(userContextMapper())
.contextSource(contextSource());
}
#Bean
public LdapContextSource contextSource() {
LdapContextSource contextSource= new LdapContextSource();
contextSource.setUrl("ldap:test");
contextSource.setUserDn("CN=,OU=Accounts,DC=ab,DC=test,DC=com");
contextSource.setPassword();
return contextSource;
}
#Bean
public InetOrgPersonContextMapper userContextMapper() {
return new InetOrgPersonContextMapper();
}
I am able to fetch user but I need users manager details.

Try this, you can get all authenticated user details from the class InetOrgPerson ! due to the implementation of your bean userContextMapper.
public void printDetails() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
InetOrgPerson person = (InetOrgPerson)(authentication.getPrincipal());
System.out.println(person.getUsername());
System.out.println(person.getGivenName());
System.out.println(person.getHomePhone());
}
// various methods are implemented in the inetOrgPerson class to getting more ldap informations

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

How to Connect to an LDAP Server and how to validate AD Groups in a Spring Boot Application

I have a Spring Boot application.
I want to connect to an LDAP server and query for valid AD groups.
I hope you are familiar with Spring Security. Write a configuration class which extends WebSecurityConfigurerAdapter and configure AD authentication provider. Refer below code. Change antMatchers to match your app.
Add dependencies spring-security-ldap,spring-boot-starter-security as well.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private Environment env;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().antMatchers(AppConstants.LOGIN_URI).fullyAuthenticated().and().formLogin().permitAll();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
String ldapUrl = env.getProperty(AppConstants.LDAP_URL);
String ldapDomain = env.getProperty(AppConstants.LDAP_DOMAIN);
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(ldapDomain,
ldapUrl);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
auth.authenticationProvider(provider);
}
To get the groups to which user is assigned inject instance of Authentication/Principal in controller class. Get
To get all attributes against the user like email, manager etc. you may will need to write a custom mapper though. Refer code below.
#GetMapping(value = { AppConstants.REST_API_LOGIN })
public ResponseEntity<User> authenticateUser(Authentication auth) {
List<String> ldapRoles = new ArrayList<String>();
auth.getAuthorities().forEach(a -> ldapRoles.add(a.getAuthority()));
/*
Write service class methods to compare ldapRoles against app specific roles from DB and exception handlers to handle exceptions
*/
User user = userService.getUser(auth);
if (!user.isAuthorized()) {
logger.info("User:" + auth.getName() + " is not authorized to access program.");
throw new UserAuthenticationException(AppConstants.NOT_VALID_MEMBER, user);
}
logger.info("User:" + auth.getName() + " logged in");
return new ResponseEntity<User>(user, HttpStatus.OK);
}

Add optional Google Sign In in my Spring Boot + Security + web Application

I am working on a Spring boot web application. I have now working a registration and login system using Spring Security with a custom userDetailService.
Now I want add a register-login system using Google Accounts. I created my Google API keys and added them to the application.properties. I think is not necessary use .yml propertie files here:
# ===============================
# = OAUTH2
# ===============================
security.oauth2.client.client-id=clientId Here
security.oauth2.client.client-secret=clientSecret here
security.oauth2.client.access-token-uri=https://www.googleapis.com/oauth2/v3/token
security.oauth2.client.user-authorization-uri=https://accounts.google.com/o/oauth2/auth
security.oauth2.client.token-name=oauth_token
security.oauth2.client.authentication-scheme=query
security.oauth2.client.client-authentication-scheme=form
security.oauth2.client.scope=profile
security.oauth2.resource.user-info-uri=https://www.googleapis.com/userinfo/v2/me
security.oauth2.resource.prefer-token-info=false
I added OAuth2 support to my Spring Boot application on this way:
#SpringBootApplication
#EnableOAuth2Sso
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
Now I want keep the posibility to login using Google or login using a website account, but I only found manuals about unique login or multiple providers login (Facebook, Google, Twitter..)
In my SpringSecurity configuration class I have this. I think that I have to create a authenticationProvider for Google and link it to the google access url in my app, but I am so confused yet about this:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
/**
* Obtenemos información de persistencia
*/
// #formatter:off
auth
//.authenticationProvider(googleOauth2AuthProvider())
.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder);
// #formatter:on
}
...
#Override
protected void configure(HttpSecurity http) throws Exception {
String[] anonymousRequest = { urls};
http
.authorizeRequests()
//..other rules
You have to use a composite filter in which you configure your desired authentication providers, for example:
private Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
filters.add(ssoFilter(facebook(), "/login/facebook"));
filters.add(ssoFilter(google(), "/login/google"));
filter.setFilters(filters);
return filter;
}
private Filter ssoFilter(ClientResources client, String path) {
OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationFilter = new OAuth2ClientAuthenticationProcessingFilter(
path);
OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
oAuth2ClientAuthenticationFilter.setRestTemplate(oAuth2RestTemplate);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(client.getResource().getUserInfoUri(),
client.getClient().getClientId());
tokenServices.setRestTemplate(oAuth2RestTemplate);
oAuth2ClientAuthenticationFilter.setTokenServices(tokenServices);
return oAuth2ClientAuthenticationFilter;
}
where:
#Bean
#ConfigurationProperties("google")
public ClientResources google() {
return new ClientResources();
}
#Bean
#ConfigurationProperties("facebook")
public ClientResources facebook() {
return new ClientResources();
}
and:
class ClientResources {
#NestedConfigurationProperty
private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails();
#NestedConfigurationProperty
private ResourceServerProperties resource = new ResourceServerProperties();
public AuthorizationCodeResourceDetails getClient() {
return client;
}
public ResourceServerProperties getResource() {
return resource;
}
}
finally, add the filter before the BasicAuthenticationFilter in your HTTP security config:
#Override
protected void configure(HttpSecurity http) throws Exception {
String[] anonymousRequest = { urls};
http
.authorizeRequests()
//..other rules
addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
Ps: your configuration properties has to start with the value specified in the #ConfigurationProperties("facebook"):
facebook:
client:
clientId: yourCliendId
clientSecret: yourClientSecret
accessTokenUri: https://graph.facebook.com/oauth/access_token
userAuthorizationUri: https://www.facebook.com/dialog/oauth
tokenName: oauth_token
authenticationScheme: query
registeredRedirectUri: http://localhost:8083/app.html
preEstablishedRedirectUri: http://localhost:8083/app.html
clientAuthenticationScheme: form
resource:
userInfoUri: https://graph.facebook.com/me
This is inspired from the example presented here: https://github.com/spring-guides/tut-spring-boot-oauth2/tree/master/github
You can achieve this using Spring Social or OAUTH2
If you want to do using spring social be aware that Google is not supported by default in spring boot social so you have to do a couple of extra steps.
Add Maven Dependencies
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-google</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
Add a GoogleAutoConfiguration Class
Do Ctrl+Shift+T in your IDE(eclipse) and look for FacebookAutoConfiguration class you should be able to find it either in org.springframework.boot.autoconfigure.social package in spring-autoconfigure.jar. Copy this File and replace Facebook with Google.
3.Add GoogleProperties
In the same package add the below class
#ConfigurationProperties(prefix = "spring.social.google")
public class GoogleProperties extends SocialProperties{
Update the application.properties with your google API key
Follow this link for complete description and step by step instruction
Hope It helps !!
If you want to do using OAUTH2 here is a working example

Spring boot + Spring LDAP + Service Account + Bad Credentials

i am getting bad credentials exception when using active directory service account and the same code is working fine for user account.
And there is nothing wrong with service user credentials.
Please find my code below.
#Configuration
protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(
"abc.def.ghi", "ldap://abc.def.ghi:389");
auth.authenticationProvider(provider);
}
}
The userPrincipleName property is not inline with expected format username#domainname for that specific user account.

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.

Resources