Spring LDAP unable authenticate user at mutlitple levels - spring-boot

Config
#Bean
public LdapContextSource contextSource() {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrls("ldap://myUrl:389/");
contextSource.setBase("DC=company,DC=com");
contextSource.setUserDn("CN=myAdmin,CN=Users,DC=company,DC=com");
contextSource.setPassword("password");
contextSource.setReferral("follow");
contextSource.afterPropertiesSet();
return contextSource;
}
#Bean
public LdapTemplate ldapTemplate(LdapContextSource contextSource) {
return new LdapTemplate(contextSource);
}
controller + service
#Autowired
private LdapTemplate ldapTemplate;
private static final String base = "OU=myTeam";
#PostMapping("/login")
public ResponseEntity<?> login(#RequestBody LoginRequest loginRequest) {
EqualsFilter ef = new EqualsFilter("sAMAccountName", loginRequest.getUsername());
boolean authenticated = ldapTemplate.authenticate(base, ef.encode(), loginRequest.getPassword());
// ----
}
For base = "OU=myTeam", Only Test 1 is able to log in but not the remaining users (Test 2, Test 3,Test 4 and Test 5)
I have tried changing the base to "OU=Users,OU=myTeam" not working for any user.
AND for base="CN=Users" (right tree & default group in LDAP) still not working for any user.
AND base="", empty base throwing error.
mvn dependencies
org.springframework.boot:spring-boot-starter:2.7.x
org.springframework.ldap:spring-ldap-core:2.4.x
org.springframework.boot:spring-boot-starter-data-ldap:2.7.x

Related

Twitter Sign in using Spring Boot

I am trying to sign in to my web application (developed using Spring Boot) using social logins. The logins for Google & facebook are okay. But the for some reason there is a token issue in the twitter login. I have created the project in the twitter developer site obtained all the credentials. Please refer to my code below.
My Property file values are mentioned below.
twitter.client.client-id=XXXXXXX
twitter.client.client-secret=XXXXXXXX
twitter.client.access-token-uri=https://api.twitter.com/oauth/access_token
twitter.client.user-authorization-uri=https://api.twitter.com/oauth/authorize
twitter.client.token-name=oauth_token
twitter.client.authentication-scheme=form
twitter.resource.user-info-uri=https://api.twitter.com/1.1/account/verify_credentials.json
The filter method
private Filter ssoTwitterFilter(String processingUrl, PrincipalExtractor principalExtractor) {
OAuth2ClientAuthenticationProcessingFilter twitterFilter = new OAuth2ClientAuthenticationProcessingFilter(
processingUrl);
LOGGER.debug("processingUrl :{} ", processingUrl);
twitterFilter.setAuthenticationSuccessHandler(authenticationSuccessHandlerAndRegistrationFilter());
OAuth2RestTemplate twitterTemplate = new OAuth2RestTemplate(twitter(), oauth2ClientContext);
twitterFilter.setRestTemplate(twitterTemplate);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(twitterResource().getUserInfoUri(),
twitter().getClientId());
tokenServices.setRestTemplate(twitterTemplate);
tokenServices.setPrincipalExtractor(principalExtractor);
return twitterFilter;
}
These are the bean configurations.
#Bean
#ConfigurationProperties("twitter.client")
public AuthorizationCodeResourceDetails twitter() {
return new AuthorizationCodeResourceDetails();
}
#Bean
#ConfigurationProperties("twitter.resource")
public ResourceServerProperties twitterResource() {
return new ResourceServerProperties();
}
This is the error that I get
enter image description here
Please can anyone shed some light on this. Because all the samples I found were related getting profile information from twitter where as i need a sample for sign in using spring Boot. Thanks in advance
You can configure Twitter login like this:
#Configuration
#EnableSocial
public class SocialConfig implements SocialConfigurer {
#Autowired
private UserAuthorizationService userAuthorizationService;
#Override
public void addConnectionFactories(ConnectionFactoryConfigurer cfConfig, Environment env) {
cfConfig.addConnectionFactory(new TwitterConnectionFactory(
env.getProperty("twitter.consumer-key"),
env.getProperty("twitter.consumer-secret")
));
}
#Override
public UserIdSource getUserIdSource() {
return new UserIdSource() {
#Override
public String getUserId() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
}
return authentication.getName();
}
};
}
#Override
public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
InMemoryUsersConnectionRepository usersConnectionRepository = new InMemoryUsersConnectionRepository(
connectionFactoryLocator
);
return usersConnectionRepository;
}
#Autowired
private TwitterConnectionSignup twitterConnectionSignup;
#Autowired
private ConnectionFactoryLocator connectionFactoryLocator;
#Autowired
private UsersConnectionRepository usersConnectionRepository;
#Bean
public ProviderSignInController providerSignInController() {
((InMemoryUsersConnectionRepository) usersConnectionRepository)
.setConnectionSignUp(twitterConnectionSignup);
return new ProviderSignInController(
connectionFactoryLocator,
usersConnectionRepository,
new TwitterSignInAdapter(userAuthorizationService));
}
}
Configure TwitterConnectionSignup:
#Service
public class TwitterConnectionSignup implements ConnectionSignUp {
#Autowired
private UserRepo userRepo;
#Override
public String execute(Connection<?> connection) {
//add your logic to save user to your db
return connection.getDisplayName();
}
}
Now configure TwitterSignInAdapter:
public class TwitterSignInAdapter implements SignInAdapter {
private UserAuthorizationService userAuthorizationService;
public TwitterSignInAdapter(UserAuthorizationService userAuthorizationService) {
this.userAuthorizationService = userAuthorizationService;
}
#Override
public String signIn(String localUserId, Connection<?> connection, NativeWebRequest webRequest) {
log.debug(" Email {}", localUserId);
UserAuthDto userAuthDto = (UserAuthDto) userAuthorizationService.loadUserByUsername(localUserId);
UsernamePasswordAuthenticationToken updatedAuth = new UsernamePasswordAuthenticationToken(userAuthDto, userAuthDto.getSocialId(),
userAuthDto.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(updatedAuth);
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
// add authentication to the session
servletRequest.getSession().setAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
SecurityContextHolder.getContext());
return "/";
}
}

