I have a situation where I would like to create an access token myself (so not through the usual process). I have come up with something like this:
#Inject
private DefaultTokenServices defaultTokenServices;
...
OAuth2Authentication auth = xxx;
OAuth2AccessToken token = defaultTokenServices.createAccessToken(auth);
The only problem is that I am not sure how to create the OAuth2Authentication (in my code the part with xxx). I have the user & client info and I know which Authorities I want to grant this token.
Here it is, your use case may differ slightly based on the flow you are using. This is what works for a password grant flow. There are a few custom class like token store, token enhancer ect. but that is really just extended versions of the spring classes modified for our own needs.
HashMap<String, String> authorizationParameters = new HashMap<String, String>();
authorizationParameters.put("scope", "read");
authorizationParameters.put("username", "mobile_client");
authorizationParameters.put("client_id", "mobile-client");
authorizationParameters.put("grant", "password");
DefaultAuthorizationRequest authorizationRequest = new DefaultAuthorizationRequest(authorizationParameters);
authorizationRequest.setApproved(true);
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_UNTRUSTED_CLIENT"));
authorizationRequest.setAuthorities(authorities);
HashSet<String> resourceIds = new HashSet<String>();
resourceIds.add("mobile-public");
authorizationRequest.setResourceIds(resourceIds);
// Create principal and auth token
User userPrincipal = new User(user.getUserID(), "", true, true, true, true, authorities);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userPrincipal, null, authorities) ;
OAuth2Authentication authenticationRequest = new OAuth2Authentication(authorizationRequest, authenticationToken);
authenticationRequest.setAuthenticated(true);
CustomTokenStore tokenStore = new CustomTokenStore();
// Token Enhancer
CustomTokenEnhancer tokenEnhancer = new CustomTokenEnhancer(user.getUserID());
CustomTokenServices tokenServices = new CustomTokenServices();
tokenServices.setTokenEnhancer(tokenEnhancer);
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(tokenStore);
OAuth2AccessToken accessToken = tokenServices.createAccessTokenForUser(authenticationRequest, user);
Here is how to generate a Token using the TokenEndpoint interface (used to expose REST service) :
#Inject
private TokenEndpoint tokenEndpoint;
public ResponseEntity<?> getToken(Principal principal) {
HashMap<String, String> parameters = new HashMap<String, String>();
parameters.put("client_id", "appid");
parameters.put("client_secret", "myOAuthSecret");
parameters.put("grant_type", "password");
parameters.put("password", myUser.getPassword());
parameters.put("scope", "read write");
parameters.put("username", myUser.getLogin());
return tokenEndpoint.getAccessToken(principal, parameters);
}
Other way, to manually generate an OAuth2 Accesss Token we can use an instance of TokenService
#Autowired
private AuthorizationServerEndpointsConfiguration configuration;
#Override
public String generateOAuth2AccessToken(User user, List<Role> roles, List<String> scopes) {
Map<String, String> requestParameters = new HashMap<String, String>();
Map<String, Serializable> extensionProperties = new HashMap<String, Serializable>();
boolean approved = true;
Set<String> responseTypes = new HashSet<String>();
responseTypes.add("code");
// Authorities
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for(Role role: roles)
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
OAuth2Request oauth2Request = new OAuth2Request(requestParameters, "clientIdTest", authorities, approved, new HashSet<String>(scopes), new HashSet<String>(Arrays.asList("resourceIdTest")), null, responseTypes, extensionProperties);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUsername(), "N/A", authorities);
OAuth2Authentication auth = new OAuth2Authentication(oauth2Request, authenticationToken);
AuthorizationServerTokenServices tokenService = configuration.getEndpointsConfigurer().getTokenServices();
OAuth2AccessToken token = tokenService.createAccessToken(auth);
return token.getValue();
}
I based my solution on Mop So's answer but instead of using:
return tokenEndpoint.getAccessToken(principal, parameters);
I used:
tokenEndpoint.postAccessToken(principal, parameters);
Why? Because if you use tokenEndpoint.getAccessToken(principal, parameters) the endpoing will throw you a HttpRequestMethodNotSupportedException because it has not been called with a GET method. At least, this is what happened to me with spring-security-oauth2-2.0.13.RELEASE
public OAuth2AccessToken getAccessToken() throws HttpRequestMethodNotSupportedException {
HashMap<String, String> parameters = new HashMap<>();
parameters.put("client_id", CLIENT_ID);
parameters.put("client_secret", CLIENT_SECRET);
parameters.put("grant_type", "client_credentials");
ClientDetails clientDetails = clientDetailsStore.get(CLIENT_ID);
// Create principal and auth token
User userPrincipal = new User(CLIENT_ID, CLIENT_SECRET, true, true, true, true, clientDetails.getAuthorities());
UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(userPrincipal, CLIENT_SECRET,
clientDetails.getAuthorities());
ResponseEntity<OAuth2AccessToken> accessToken = tokenEndpoint.postAccessToken(principal, parameters);
return accessToken.getBody();
}
This has worked for me:
#Override public OAuth2AccessToken getToken(String username, String password) {
HashMap<String, String> parameters = new HashMap<String, String>();
parameters.put("client_id", clientid);
parameters.put("grant_type", "password");
parameters.put("password", username);
parameters.put("scope", scope);
parameters.put("username", password);
AuthorizationRequest authorizationRequest = defaultOAuth2RequestFactory.createAuthorizationRequest(parameters);
authorizationRequest.setApproved(true);
OAuth2Request oauth2Request = defaultOAuth2RequestFactory.createOAuth2Request(authorizationRequest);
// Create principal and auth token
final UsernamePasswordAuthenticationToken loginToken = new UsernamePasswordAuthenticationToken(
username, password);
Authentication authentication = authenticationManager.authenticate(loginToken);
OAuth2Authentication authenticationRequest = new OAuth2Authentication(oauth2Request, authentication);
authenticationRequest.setAuthenticated(true);
OAuth2AccessToken accessToken = tokenServices.createAccessToken(authenticationRequest);
return accessToken;
}
In the Oauth2Configuration:
#Bean
DefaultOAuth2RequestFactory defaultOAuth2RequestFactory() {
return new DefaultOAuth2RequestFactory(clientDetailsService);
}
The rest of the Oauth2Configuration should look like in the article:
http://stytex.de/blog/2016/02/01/spring-cloud-security-with-oauth2/
Problem
I had problems with all the implementations listed here, so I finally managed to get my own with a stateless server, oauth2 and google social. Its just the last part of the tutorial that is missing here
The problem for me is that after executing the google oauth, I need to exchange a 10 second duration token for a long lived token. In order to do that I need to generate a JWT token and exchange it with a real access token generated by myself.
Implementation
#Service
class SocialTokenVerificationService {
#Autowired
private lateinit var jwsTokenService: JWSTokenService
#Autowired
private lateinit var clientDetailsService: ClientDetailsService
#Autowired
private lateinit var userService: UserService
#Autowired
private lateinit var tokenServices: DefaultTokenServices
#Autowired
private lateinit var tokenRequestFactory: OAuth2RequestFactory
fun verifyToken(token: String): OAuth2AccessToken? {
val claimSet = jwsTokenService.parseToken(token)
val userDetails = userService.loadUserByUsername(claimSet.subject)
val client = clientDetailsService.loadClientByClientId(DEFAULT_SERVER_CLIENT)
val parameters = HashMap<String, String>()
val authentication = UsernamePasswordAuthenticationToken(userDetails, null, userDetails.authorities)
return tokenServices.createAccessToken(OAuth2Authentication(
tokenRequestFactory.createOAuth2Request(client, TokenRequest(parameters, client.clientId, listOf("read", "write"), "password")),
authentication
))
}
}
JWSTokenService: its a self implemented class that encodes and decodes the exchanging token between google oauth and mine.
ClientDetailsService: bean declared as as part of the authorization server. Comes from my database
override fun configure(clients: ClientDetailsServiceConfigurer) {
clients.jdbc(datasource)
}
UserService: just a user service that extends UserDetailsService to obtain my users from the database
DefaultTokenServices: implemented as a primary bean as follows
#Bean
#Primary
fun tokenServices(): DefaultTokenServices {
val defaultTokenServices = DefaultTokenServices()
defaultTokenServices.setTokenStore(tokenStore())
defaultTokenServices.setSupportRefreshToken(true)
defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter())
return defaultTokenServices
}
OAuth2RequestFactory: implemented as a bean as follows
#Bean
fun oauthRequestFactory(clientsDetails: ClientDetailsService): OAuth2RequestFactory {
return DefaultOAuth2RequestFactory(clientsDetails)
}
With all this dependencies, what I need to do to generate a token that gets stored into the database and follows the same flows as the other ones without providing a password is:
Parse the jws token and verify its validity
Load the user that was authenticated with google
Generate an Authentication using the UsernamePasswordAuthenticationToken class. This is the key part, call DefaultTokenServices#createAccessToken to obtain a new token. It needs some arguments to execute the request:
OAuth2Request: it can be created with the OAuth2RequestFactory
The Authentication created previously
We need to generate a TokenRequest with the client that is triggering this token request. In my case I have that hardcoded
Summary
So to recap how to create a token manually:
We need to ask the token services to give us a token
For that we need to provide the authentication details and a client who does the request
With those 2 we can obtain a new token and serve it normally
In a spring boot 2.2.2 project I'm using the following code to do a pasword flow server side:
I had to specify authorizedClientManager.setContextAttributesMapper since PasswordOAuth2AuthorizedClientProvider is expecting specific attributes in the context. Hope that helps.
Config (application.yaml):
spring:
security:
oauth2:
client:
provider:
yourOauthProvider:
user-info-uri: ...
authorization-uri: ...
token-uri: ...
registration:
regId:
clientId: ...
clientSecret: ...
provider: yourOauthProvider
authorization-grant-type: password
redirect-uri-template: "{baseUrl}/login/oauth2/code/{registrationId}"
scope:
Wiring:
#Configuration
public class Oauth2ClientConfig {
#Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.password()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
authorizedClientManager.setContextAttributesMapper(r -> {
Map<String, Object> m = new HashMap<>();
m.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, r.getPrincipal().getPrincipal());
m.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, r.getPrincipal().getCredentials());
return m;
});
return authorizedClientManager;
}
}
Service:
class AuthService {
#Autowired
private OAuth2AuthorizedClientManager authorizedClientManager;
public OAuth2AccessToken authenticate(String user, String password) {
Authentication principal = new UsernamePasswordAuthenticationToken(
user,
password);
OAuth2AuthorizeRequest authorizeRequest =
OAuth2AuthorizeRequest.withClientRegistrationId("regId")
.principal(principal)
.build();
OAuth2AuthorizedClient authorizedClient =
this.authorizedClientManager.authorize(authorizeRequest);
return authorizedClient.getAccessToken();
}
}
Related
I am trying to connect RestApi created with SpringBoot to get access token from Keycloak.
This is the code I have:
Application.yml
keycloak:
realm: ${CLIENT_RELM_NAME:registerApiRealm}
auth-server-url: ${KEYCLOAK_URL_WITH_PATH:http://localhost:8080/auth}
ssl-required: external
#keycloak resource is the client ID
resource: ${KEYCLOAK_CLIENT_NAME:registerApiClienty}
#replace secret with your key
credentials:
secret: ${CLIENT_RELM_SECRET:12a658ea-b728-4f53-9948-492ef470363f}
#The line below will prevent redirect to login page
bearer-only: true
KeycloakServiceImpl.java
#Component
public class KeyCloakServiceImpl implements KeyCloakService {
private static final Logger log = LoggerFactory.getLogger(RegistrationController.class);
#Value("${keycloak.credentials.secret}")
private String SECRETKEY;
#Value("${keycloak.resource}")
private String CLIENTID;
#Value("${keycloak.auth-server-url}")
private String AUTHURL;
#Value("${keycloak.realm}")
private String REALM;
#Value("${admin.username}")
private String ADMIN_USERNAME;
#Value("${admin.password}")
private String ADMIN_PASSWORD;
#Autowired
RestTemplate restTemplate;
#Override
public TokenDto getToken(UserCredentials userCredentials) {
TokenDto responseToken = null;
try {
MultiValueMap<String, String> urlParameters = new LinkedMultiValueMap<>();
urlParameters.add("grant_type", "password");
urlParameters.add("client_id", CLIENTID);
urlParameters.add("username", userCredentials.getUsername());
urlParameters.add("password", userCredentials.getPassword());
urlParameters.add("client_secret", SECRETKEY);
responseToken = authenticate(urlParameters);
} catch (Exception e) {
e.printStackTrace();
}
return responseToken;
}
private TokenDto authenticate( MultiValueMap<String, String> urlParameters ) throws Exception {
TokenDto tokenDto = new TokenDto();
String uri = AUTHURL + "/realms/" + REALM + "/protocol/openid-connect/token";
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(urlParameters, httpHeaders);
ResponseEntity<Object> result = restTemplate.exchange(uri, HttpMethod.POST, request, Object.class);
log.info("{}", result);
log.info("{}", result.getBody());
LinkedHashMap<String, Object> map = (LinkedHashMap<String, Object>) result.getBody();
if (map != null) {
tokenDto.setAccess_token(map.get("access_token").toString());
tokenDto.setToken_type(map.get("token_type").toString());
tokenDto.setRefresh_token(map.get("refresh_token").toString());
tokenDto.setExpires_in(map.get("expires_in").toString());
tokenDto.setScope(map.get("scope").toString());
} else {
return null;
}
return tokenDto;
}
When I test it with Postaman by sending username and `password``
{
"username": "user",
"password": "useruser35"
}
I am getting the following error:
org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request: [{"error":"invalid_client","error_description":"Invalid client credentials"}]
I am not sure why I double-checked if my user is created and it is, I checked clientId and secret and everything seems fine.
What am I missing here, any advice appreciated.
Your code seems to be valid.
You might want to check out this manual to see if keycloak has been properly configured.
The password grant flow in your example is usually not the preferred approach for doing signons.
You can also retrieve the token via spring security, see this link. There are many examples on the internet of how to do oAuth2 with spring security.
The following code will fetch 20 devices and will consume some data from an online service.
In order to use the online service the WebClient need to get access token (authorization-grant-type=client_credentials)
spring.security.oauth2.client.registration.web.client-id=xxxx
spring.security.oauth2.client.registration.web.client-secret=xxxx
spring.security.oauth2.client.registration.web.scope=xxxx
spring.security.oauth2.client.registration.web.authorization-grant-type=client_credentials
spring.security.oauth2.client.provider.web.token-uri=https://xxxx
Config:
#Configuration
public class Config {
#Autowired
public ClientRegistrationRepository clientRegistrationRepository;
#Bean
public WebClient webClient(ExchangeFilterFunction getOAuth2FilterFunction) {
logger.info("** start webClient **");
return WebClient.builder().filter(getOAuth2FilterFunction).build();
}
#Bean
public ExchangeFilterFunction getOAuth2FilterFunction(ReactiveClientRegistrationRepository clientRegistrationRepository) {
logger.info("** start getOAuth2FilterFunction **");
InMemoryReactiveOAuth2AuthorizedClientService authorizedClientService = new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository);
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(new ClientCredentialsReactiveOAuth2AuthorizedClientProvider());
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2FilterFunction = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth2FilterFunction.setDefaultClientRegistrationId("web");
return oauth2FilterFunction;
}
#Bean
public ReactiveClientRegistrationRepository clientRegistrations() {
logger.info("** start clientRegistrations **");
ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId("web");
return new InMemoryReactiveClientRegistrationRepository(clientRegistration);
}
WebClient:
private void getData(List<Device> initlist) {
logger.info("** start getDeviceData **");
List<Mono<DeviceDto>> jsonDeviceList = initlist.stream()
.map(device -> webClient.post().uri(infoUri)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.body(Mono.just(device.getMacAddress()),String.class)
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("web"))
.retrieve()
.bodyToMono(DeviceDto.class))
.collect(Collectors.toList());
ObjectMapper mapper = new ObjectMapper();
Flux<DeviceDto> mergedMonos = Flux.fromIterable(jsonDeviceList).flatMapSequential(Function.identity());
mergedMonos.map(device -> mapper.valueToTree(device)).collectList().subscribe(list -> {
generateCsv(list);
});
}
The problem is that for each service request there will be an equivalent access token request from the authentication server. So for all 20 devices in the list the WebClient will request access token 20 times.
How can I change this to have only one call rather then 20 ?
Thank you
What #Toerktumlare said is right. If you want to call oauth server once, you just need to cache the access_token in memory or redis at first request and then use the same access_token before it is expired.
WebClient webClient = WebClient.builder()
.defaultHeader("Authorization", "Bearer " + getAccessToken())
.build();
private String getAccessToken() {
// get access_token from redis
// if expiring, it will return null
String access_token = (String) redisTemplate.opsForValue().get("access_token");
if (null != access_token) {
return access_token;
}
// get access_token from oauth server again and cache it into redis
return getAccessTokenFromOauthServer();
}
I'm trying to generate an access token from a custom corporate oauth 2 authorization server with Resource Owner Password Credentials Flow.
See https://www.rfc-editor.org/rfc/rfc6749#section-4.3
This server only generate an access token if receive the following parameters:
POST https://custom_corporate_server/auth/oauth/v2/token
Header
idp: 99
Body
grant_type: password
scope: my_scope
client_id: 00******-****-****-****-**********99
client_secret: 00******-****-****-****-**********99
username: my_user
password: my_password
Their configuration requires additional header custom parameter: idp - should be a numeric.
I'm using Spring Boot 2.3.0 and Spring Security 5.3.2.
I followed the link bellow to build my test example:
https://docs.spring.io/spring-security/site/docs/5.3.2.RELEASE/reference/html5/#using-the-access-token-2
#Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());
return authorizedClientManager;
}
private Function<OAuth2AuthorizeRequest, Map<String, Object>> contextAttributesMapper() {
return authorizeRequest -> {
Map<String, Object> contextAttributes = Collections.emptyMap();
HttpServletRequest servletRequest = authorizeRequest.getAttribute(HttpServletRequest.class.getName());
String username = servletRequest.getParameter(OAuth2ParameterNames.USERNAME);
String password = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD);
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
contextAttributes = new HashMap<>();
// `PasswordOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, username);
contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, password);
}
return contextAttributes;
};
}
I was unable to pass this parameter in the header to the authorization server. How to do this is my main dilemma today.
Have look at this article, it explains all kinds of customizations to authorization and token requests. In your case, the section about token request extra parameters, seems to describe exactly what you need.
You could do something like this:
public class CustomRequestEntityConverter implements Converter<OAuth2PasswordGrantRequest, RequestEntity<?>> {
private OAuth2PasswordGrantRequestEntityConverter defaultConverter;
public CustomRequestEntityConverter() {
defaultConverter = new OAuth2PasswordGrantRequestEntityConverter();
}
#Override
public RequestEntity<?> convert(OAuth2PasswordGrantRequest req) {
RequestEntity<?> entity = defaultConverter.convert(req);
MultiValueMap<String, String> params = entity.getHeaders();
params.add("idp", "99");
return new RequestEntity<>(params, entity.getHeaders(), entity.getMethod(), entity.getUrl());
}
}
I realize LDAP authentication by Spring. In my case, I use ActiveDirectoryLdapAuthenticationProvider.
It looks like here:
private Authentication authenticate(String username, String password, HelpDescUser userDetails) {
String url = "ldap://" + ldapHost + ":" + port + "/";
ActiveDirectoryLdapAuthenticationProvider ldapProvider =
new ActiveDirectoryLdapAuthenticationProvider(domain, url, rootDn);
String filterWithName = String.format(filter, username);
ldapProvider.setSearchFilter(filterWithName);
ldapProvider.setContextEnvironmentProperties(createProperties(username, password));
ldapProvider.setConvertSubErrorCodesToExceptions(true);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, password);
Authentication authenticate;
try {
authenticate = ldapProvider.authenticate(authentication);
} catch (Exception e) {
throw new BadCredentialsException("Пользователь не авторизован (сервер LDAP не подтвердил авторизацию).");
}
if (Objects.nonNull(authenticate) && authenticate.isAuthenticated()) {
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
} else {
throw new BadCredentialsException("Пользователь не авторизован (сервер LDAP не подтвердил авторизацию).");
}
}
private Map<String, Object> createProperties(String username, String password) {
Map<String, Object> properties = new HashMap<>();
properties.put(Context.SECURITY_PRINCIPAL, username);
properties.put(Context.SECURITY_CREDENTIALS, password);
return properties;
}
I have a problem.
As I understand authentication schema, when we authenticate by user, we also need to have a technical account. We bind by technical account & than sending user login & password, & after that, we receive answer. But in this schema, we bind with the same user to authenticate, & it's wrong - this user may have no rights to bind.
Please, show me working solution to authenticate with Spring ActiveDirectoryLdapAuthenticationProvider?
When you declare ActiveDirectoryLdapAuthenticationProvider bean, you can use setContextEnvironmentProperties() method.
In example:
#Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(null, ldapUrls, ldapBase);
setContextEnvironmentProperties(provider);
return provider;
}
private void setContextEnvironmentProperties(ActiveDirectoryLdapAuthenticationProvider provider) {
Map<String, Object> contextEnvironmentProperties = new HashMap<>();
if (StringUtils.isNotEmpty(ldapUsername)) {
contextEnvironmentProperties.put(Context.SECURITY_PRINCIPAL, ldapUsername);
}
if (StringUtils.isNotEmpty(ldapPassword)) {
contextEnvironmentProperties.put(Context.SECURITY_CREDENTIALS, ldapPassword);
}
if (!contextEnvironmentProperties.isEmpty()) {
provider.setContextEnvironmentProperties(contextEnvironmentProperties);
}
}
I try to implement auth through AWS Cognito using aws-java-sdk-cognitoidentity and for convenience use cognitoauth classes
Authentication works fine but when I get AuthenticationResultType from respondToAuthChallengeResult it return null why that happens?
Sample:
AWSCryptoSettings cryptoParams = new AWSCryptoSettings();
AWSCognitoSession clientSession = new AWSCognitoSession(
cryptoParams, "test", "123456", USER_POOL_ID);
AWSCognitoIdentityProvider provider = AWSCognitoIdentityProviderClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials()))
.withRegion(Regions.EU_WEST_1)
.build();
InitiateAuthRequest authRequest = new InitiateAuthRequest()
.withAuthFlow(AuthFlowType.USER_SRP_AUTH)
.withClientId(CLIENT_APP_ID)
.withAuthParameters(clientSession.step1()); //step1() return Map<String,String> with parameters for auth in it
//Respond to authentication challenge
InitiateAuthResult authResult = provider.initiateAuth(authRequest);
Map<String, String> params = authResult.getChallengeParameters();
Map<String, String> srpAuthResponses = clientSession.step2(params); //step2() return also Map<String, String> with formatted parameters.
RespondToAuthChallengeRequest respondToAuthChallengeRequest = new RespondToAuthChallengeRequest()
.withChallengeName(authResult.getChallengeName())
.withClientId(CLIENT_APP_ID)
.withChallengeResponses(srpAuthResponses);
RespondToAuthChallengeResult respondToAuthChallengeResult = provider.respondToAuthChallenge(respondToAuthChallengeRequest);
//debug
System.out.println(respondToAuthChallengeResult.getChallengeName());
System.out.println(respondToAuthChallengeResult.getChallengeParameters());
System.out.println(respondToAuthChallengeResult.getAuthenticationResult());
AuthenticationResultType authenticationResultType = respondToAuthChallengeResult.getAuthenticationResult(); //there null is retruned;
Output from sout is:
NEW_PASSWORD_REQUIRED
{userAttributes={"email":"username123#example.com"}, requiredAttributes=[]}
null
I don't configure correctly user pool or something is wrong in code?
Thanks.
This seems like you have created the user through the console or through the AdminCreateUser API. The user needs to create a new password as the state says.