Spring Boot OAuth2 manually create new JWT token

At my Spring Boot application I have configured Spring OAuth2 server with JWT tokens.
Also I have added Spring Social configuration in order to be able authenticate users via various Social Networks like Twitter, Facebook and so on.
This is my SpringSocial config:
#Configuration
#EnableSocial
public class SocialConfig extends SocialConfigurerAdapter {
#Bean
public ProviderSignInController providerSignInController(ConnectionFactoryLocator connectionFactoryLocator, UsersConnectionRepository usersConnectionRepository) {
return new ProviderSignInController(connectionFactoryLocator, usersConnectionRepository, new SimpleSignInAdapter(authTokenServices, "client_id", userService));
}
...
}
Also, based on the folksinging answer Integrate Spring Security OAuth2 and Spring Social I have implemented SimpleSignInAdapter in order to handle successful authentication with 3rdparty Social Networks:
public class SimpleSignInAdapter implements SignInAdapter {
final static Logger logger = LoggerFactory.getLogger(SimpleSignInAdapter.class);
public static final String REDIRECT_PATH_BASE = "/#/login";
public static final String FIELD_TOKEN = "access_token";
public static final String FIELD_EXPIRATION_SECS = "expires_in";
private final AuthorizationServerTokenServices authTokenServices;
private final String localClientId;
private final UserService userService;
public SimpleSignInAdapter(AuthorizationServerTokenServices authTokenServices, String localClientId, UserService userService){
this.authTokenServices = authTokenServices;
this.localClientId = localClientId;
this.userService = userService;
}
#Override
public String signIn(String userId, Connection<?> connection, NativeWebRequest request) {
UserDetails userDetails = loadUserById(Long.parseLong(userId));
OAuth2AccessToken oauth2Token = authTokenServices.createAccessToken(convertAuthentication(userDetails));
String redirectUrl = new StringBuilder(REDIRECT_PATH_BASE)
.append("?").append(FIELD_TOKEN).append("=")
.append(encode(oauth2Token.getValue()))
.append("&").append(FIELD_EXPIRATION_SECS).append("=")
.append(oauth2Token.getExpiresIn())
.toString();
return redirectUrl;
}
private OAuth2Authentication convertAuthentication(UserDetails userDetails) {
OAuth2Request request = new OAuth2Request(null, localClientId, null, true, null, null, null, null, null);
return new OAuth2Authentication(request, new UsernamePasswordAuthenticationToken(userDetails, "N/A", userDetails.getAuthorities()));
}
private String encode(String in) {
String res = in;
try {
res = UriUtils.encode(in, "UTF-8");
} catch(UnsupportedEncodingException e){
logger.error("ERROR: unsupported encoding: " + "UTF-8", e);
}
return res;
}
public UserDetails loadUserById(Long id) throws UsernameNotFoundException {
User user = userService.findUserById(id);
if (user == null) {
throw new UsernameNotFoundException("User " + id + " not found.");
}
Set<Permission> permissions = userService.getUserPermissions(user);
return new DBUserDetails(user, permissions);
}
}
Everything works fine except one thing - the following line of code produces plain OAuth2 access token:
OAuth2AccessToken oauth2Token = authTokenServices.createAccessToken(convertAuthentication(userDetails));
but I need to create JWT token instead.
How to create or convert this token to JWT based ? I suppose I can use JwtAccessTokenConverter class for this purpose but don't know how at this moment.
This worked for me, after i wanted my own Custom JWT token.
DefaultTokenServices service = new DefaultTokenServices();
service.setTokenStore(jwtAccessTokenConverter);
service.setTokenEnhancer(jwtAccessTokenConverter);
OAuth2AccessToken token = service.createAccessToken(authentication);
Autowire the jwtAccessTokenConverter
#Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
After debugging I have found a solution:
private final TokenEnhancer tokenEnhancer;
...
OAuth2Authentication authentication = convertAuthentication(userDetails);
OAuth2AccessToken accessToken = authTokenServices.createAccessToken(authentication);
accessToken = tokenEnhancer.enhance(accessToken, authentication);

How to use OAuth2RestTemplate?

I'm trying to understand how to use a OAuth2RestTemplate object to consume my OAuth2 secured REST service (which is running under a different project and let's assume also on a different server etc...)
An example of my REST service is:
http://localhost:8082/app/helloworld
-> Accessing this URL generates an error as I am not authenticated
To request a token I would go to:
http://localhost:8082/app/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=**USERNAME**&password=**PASSWORD**
After I receive the token I can then connect to the REST API by using the following URL (example token inserted)
http://localhost:8082/app/helloworld/?access_token=**4855f557-c6ee-43b7-8617-c24591965206**
Now my question is how do I implement a second application which can consume this OAuth2 secured REST API? I really haven't found any working examples where you provide the user name and password (e.g. coming from a login form) and then a token is generated which can be re-used to get data from the REST API.
I currently tried something with the following objects:
BaseOAuth2ProtectedResourceDetails baseOAuth2ProtectedResourceDetails = new BaseOAuth2ProtectedResourceDetails();
baseOAuth2ProtectedResourceDetails.setClientId("restapp");
baseOAuth2ProtectedResourceDetails.setClientSecret("restapp");
baseOAuth2ProtectedResourceDetails.setGrantType("password");
// how to set user name and password ???
DefaultAccessTokenRequest accessTokenRequest = new DefaultAccessTokenRequest();
OAuth2ClientContext oAuth2ClientContext = new DefaultOAuth2ClientContext(accessTokenRequest());
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(baseOAuth2ProtectedResourceDetails,oAuth2ClientContext);
But this just isn't working :(
Any ideas, links to working examples or tutorials are greatly appreciated.
You can find examples for writing OAuth clients here:
https://github.com/spring-projects/spring-security-oauth
In your case you can't just use default or base classes for everything, you have a multiple classes Implementing OAuth2ProtectedResourceDetails. The configuration depends of how you configured your OAuth service but assuming from your curl connections I would recommend:
#EnableOAuth2Client
#Configuration
class MyConfig{
#Value("${oauth.resource:http://localhost:8082}")
private String baseUrl;
#Value("${oauth.authorize:http://localhost:8082/oauth/authorize}")
private String authorizeUrl;
#Value("${oauth.token:http://localhost:8082/oauth/token}")
private String tokenUrl;
#Bean
protected OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource;
resource = new ResourceOwnerPasswordResourceDetails();
List scopes = new ArrayList<String>(2);
scopes.add("write");
scopes.add("read");
resource.setAccessTokenUri(tokenUrl);
resource.setClientId("restapp");
resource.setClientSecret("restapp");
resource.setGrantType("password");
resource.setScope(scopes);
resource.setUsername("**USERNAME**");
resource.setPassword("**PASSWORD**");
return resource;
}
#Bean
public OAuth2RestOperations restTemplate() {
AccessTokenRequest atr = new DefaultAccessTokenRequest();
return new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(atr));
}
}
#Service
#SuppressWarnings("unchecked")
class MyService {
#Autowired
private OAuth2RestOperations restTemplate;
public MyService() {
restTemplate.getAccessToken();
}
}
Do not forget about #EnableOAuth2Client on your config class, also I would suggest to try that the urls you are using are working with curl first, also try to trace it with the debugger because lot of exceptions are just consumed and never printed out due security reasons, so it gets little hard to find where the issue is. You should use logger with debug enabled set.
Good luck
I uploaded sample springboot app on github https://github.com/mariubog/oauth-client-sample
to depict your situation because I could not find any samples for your scenario .
In the answer from #mariubog (https://stackoverflow.com/a/27882337/1279002) I was using password grant types too as in the example but needed to set the client authentication scheme to form. Scopes were not supported by the endpoint for password and there was no need to set the grant type as the ResourceOwnerPasswordResourceDetails object sets this itself in the constructor.
...
public ResourceOwnerPasswordResourceDetails() {
setGrantType("password");
}
...
The key thing for me was the client_id and client_secret were not being added to the form object to post in the body if resource.setClientAuthenticationScheme(AuthenticationScheme.form); was not set.
See the switch in:
org.springframework.security.oauth2.client.token.auth.DefaultClientAuthenticationHandler.authenticateTokenRequest()
Finally, when connecting to Salesforce endpoint the password token needed to be appended to the password.
#EnableOAuth2Client
#Configuration
class MyConfig {
#Value("${security.oauth2.client.access-token-uri}")
private String tokenUrl;
#Value("${security.oauth2.client.client-id}")
private String clientId;
#Value("${security.oauth2.client.client-secret}")
private String clientSecret;
#Value("${security.oauth2.client.password-token}")
private String passwordToken;
#Value("${security.user.name}")
private String username;
#Value("${security.user.password}")
private String password;
#Bean
protected OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
resource.setAccessTokenUri(tokenUrl);
resource.setClientId(clientId);
resource.setClientSecret(clientSecret);
resource.setClientAuthenticationScheme(AuthenticationScheme.form);
resource.setUsername(username);
resource.setPassword(password + passwordToken);
return resource;
}
#Bean
public OAuth2RestOperations restTemplate() {
return new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
}
}
#Service
#SuppressWarnings("unchecked")
class MyService {
#Autowired
private OAuth2RestOperations restTemplate;
public MyService() {
restTemplate.getAccessToken();
}
}
I have different approach if you want access token and make call to other resource system with access token in header
Spring Security comes with automatic security: oauth2 properties access from application.yml file for every request and every request has SESSIONID which it reads and pull user info via Principal, so you need to make sure inject Principal in OAuthUser and get accessToken and make call to resource server
This is your application.yml, change according to your auth server:
security:
oauth2:
client:
clientId: 233668646673605
clientSecret: 33b17e044ee6a4fa383f46ec6e28ea1d
accessTokenUri: https://graph.facebook.com/oauth/access_token
userAuthorizationUri: https://www.facebook.com/dialog/oauth
tokenName: oauth_token
authenticationScheme: query
clientAuthenticationScheme: form
resource:
userInfoUri: https://graph.facebook.com/me
#Component
public class OAuthUser implements Serializable {
private static final long serialVersionUID = 1L;
private String authority;
#JsonIgnore
private String clientId;
#JsonIgnore
private String grantType;
private boolean isAuthenticated;
private Map<String, Object> userDetail = new LinkedHashMap<String, Object>();
#JsonIgnore
private String sessionId;
#JsonIgnore
private String tokenType;
#JsonIgnore
private String accessToken;
#JsonIgnore
private Principal principal;
public void setOAuthUser(Principal principal) {
this.principal = principal;
init();
}
public Principal getPrincipal() {
return principal;
}
private void init() {
if (principal != null) {
OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) principal;
if (oAuth2Authentication != null) {
for (GrantedAuthority ga : oAuth2Authentication.getAuthorities()) {
setAuthority(ga.getAuthority());
}
setClientId(oAuth2Authentication.getOAuth2Request().getClientId());
setGrantType(oAuth2Authentication.getOAuth2Request().getGrantType());
setAuthenticated(oAuth2Authentication.getUserAuthentication().isAuthenticated());
OAuth2AuthenticationDetails oAuth2AuthenticationDetails = (OAuth2AuthenticationDetails) oAuth2Authentication
.getDetails();
if (oAuth2AuthenticationDetails != null) {
setSessionId(oAuth2AuthenticationDetails.getSessionId());
setTokenType(oAuth2AuthenticationDetails.getTokenType());
// This is what you will be looking for
setAccessToken(oAuth2AuthenticationDetails.getTokenValue());
}
// This detail is more related to Logged-in User
UsernamePasswordAuthenticationToken userAuthenticationToken = (UsernamePasswordAuthenticationToken) oAuth2Authentication.getUserAuthentication();
if (userAuthenticationToken != null) {
LinkedHashMap<String, Object> detailMap = (LinkedHashMap<String, Object>) userAuthenticationToken.getDetails();
if (detailMap != null) {
for (Map.Entry<String, Object> mapEntry : detailMap.entrySet()) {
//System.out.println("#### detail Key = " + mapEntry.getKey());
//System.out.println("#### detail Value = " + mapEntry.getValue());
getUserDetail().put(mapEntry.getKey(), mapEntry.getValue());
}
}
}
}
}
}
public String getAuthority() {
return authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getGrantType() {
return grantType;
}
public void setGrantType(String grantType) {
this.grantType = grantType;
}
public boolean isAuthenticated() {
return isAuthenticated;
}
public void setAuthenticated(boolean isAuthenticated) {
this.isAuthenticated = isAuthenticated;
}
public Map<String, Object> getUserDetail() {
return userDetail;
}
public void setUserDetail(Map<String, Object> userDetail) {
this.userDetail = userDetail;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public String getTokenType() {
return tokenType;
}
public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
#Override
public String toString() {
return "OAuthUser [clientId=" + clientId + ", grantType=" + grantType + ", isAuthenticated=" + isAuthenticated
+ ", userDetail=" + userDetail + ", sessionId=" + sessionId + ", tokenType="
+ tokenType + ", accessToken= " + accessToken + " ]";
}
#RestController
public class YourController {
#Autowired
OAuthUser oAuthUser;
// In case if you want to see Profile of user then you this
#RequestMapping(value = "/profile", produces = MediaType.APPLICATION_JSON_VALUE)
public OAuthUser user(Principal principal) {
oAuthUser.setOAuthUser(principal);
// System.out.println("#### Inside user() - oAuthUser.toString() = " + oAuthUser.toString());
return oAuthUser;
}
#RequestMapping(value = "/createOrder",
method = RequestMethod.POST,
headers = {"Content-type=application/json"},
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public FinalOrderDetail createOrder(#RequestBody CreateOrder createOrder) {
return postCreateOrder_restTemplate(createOrder, oAuthUser).getBody();
}
private ResponseEntity<String> postCreateOrder_restTemplate(CreateOrder createOrder, OAuthUser oAuthUser) {
String url_POST = "your post url goes here";
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("Authorization", String.format("%s %s", oAuthUser.getTokenType(), oAuthUser.getAccessToken()));
headers.add("Content-Type", "application/json");
RestTemplate restTemplate = new RestTemplate();
//restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpEntity<String> request = new HttpEntity<String>(createOrder, headers);
ResponseEntity<String> result = restTemplate.exchange(url_POST, HttpMethod.POST, request, String.class);
System.out.println("#### post response = " + result);
return result;
}
}
My simple solution. IMHO it's the cleanest.
First create a application.yml
spring.main.allow-bean-definition-overriding: true
security:
oauth2:
client:
clientId: XXX
clientSecret: XXX
accessTokenUri: XXX
tokenName: access_token
grant-type: client_credentials
Create the main class: Main
#SpringBootApplication
#EnableOAuth2Client
public class Main extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll();
}
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
#Bean
public OAuth2RestTemplate oauth2RestTemplate(ClientCredentialsResourceDetails details) {
return new OAuth2RestTemplate(details);
}
}
Then Create the controller class: Controller
#RestController
class OfferController {
#Autowired
private OAuth2RestOperations restOperations;
#RequestMapping(value = "/<your url>"
, method = RequestMethod.GET
, produces = "application/json")
public String foo() {
ResponseEntity<String> responseEntity = restOperations.getForEntity(<the url you want to call on the server>, String.class);
return responseEntity.getBody();
}
}
Maven dependencies
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
</dependencies>

Spring LDAP - Creation of LdapTemplate in standalone java program - Using Spring LDAP as CDI Resource

I am trying to construct a LdapTemplate object of using spring data.
public class LDAPTemplate {
public static void main(String[] args) {
LdapContextSource lcs = new LdapContextSource();
lcs.setUrl("ldap://localhost:389/");
lcs.setUserDn("cn=Manager, dc=example, dc=com");
lcs.setPassword("secret1");
lcs.setDirObjectFactory(DefaultDirObjectFactory.class);
LdapTemplate ldap = new LdapTemplate(lcs);
ldap.lookup("cn=aaa");
}
}
I wanted to know is that the right way to instantiate ldap template object. Because when I perform a lookup, it throws NPE.
I am trying to use LDAP Spring in CDI context without using spring at all. If you have pointers on that would be nice. Does Spring LDAP is dependent on spring?
LdapContextSource is InitializingBean so you need to call afterPropertiesSet...
And the JavaDoc:
When using implementations of this class outside of a Spring Context
it is necessary to call afterPropertiesSet() when all properties are
set, in order to finish up initialization.
Correct Code
public class LDAPTemplate {
public static void main(String[] args) {
LdapContextSource lcs = new LdapContextSource();
lcs.setUrl("ldap://localhost:389/");
lcs.setUserDn("cn=Manager, dc=example, dc=com");
lcs.setPassword("secret1");
lcs.setDirObjectFactory(DefaultDirObjectFactory.class);
lcs.afterPropertiesSet();
LdapTemplate ldap = new LdapTemplate(lcs);
ldap.lookup("cn=aaa");
}
}
Solution: To Use Spring LDAP in CDI conte without using Spring IoC
Create a resource producer for LDAP template.
public class Resources {
private LdapTemplate template;
#Produces
//It is a custom qualifier
#CustomeLDAPTemplate
public LdapTemplate getTemplate() {
LdapContextSource lcs = new LdapContextSource();
lcs.setUrl("ldap://localhost:389/");
lcs.setUserDn("cn=Manager, dc=example, dc=com");
lcs.setPassword("secret1");
lcs.setDirObjectFactory(DefaultDirObjectFactory.class);
lcs.afterPropertiesSet();
template = new LdapTemplate(lcs);
return template;
}
public void setTemplate(LdapTemplate template) {
this.template = template;
}
}
Create a custom qualifier - To say I want tempate object of LdapTemplate and CustomeLDAPTemplate type
#Qualifier
#Retention(RUNTIME)
#Target({TYPE,CONSTRUCTOR, METHOD, FIELD})
public #interface CustomeLDAPTemplate {}
Implementation on - I used a JAX-WS class to verify.
#Path("/users")
#RequestScoped
public class UserResource {
#Inject
#CustomeLDAPTemplate
private LdapTemplate template;
#POST
#Consumes(MediaType.APPLICATION_XML)
public Response createUser(InputStream is){
User user = readStream(is);
System.out.println("LDAP Look up " + template.lookup("cn=aaa,ou=Org1, dc=example, dc=com").toString());
uRepo.save(user);
return Response.created(URI.create("/users/" + user.getUser_id())).build();
}
}
/**
* contextSource
* #return
*/
#Bean
public LdapContextSource contextSource() {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(properties.getProperty("ldap.url"));
contextSource.setBase(properties.getProperty("ldap.base.dn"));
contextSource.setUserDn(properties.getProperty("ldap.principal"));
contextSource.setPassword(properties.getProperty("ldap.password"));
contextSource.setReferral("ignore");
return contextSource;
}
/**
* Create Ldap Templelate Instance
* #return
*/
#Bean
public LdapTemplate ldapTemplate() {
LdapTemplate ldapTemplate = new LdapTemplate();
try {
ldapTemplate = new LdapTemplate(contextSource());
} catch (Exception e) {
log.error("error while creating LDap Template", e);
}
return ldapTemplate;
}
/**
* this Method check if the username and password are valid
* then return either true if exists and false if not
* #param username
* #param password
* #return
*/
public Boolean authenticateUser(final String username, final String password) {
boolean auth = false;
LdapTemplate ldapTemplate = new LdapTemplate(contextSource());
try {
ldapTemplate.setIgnorePartialResultException(true);
log.info("ldapTemplate-->" + ldapTemplate);
final AndFilter filter = new AndFilter().and(new EqualsFilter("objectclass", OBJECT_CLASS)).and(new EqualsFilter(NETWORK_USER_ENTITY, username));
auth = ldapTemplate.authenticate(BASE_DN, filter.encode(), password);
log.info("is Valid user :" + auth);
} catch (Exception e) {
log.error("error while creating LDap Template", e);
}
return auth;
}

Creating cron job to fetching twitter posts from user's wall using spring-social

I'm trying to create a cron job, which should fetch logged user's tweets.
I'm trying to do it like this:
public class MessagesSaver {
private static final Logger logger = LoggerFactory
.getLogger(MessagesSaver.class);
private static String TWITTER_NETWORK = "twitter";
private static String FACEBOOK_NETWORK = "facebook";
private static int MAX_TWEET_COUNT_PER_PAGE = 50;
#Autowired
private MessageRepository messageRepository;
#Autowired
private Twitter twitter;
#Scheduled(cron = "0 30 * * * *")
public void getMessagesFromSocialNetworks() {
if (twitter != null) {
List<Tweet> tweets = twitter.timelineOperations().getUserTimeline(
MAX_TWEET_COUNT_PER_PAGE);
parseAndSaveTwitterPosts(tweets);
}
}
}
and SocialConfig :
#Configuration
#EnableSocial
public class SocialConfig implements SocialConfigurer {
#Inject
private DataSource dataSource;
//
// SocialConfigurer implementation methods
//
#Override
public void addConnectionFactories(ConnectionFactoryConfigurer cfConfig,
Environment env) {
cfConfig.addConnectionFactory(new TwitterConnectionFactory(env
.getProperty("twitter.consumerKey"), env
.getProperty("twitter.consumerSecret")));
}
#Override
public UserIdSource getUserIdSource() {
return new UserIdSource() {
#Override
public String getUserId() {
return "admin";
}
};
}
#Override
public UsersConnectionRepository getUsersConnectionRepository(
ConnectionFactoryLocator connectionFactoryLocator) {
return new JdbcUsersConnectionRepository(dataSource,
connectionFactoryLocator, Encryptors.noOpText());
}
#Bean
#Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public Twitter twitter(ConnectionRepository repository) {
Connection<Twitter> connection = repository
.findPrimaryConnection(Twitter.class);
return connection != null ? connection.getApi() : null;
}
//
// Web Controller and Filter Beans
//
#Bean
public ConnectController connectController(
ConnectionFactoryLocator connectionFactoryLocator,
ConnectionRepository connectionRepository) {
ConnectController connectController = new ConnectController(
connectionFactoryLocator, connectionRepository);
return connectController;
}
#Bean
public ProviderSignInController providerSignInController(
ConnectionFactoryLocator connectionFactoryLocator,
UsersConnectionRepository usersConnectionRepository) {
return new ProviderSignInController(connectionFactoryLocator,
usersConnectionRepository, new SimpleSignInAdapter(
new HttpSessionRequestCache()));
}
#Bean
public DisconnectController disconnectController(
UsersConnectionRepository usersConnectionRepository, Environment env) {
return new DisconnectController(usersConnectionRepository,
env.getProperty("facebook.clientSecret"));
}
#Bean
public ReconnectFilter apiExceptionHandler(
UsersConnectionRepository usersConnectionRepository,
UserIdSource userIdSource) {
return new ReconnectFilter(usersConnectionRepository, userIdSource);
}
}
But of course it doesn't work, because twitter connection live in the request scope(
How i can configure this job?
The logged in user is associated with a web session, so there's no problem obtaining a request-scoped Twitter object at the web level of your app.
However, scheduled/cron jobs operate independent of the web layer of your application. They have no concept of "logged in user", as they are simply background beans, similar to services or DAOs in that they have no concept of who the current user is. From the perspective of MessagesSaver, who is the logged in user? There could easily be many logged in users. Which one is it expected to work on behalf of?
You could inject a UsersConnectionRepository into MessagesSaver, use it to obtain a ConnectionRepository for a specific user, then use that to obtain the Twitter connection (and from that, the Twitter API binding). The tricky bit is (again) who is the logged in user? There could be many...which one is MessagesSaver supposed to use?
Stepping away from what you've written here, what is it that your trying to accomplish? Maybe there's another way to do what you need.

Resources