Spring security: get password in UserDetailsServiceMethod












0














In order to get my account I have a external spring application that I need to login at. Why I need it is not important but in order to do a /login call on the API I need to get the password in the UserDetailsServiceMethod. Here is my security setup:



//https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;

//Constructor gets authLogic for external authentication
@Autowired
public WebSecurity(@Qualifier("authLogic") UserDetailsService userDetailsService){
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = new BCryptPasswordEncoder();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**", "/swagger-resources/configuration/ui", "/swagger-resources/configuration/security").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList(BANK_API, INVENTORY_API, MARKET_API)); //TODO: is dit correct??
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setExposedHeaders(Arrays.asList("X-Auth-Token","Authorization","Access-Control-Allow-Origin","Access-Control-Allow-Credentials"));

final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}


My UserDetailsServiceMethod implementation:



@Service
public class AuthLogic implements UserDetailsService {
private HttpServletRequest request;
private IAccountRepository accountRepository;
private RestCallLogic restCall;

@Autowired
public AuthLogic(HttpServletRequest request, IAccountRepository accountRepository, RestCallLogic restCall){
this.request = request;
this.accountRepository = accountRepository;
this.restCall = restCall;
}

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//get password
//make restcall to external login
}
}


Is there a way I can get the password while using the spring security implementation. Because I could easily make my own class and do the login from there but it would be nice to use Spring security for it. Also the login returns a token that I can reform to a User. Maybe i'm just overthinking...



In order to make a API call i needed to write a custom AuthenticationProvider:



@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

String username = authentication.getName();
String password = authentication.getCredentials().toString();

UserDetails principal = new User(username, password, new ArrayList<>());

return new UsernamePasswordAuthenticationToken(principal, password, new ArrayList<>());
}

@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}









share|improve this question




















  • 2




    No you don't... You need a custom AuthenticationProvider not a custom UserDetailsService. You are trying to solve it in the wrong place.
    – M. Deinum
    Nov 23 '18 at 12:14










  • Thanks for the useful information!!! The only problem I have know is that my custom AuthenticationProvider doesn't trigger when i do /login
    – spoilerd do
    Nov 23 '18 at 13:53










  • But your AuthenticatioNprovider isn't calling anything? It only returns a user it doesn't do a call to an external system at all. Also I doubt that your JwtAuthenticationFilter is actually producing a UsernamePasswordAuthentication.
    – M. Deinum
    Nov 24 '18 at 18:01
















0














In order to get my account I have a external spring application that I need to login at. Why I need it is not important but in order to do a /login call on the API I need to get the password in the UserDetailsServiceMethod. Here is my security setup:



//https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;

//Constructor gets authLogic for external authentication
@Autowired
public WebSecurity(@Qualifier("authLogic") UserDetailsService userDetailsService){
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = new BCryptPasswordEncoder();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**", "/swagger-resources/configuration/ui", "/swagger-resources/configuration/security").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList(BANK_API, INVENTORY_API, MARKET_API)); //TODO: is dit correct??
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setExposedHeaders(Arrays.asList("X-Auth-Token","Authorization","Access-Control-Allow-Origin","Access-Control-Allow-Credentials"));

final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}


My UserDetailsServiceMethod implementation:



@Service
public class AuthLogic implements UserDetailsService {
private HttpServletRequest request;
private IAccountRepository accountRepository;
private RestCallLogic restCall;

@Autowired
public AuthLogic(HttpServletRequest request, IAccountRepository accountRepository, RestCallLogic restCall){
this.request = request;
this.accountRepository = accountRepository;
this.restCall = restCall;
}

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//get password
//make restcall to external login
}
}


Is there a way I can get the password while using the spring security implementation. Because I could easily make my own class and do the login from there but it would be nice to use Spring security for it. Also the login returns a token that I can reform to a User. Maybe i'm just overthinking...



In order to make a API call i needed to write a custom AuthenticationProvider:



@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

String username = authentication.getName();
String password = authentication.getCredentials().toString();

UserDetails principal = new User(username, password, new ArrayList<>());

return new UsernamePasswordAuthenticationToken(principal, password, new ArrayList<>());
}

@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}









share|improve this question




















  • 2




    No you don't... You need a custom AuthenticationProvider not a custom UserDetailsService. You are trying to solve it in the wrong place.
    – M. Deinum
    Nov 23 '18 at 12:14










  • Thanks for the useful information!!! The only problem I have know is that my custom AuthenticationProvider doesn't trigger when i do /login
    – spoilerd do
    Nov 23 '18 at 13:53










  • But your AuthenticatioNprovider isn't calling anything? It only returns a user it doesn't do a call to an external system at all. Also I doubt that your JwtAuthenticationFilter is actually producing a UsernamePasswordAuthentication.
    – M. Deinum
    Nov 24 '18 at 18:01














0












0








0







In order to get my account I have a external spring application that I need to login at. Why I need it is not important but in order to do a /login call on the API I need to get the password in the UserDetailsServiceMethod. Here is my security setup:



//https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;

//Constructor gets authLogic for external authentication
@Autowired
public WebSecurity(@Qualifier("authLogic") UserDetailsService userDetailsService){
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = new BCryptPasswordEncoder();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**", "/swagger-resources/configuration/ui", "/swagger-resources/configuration/security").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList(BANK_API, INVENTORY_API, MARKET_API)); //TODO: is dit correct??
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setExposedHeaders(Arrays.asList("X-Auth-Token","Authorization","Access-Control-Allow-Origin","Access-Control-Allow-Credentials"));

final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}


My UserDetailsServiceMethod implementation:



@Service
public class AuthLogic implements UserDetailsService {
private HttpServletRequest request;
private IAccountRepository accountRepository;
private RestCallLogic restCall;

@Autowired
public AuthLogic(HttpServletRequest request, IAccountRepository accountRepository, RestCallLogic restCall){
this.request = request;
this.accountRepository = accountRepository;
this.restCall = restCall;
}

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//get password
//make restcall to external login
}
}


Is there a way I can get the password while using the spring security implementation. Because I could easily make my own class and do the login from there but it would be nice to use Spring security for it. Also the login returns a token that I can reform to a User. Maybe i'm just overthinking...



In order to make a API call i needed to write a custom AuthenticationProvider:



@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

String username = authentication.getName();
String password = authentication.getCredentials().toString();

UserDetails principal = new User(username, password, new ArrayList<>());

return new UsernamePasswordAuthenticationToken(principal, password, new ArrayList<>());
}

@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}









share|improve this question















In order to get my account I have a external spring application that I need to login at. Why I need it is not important but in order to do a /login call on the API I need to get the password in the UserDetailsServiceMethod. Here is my security setup:



//https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;

//Constructor gets authLogic for external authentication
@Autowired
public WebSecurity(@Qualifier("authLogic") UserDetailsService userDetailsService){
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = new BCryptPasswordEncoder();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**", "/swagger-resources/configuration/ui", "/swagger-resources/configuration/security").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList(BANK_API, INVENTORY_API, MARKET_API)); //TODO: is dit correct??
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setExposedHeaders(Arrays.asList("X-Auth-Token","Authorization","Access-Control-Allow-Origin","Access-Control-Allow-Credentials"));

final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}


My UserDetailsServiceMethod implementation:



@Service
public class AuthLogic implements UserDetailsService {
private HttpServletRequest request;
private IAccountRepository accountRepository;
private RestCallLogic restCall;

@Autowired
public AuthLogic(HttpServletRequest request, IAccountRepository accountRepository, RestCallLogic restCall){
this.request = request;
this.accountRepository = accountRepository;
this.restCall = restCall;
}

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//get password
//make restcall to external login
}
}


Is there a way I can get the password while using the spring security implementation. Because I could easily make my own class and do the login from there but it would be nice to use Spring security for it. Also the login returns a token that I can reform to a User. Maybe i'm just overthinking...



In order to make a API call i needed to write a custom AuthenticationProvider:



@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

String username = authentication.getName();
String password = authentication.getCredentials().toString();

UserDetails principal = new User(username, password, new ArrayList<>());

return new UsernamePasswordAuthenticationToken(principal, password, new ArrayList<>());
}

@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}






java spring spring-security






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 '18 at 13:54







spoilerd do

















asked Nov 23 '18 at 11:24









spoilerd dospoilerd do

205




205








  • 2




    No you don't... You need a custom AuthenticationProvider not a custom UserDetailsService. You are trying to solve it in the wrong place.
    – M. Deinum
    Nov 23 '18 at 12:14










  • Thanks for the useful information!!! The only problem I have know is that my custom AuthenticationProvider doesn't trigger when i do /login
    – spoilerd do
    Nov 23 '18 at 13:53










  • But your AuthenticatioNprovider isn't calling anything? It only returns a user it doesn't do a call to an external system at all. Also I doubt that your JwtAuthenticationFilter is actually producing a UsernamePasswordAuthentication.
    – M. Deinum
    Nov 24 '18 at 18:01














  • 2




    No you don't... You need a custom AuthenticationProvider not a custom UserDetailsService. You are trying to solve it in the wrong place.
    – M. Deinum
    Nov 23 '18 at 12:14










  • Thanks for the useful information!!! The only problem I have know is that my custom AuthenticationProvider doesn't trigger when i do /login
    – spoilerd do
    Nov 23 '18 at 13:53










  • But your AuthenticatioNprovider isn't calling anything? It only returns a user it doesn't do a call to an external system at all. Also I doubt that your JwtAuthenticationFilter is actually producing a UsernamePasswordAuthentication.
    – M. Deinum
    Nov 24 '18 at 18:01








2




2




No you don't... You need a custom AuthenticationProvider not a custom UserDetailsService. You are trying to solve it in the wrong place.
– M. Deinum
Nov 23 '18 at 12:14




No you don't... You need a custom AuthenticationProvider not a custom UserDetailsService. You are trying to solve it in the wrong place.
– M. Deinum
Nov 23 '18 at 12:14












Thanks for the useful information!!! The only problem I have know is that my custom AuthenticationProvider doesn't trigger when i do /login
– spoilerd do
Nov 23 '18 at 13:53




Thanks for the useful information!!! The only problem I have know is that my custom AuthenticationProvider doesn't trigger when i do /login
– spoilerd do
Nov 23 '18 at 13:53












But your AuthenticatioNprovider isn't calling anything? It only returns a user it doesn't do a call to an external system at all. Also I doubt that your JwtAuthenticationFilter is actually producing a UsernamePasswordAuthentication.
– M. Deinum
Nov 24 '18 at 18:01




But your AuthenticatioNprovider isn't calling anything? It only returns a user it doesn't do a call to an external system at all. Also I doubt that your JwtAuthenticationFilter is actually producing a UsernamePasswordAuthentication.
– M. Deinum
Nov 24 '18 at 18:01












2 Answers
2






active

oldest

votes


















1














Behind the scene, Spring Security parses user's credentials in filter (ex. BasicAuthenticationFilter, UsernamePasswordAuthenticationFilter etc. - the filters retrieves user credentials), if such filter successfully retrieved user's credentials it passes such credentials to AuthenticationProvider to verify credentials and create user's details (read more about AuthenticationProvider). The AuthenticationProvider can verify credentials on various way.



One of the implementation of AuthenticationProvider is DaoAuthenticationProvider which tries to find user by username in UserDetailsService and if it found it gets UserDetails for the user from UserDetailsService and then checks if password provided by the user is satisfing the password in UserDetails.



In your case you need to make such request not in UserDetailsService, but in AuthenticationProvider because it's responsible for such case.



My suggestion is to extend AbstractUserDetailsAuthenticationProvider class from spring security and implement your functionality in abstract method protected abstract UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException;.



For example:



@Configuration
public class WebSecurityConf43547 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new AbstractUserDetailsAuthenticationProvider() {
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
//from docs: "[...]Generally a subclass will at least compare the
//Authentication.getCredentials() with a UserDetails.getPassword() [...]"
}

@Override
protected UserDetails retrieveUser(String s, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
usernamePasswordAuthenticationToken.getCredentials();
//your api here
}
});
}
}


The better example: look how DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider in spring security.






share|improve this answer























  • Do i have to do any other configurations in the WebSecurityConfigureAdapter. Cause I started making a custom AuthenticationProvider class and it doesn't get triggered when I do /login it just says Acces Denied.
    – spoilerd do
    Nov 23 '18 at 14:00










  • One more question: where do i put my call to the database to check if the account exists in my local database?
    – spoilerd do
    Nov 28 '18 at 10:23



















0














After a week I finally got what I wanted. So i made a custom authentication provider that will make a REST call to my authentication API. If the username and password I gave are correct I'll get a JWT-token back that contains a username, roles and a ID. after that I just call a custom Authentication service that checks if the user id already exists in its database. If that isn't the case than I'll create a new user with the given id from the JWT-token.



Here is my custom authentication provider:



public class JwtAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

//custom authentication service
private AuthLogic userDetailsImpl;

public JwtAuthenticationProvider(AuthLogic userDetailsImpl) {
this.userDetailsImpl = userDetailsImpl;
}

@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
//JWTUser is a custom class that extends the UserDetails class from spring
JwtUser user = (JwtUser) userDetails;

//call the custom auth service to check if the user exists in the database
userDetailsImpl.loadUserByUsername(user.getUserID(), user.getUsername());
}

@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
//get the token from a external authentication API
String token = retrieveAccountData(new LoginWrapper(username, authentication.getCredentials().toString()));

Claims claims = Jwts.parser()
.setSigningKey(JWTKEY)
.parseClaimsJws(token)
.getBody();

List<String> scopes = (List<String>) claims.get("scopes");
int UserId = (int) claims.get("userID");
List<GrantedAuthority> authorities = scopes.stream()
.map(authority -> new SimpleGrantedAuthority(authority))
.collect(Collectors.toList());

//return the User
return new JwtUser(UserId, username, authentication.getCredentials().toString(), authorities);
}

private String retrieveAccountData(LoginWrapper loginWrapper){
URI uri = UriComponentsBuilder.fromUriString(BANK_LOGIN).build().toUri();
Gson gson = new GsonBuilder().create();

RequestEntity<String> request = RequestEntity
.post(uri)
.accept(MediaType.APPLICATION_JSON)
.body(gson.toJson(loginWrapper));

//post call
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(request, String.class);

//check if status code is correct
if(response.getStatusCode() != HttpStatus.OK) {
throw new UsernameNotFoundException(loginWrapper.getUsername());
}

//convert to LoginWrapper
return gson.fromJson(response.getBody(), TokenWrapper.class).getToken();
}
}


And here is my custom authentication service:



@Service
public class AuthLogic {
private IAccountRepository accountRepository;

@Autowired
public AuthLogic(IAccountRepository context) {
this.accountRepository = context;
}
trough with the jwt token)
public UserDetails loadUserByUsername(int userId, String username) throws UsernameNotFoundException {
Optional<Account> foundAccount = accountRepository.findById(userId);

Account account;
//check if user has logged in to our inventory API before, if not create new account
if (!foundAccount.isPresent()) {
account = accountRepository.save(new Account(userId, username));
} else {
account = foundAccount.get();
}

return new JwtUserPrincipal(account);
}
}


In order to call the service from the provider you need to configure your WebSecurityConfigurerAdapter properly:



@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private JwtAuthenticationProvider authenticationProvider;

@Autowired
public WebSecurity(@Qualifier("authLogic") AuthLogic userDetailsImpl) {
this.authenticationProvider = new JwtAuthenticationProvider(userDetailsImpl);
}

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
}


I hope this answer helps.






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53445809%2fspring-security-get-password-in-userdetailsservicemethod%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    Behind the scene, Spring Security parses user's credentials in filter (ex. BasicAuthenticationFilter, UsernamePasswordAuthenticationFilter etc. - the filters retrieves user credentials), if such filter successfully retrieved user's credentials it passes such credentials to AuthenticationProvider to verify credentials and create user's details (read more about AuthenticationProvider). The AuthenticationProvider can verify credentials on various way.



    One of the implementation of AuthenticationProvider is DaoAuthenticationProvider which tries to find user by username in UserDetailsService and if it found it gets UserDetails for the user from UserDetailsService and then checks if password provided by the user is satisfing the password in UserDetails.



    In your case you need to make such request not in UserDetailsService, but in AuthenticationProvider because it's responsible for such case.



    My suggestion is to extend AbstractUserDetailsAuthenticationProvider class from spring security and implement your functionality in abstract method protected abstract UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException;.



    For example:



    @Configuration
    public class WebSecurityConf43547 extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(new AbstractUserDetailsAuthenticationProvider() {
    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
    //from docs: "[...]Generally a subclass will at least compare the
    //Authentication.getCredentials() with a UserDetails.getPassword() [...]"
    }

    @Override
    protected UserDetails retrieveUser(String s, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
    usernamePasswordAuthenticationToken.getCredentials();
    //your api here
    }
    });
    }
    }


    The better example: look how DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider in spring security.






    share|improve this answer























    • Do i have to do any other configurations in the WebSecurityConfigureAdapter. Cause I started making a custom AuthenticationProvider class and it doesn't get triggered when I do /login it just says Acces Denied.
      – spoilerd do
      Nov 23 '18 at 14:00










    • One more question: where do i put my call to the database to check if the account exists in my local database?
      – spoilerd do
      Nov 28 '18 at 10:23
















    1














    Behind the scene, Spring Security parses user's credentials in filter (ex. BasicAuthenticationFilter, UsernamePasswordAuthenticationFilter etc. - the filters retrieves user credentials), if such filter successfully retrieved user's credentials it passes such credentials to AuthenticationProvider to verify credentials and create user's details (read more about AuthenticationProvider). The AuthenticationProvider can verify credentials on various way.



    One of the implementation of AuthenticationProvider is DaoAuthenticationProvider which tries to find user by username in UserDetailsService and if it found it gets UserDetails for the user from UserDetailsService and then checks if password provided by the user is satisfing the password in UserDetails.



    In your case you need to make such request not in UserDetailsService, but in AuthenticationProvider because it's responsible for such case.



    My suggestion is to extend AbstractUserDetailsAuthenticationProvider class from spring security and implement your functionality in abstract method protected abstract UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException;.



    For example:



    @Configuration
    public class WebSecurityConf43547 extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(new AbstractUserDetailsAuthenticationProvider() {
    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
    //from docs: "[...]Generally a subclass will at least compare the
    //Authentication.getCredentials() with a UserDetails.getPassword() [...]"
    }

    @Override
    protected UserDetails retrieveUser(String s, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
    usernamePasswordAuthenticationToken.getCredentials();
    //your api here
    }
    });
    }
    }


    The better example: look how DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider in spring security.






    share|improve this answer























    • Do i have to do any other configurations in the WebSecurityConfigureAdapter. Cause I started making a custom AuthenticationProvider class and it doesn't get triggered when I do /login it just says Acces Denied.
      – spoilerd do
      Nov 23 '18 at 14:00










    • One more question: where do i put my call to the database to check if the account exists in my local database?
      – spoilerd do
      Nov 28 '18 at 10:23














    1












    1








    1






    Behind the scene, Spring Security parses user's credentials in filter (ex. BasicAuthenticationFilter, UsernamePasswordAuthenticationFilter etc. - the filters retrieves user credentials), if such filter successfully retrieved user's credentials it passes such credentials to AuthenticationProvider to verify credentials and create user's details (read more about AuthenticationProvider). The AuthenticationProvider can verify credentials on various way.



    One of the implementation of AuthenticationProvider is DaoAuthenticationProvider which tries to find user by username in UserDetailsService and if it found it gets UserDetails for the user from UserDetailsService and then checks if password provided by the user is satisfing the password in UserDetails.



    In your case you need to make such request not in UserDetailsService, but in AuthenticationProvider because it's responsible for such case.



    My suggestion is to extend AbstractUserDetailsAuthenticationProvider class from spring security and implement your functionality in abstract method protected abstract UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException;.



    For example:



    @Configuration
    public class WebSecurityConf43547 extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(new AbstractUserDetailsAuthenticationProvider() {
    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
    //from docs: "[...]Generally a subclass will at least compare the
    //Authentication.getCredentials() with a UserDetails.getPassword() [...]"
    }

    @Override
    protected UserDetails retrieveUser(String s, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
    usernamePasswordAuthenticationToken.getCredentials();
    //your api here
    }
    });
    }
    }


    The better example: look how DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider in spring security.






    share|improve this answer














    Behind the scene, Spring Security parses user's credentials in filter (ex. BasicAuthenticationFilter, UsernamePasswordAuthenticationFilter etc. - the filters retrieves user credentials), if such filter successfully retrieved user's credentials it passes such credentials to AuthenticationProvider to verify credentials and create user's details (read more about AuthenticationProvider). The AuthenticationProvider can verify credentials on various way.



    One of the implementation of AuthenticationProvider is DaoAuthenticationProvider which tries to find user by username in UserDetailsService and if it found it gets UserDetails for the user from UserDetailsService and then checks if password provided by the user is satisfing the password in UserDetails.



    In your case you need to make such request not in UserDetailsService, but in AuthenticationProvider because it's responsible for such case.



    My suggestion is to extend AbstractUserDetailsAuthenticationProvider class from spring security and implement your functionality in abstract method protected abstract UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException;.



    For example:



    @Configuration
    public class WebSecurityConf43547 extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(new AbstractUserDetailsAuthenticationProvider() {
    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
    //from docs: "[...]Generally a subclass will at least compare the
    //Authentication.getCredentials() with a UserDetails.getPassword() [...]"
    }

    @Override
    protected UserDetails retrieveUser(String s, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
    usernamePasswordAuthenticationToken.getCredentials();
    //your api here
    }
    });
    }
    }


    The better example: look how DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider in spring security.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 23 '18 at 13:51

























    answered Nov 23 '18 at 13:37









    Andrew SashaAndrew Sasha

    434212




    434212












    • Do i have to do any other configurations in the WebSecurityConfigureAdapter. Cause I started making a custom AuthenticationProvider class and it doesn't get triggered when I do /login it just says Acces Denied.
      – spoilerd do
      Nov 23 '18 at 14:00










    • One more question: where do i put my call to the database to check if the account exists in my local database?
      – spoilerd do
      Nov 28 '18 at 10:23


















    • Do i have to do any other configurations in the WebSecurityConfigureAdapter. Cause I started making a custom AuthenticationProvider class and it doesn't get triggered when I do /login it just says Acces Denied.
      – spoilerd do
      Nov 23 '18 at 14:00










    • One more question: where do i put my call to the database to check if the account exists in my local database?
      – spoilerd do
      Nov 28 '18 at 10:23
















    Do i have to do any other configurations in the WebSecurityConfigureAdapter. Cause I started making a custom AuthenticationProvider class and it doesn't get triggered when I do /login it just says Acces Denied.
    – spoilerd do
    Nov 23 '18 at 14:00




    Do i have to do any other configurations in the WebSecurityConfigureAdapter. Cause I started making a custom AuthenticationProvider class and it doesn't get triggered when I do /login it just says Acces Denied.
    – spoilerd do
    Nov 23 '18 at 14:00












    One more question: where do i put my call to the database to check if the account exists in my local database?
    – spoilerd do
    Nov 28 '18 at 10:23




    One more question: where do i put my call to the database to check if the account exists in my local database?
    – spoilerd do
    Nov 28 '18 at 10:23













    0














    After a week I finally got what I wanted. So i made a custom authentication provider that will make a REST call to my authentication API. If the username and password I gave are correct I'll get a JWT-token back that contains a username, roles and a ID. after that I just call a custom Authentication service that checks if the user id already exists in its database. If that isn't the case than I'll create a new user with the given id from the JWT-token.



    Here is my custom authentication provider:



    public class JwtAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

    //custom authentication service
    private AuthLogic userDetailsImpl;

    public JwtAuthenticationProvider(AuthLogic userDetailsImpl) {
    this.userDetailsImpl = userDetailsImpl;
    }

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
    //JWTUser is a custom class that extends the UserDetails class from spring
    JwtUser user = (JwtUser) userDetails;

    //call the custom auth service to check if the user exists in the database
    userDetailsImpl.loadUserByUsername(user.getUserID(), user.getUsername());
    }

    @Override
    protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
    //get the token from a external authentication API
    String token = retrieveAccountData(new LoginWrapper(username, authentication.getCredentials().toString()));

    Claims claims = Jwts.parser()
    .setSigningKey(JWTKEY)
    .parseClaimsJws(token)
    .getBody();

    List<String> scopes = (List<String>) claims.get("scopes");
    int UserId = (int) claims.get("userID");
    List<GrantedAuthority> authorities = scopes.stream()
    .map(authority -> new SimpleGrantedAuthority(authority))
    .collect(Collectors.toList());

    //return the User
    return new JwtUser(UserId, username, authentication.getCredentials().toString(), authorities);
    }

    private String retrieveAccountData(LoginWrapper loginWrapper){
    URI uri = UriComponentsBuilder.fromUriString(BANK_LOGIN).build().toUri();
    Gson gson = new GsonBuilder().create();

    RequestEntity<String> request = RequestEntity
    .post(uri)
    .accept(MediaType.APPLICATION_JSON)
    .body(gson.toJson(loginWrapper));

    //post call
    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<String> response = restTemplate.exchange(request, String.class);

    //check if status code is correct
    if(response.getStatusCode() != HttpStatus.OK) {
    throw new UsernameNotFoundException(loginWrapper.getUsername());
    }

    //convert to LoginWrapper
    return gson.fromJson(response.getBody(), TokenWrapper.class).getToken();
    }
    }


    And here is my custom authentication service:



    @Service
    public class AuthLogic {
    private IAccountRepository accountRepository;

    @Autowired
    public AuthLogic(IAccountRepository context) {
    this.accountRepository = context;
    }
    trough with the jwt token)
    public UserDetails loadUserByUsername(int userId, String username) throws UsernameNotFoundException {
    Optional<Account> foundAccount = accountRepository.findById(userId);

    Account account;
    //check if user has logged in to our inventory API before, if not create new account
    if (!foundAccount.isPresent()) {
    account = accountRepository.save(new Account(userId, username));
    } else {
    account = foundAccount.get();
    }

    return new JwtUserPrincipal(account);
    }
    }


    In order to call the service from the provider you need to configure your WebSecurityConfigurerAdapter properly:



    @EnableWebSecurity
    public class WebSecurity extends WebSecurityConfigurerAdapter {
    private JwtAuthenticationProvider authenticationProvider;

    @Autowired
    public WebSecurity(@Qualifier("authLogic") AuthLogic userDetailsImpl) {
    this.authenticationProvider = new JwtAuthenticationProvider(userDetailsImpl);
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider);
    }
    }


    I hope this answer helps.






    share|improve this answer


























      0














      After a week I finally got what I wanted. So i made a custom authentication provider that will make a REST call to my authentication API. If the username and password I gave are correct I'll get a JWT-token back that contains a username, roles and a ID. after that I just call a custom Authentication service that checks if the user id already exists in its database. If that isn't the case than I'll create a new user with the given id from the JWT-token.



      Here is my custom authentication provider:



      public class JwtAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

      //custom authentication service
      private AuthLogic userDetailsImpl;

      public JwtAuthenticationProvider(AuthLogic userDetailsImpl) {
      this.userDetailsImpl = userDetailsImpl;
      }

      @Override
      protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
      //JWTUser is a custom class that extends the UserDetails class from spring
      JwtUser user = (JwtUser) userDetails;

      //call the custom auth service to check if the user exists in the database
      userDetailsImpl.loadUserByUsername(user.getUserID(), user.getUsername());
      }

      @Override
      protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
      //get the token from a external authentication API
      String token = retrieveAccountData(new LoginWrapper(username, authentication.getCredentials().toString()));

      Claims claims = Jwts.parser()
      .setSigningKey(JWTKEY)
      .parseClaimsJws(token)
      .getBody();

      List<String> scopes = (List<String>) claims.get("scopes");
      int UserId = (int) claims.get("userID");
      List<GrantedAuthority> authorities = scopes.stream()
      .map(authority -> new SimpleGrantedAuthority(authority))
      .collect(Collectors.toList());

      //return the User
      return new JwtUser(UserId, username, authentication.getCredentials().toString(), authorities);
      }

      private String retrieveAccountData(LoginWrapper loginWrapper){
      URI uri = UriComponentsBuilder.fromUriString(BANK_LOGIN).build().toUri();
      Gson gson = new GsonBuilder().create();

      RequestEntity<String> request = RequestEntity
      .post(uri)
      .accept(MediaType.APPLICATION_JSON)
      .body(gson.toJson(loginWrapper));

      //post call
      RestTemplate restTemplate = new RestTemplate();
      ResponseEntity<String> response = restTemplate.exchange(request, String.class);

      //check if status code is correct
      if(response.getStatusCode() != HttpStatus.OK) {
      throw new UsernameNotFoundException(loginWrapper.getUsername());
      }

      //convert to LoginWrapper
      return gson.fromJson(response.getBody(), TokenWrapper.class).getToken();
      }
      }


      And here is my custom authentication service:



      @Service
      public class AuthLogic {
      private IAccountRepository accountRepository;

      @Autowired
      public AuthLogic(IAccountRepository context) {
      this.accountRepository = context;
      }
      trough with the jwt token)
      public UserDetails loadUserByUsername(int userId, String username) throws UsernameNotFoundException {
      Optional<Account> foundAccount = accountRepository.findById(userId);

      Account account;
      //check if user has logged in to our inventory API before, if not create new account
      if (!foundAccount.isPresent()) {
      account = accountRepository.save(new Account(userId, username));
      } else {
      account = foundAccount.get();
      }

      return new JwtUserPrincipal(account);
      }
      }


      In order to call the service from the provider you need to configure your WebSecurityConfigurerAdapter properly:



      @EnableWebSecurity
      public class WebSecurity extends WebSecurityConfigurerAdapter {
      private JwtAuthenticationProvider authenticationProvider;

      @Autowired
      public WebSecurity(@Qualifier("authLogic") AuthLogic userDetailsImpl) {
      this.authenticationProvider = new JwtAuthenticationProvider(userDetailsImpl);
      }

      @Override
      public void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.authenticationProvider(authenticationProvider);
      }
      }


      I hope this answer helps.






      share|improve this answer
























        0












        0








        0






        After a week I finally got what I wanted. So i made a custom authentication provider that will make a REST call to my authentication API. If the username and password I gave are correct I'll get a JWT-token back that contains a username, roles and a ID. after that I just call a custom Authentication service that checks if the user id already exists in its database. If that isn't the case than I'll create a new user with the given id from the JWT-token.



        Here is my custom authentication provider:



        public class JwtAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

        //custom authentication service
        private AuthLogic userDetailsImpl;

        public JwtAuthenticationProvider(AuthLogic userDetailsImpl) {
        this.userDetailsImpl = userDetailsImpl;
        }

        @Override
        protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        //JWTUser is a custom class that extends the UserDetails class from spring
        JwtUser user = (JwtUser) userDetails;

        //call the custom auth service to check if the user exists in the database
        userDetailsImpl.loadUserByUsername(user.getUserID(), user.getUsername());
        }

        @Override
        protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        //get the token from a external authentication API
        String token = retrieveAccountData(new LoginWrapper(username, authentication.getCredentials().toString()));

        Claims claims = Jwts.parser()
        .setSigningKey(JWTKEY)
        .parseClaimsJws(token)
        .getBody();

        List<String> scopes = (List<String>) claims.get("scopes");
        int UserId = (int) claims.get("userID");
        List<GrantedAuthority> authorities = scopes.stream()
        .map(authority -> new SimpleGrantedAuthority(authority))
        .collect(Collectors.toList());

        //return the User
        return new JwtUser(UserId, username, authentication.getCredentials().toString(), authorities);
        }

        private String retrieveAccountData(LoginWrapper loginWrapper){
        URI uri = UriComponentsBuilder.fromUriString(BANK_LOGIN).build().toUri();
        Gson gson = new GsonBuilder().create();

        RequestEntity<String> request = RequestEntity
        .post(uri)
        .accept(MediaType.APPLICATION_JSON)
        .body(gson.toJson(loginWrapper));

        //post call
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.exchange(request, String.class);

        //check if status code is correct
        if(response.getStatusCode() != HttpStatus.OK) {
        throw new UsernameNotFoundException(loginWrapper.getUsername());
        }

        //convert to LoginWrapper
        return gson.fromJson(response.getBody(), TokenWrapper.class).getToken();
        }
        }


        And here is my custom authentication service:



        @Service
        public class AuthLogic {
        private IAccountRepository accountRepository;

        @Autowired
        public AuthLogic(IAccountRepository context) {
        this.accountRepository = context;
        }
        trough with the jwt token)
        public UserDetails loadUserByUsername(int userId, String username) throws UsernameNotFoundException {
        Optional<Account> foundAccount = accountRepository.findById(userId);

        Account account;
        //check if user has logged in to our inventory API before, if not create new account
        if (!foundAccount.isPresent()) {
        account = accountRepository.save(new Account(userId, username));
        } else {
        account = foundAccount.get();
        }

        return new JwtUserPrincipal(account);
        }
        }


        In order to call the service from the provider you need to configure your WebSecurityConfigurerAdapter properly:



        @EnableWebSecurity
        public class WebSecurity extends WebSecurityConfigurerAdapter {
        private JwtAuthenticationProvider authenticationProvider;

        @Autowired
        public WebSecurity(@Qualifier("authLogic") AuthLogic userDetailsImpl) {
        this.authenticationProvider = new JwtAuthenticationProvider(userDetailsImpl);
        }

        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
        }
        }


        I hope this answer helps.






        share|improve this answer












        After a week I finally got what I wanted. So i made a custom authentication provider that will make a REST call to my authentication API. If the username and password I gave are correct I'll get a JWT-token back that contains a username, roles and a ID. after that I just call a custom Authentication service that checks if the user id already exists in its database. If that isn't the case than I'll create a new user with the given id from the JWT-token.



        Here is my custom authentication provider:



        public class JwtAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

        //custom authentication service
        private AuthLogic userDetailsImpl;

        public JwtAuthenticationProvider(AuthLogic userDetailsImpl) {
        this.userDetailsImpl = userDetailsImpl;
        }

        @Override
        protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        //JWTUser is a custom class that extends the UserDetails class from spring
        JwtUser user = (JwtUser) userDetails;

        //call the custom auth service to check if the user exists in the database
        userDetailsImpl.loadUserByUsername(user.getUserID(), user.getUsername());
        }

        @Override
        protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        //get the token from a external authentication API
        String token = retrieveAccountData(new LoginWrapper(username, authentication.getCredentials().toString()));

        Claims claims = Jwts.parser()
        .setSigningKey(JWTKEY)
        .parseClaimsJws(token)
        .getBody();

        List<String> scopes = (List<String>) claims.get("scopes");
        int UserId = (int) claims.get("userID");
        List<GrantedAuthority> authorities = scopes.stream()
        .map(authority -> new SimpleGrantedAuthority(authority))
        .collect(Collectors.toList());

        //return the User
        return new JwtUser(UserId, username, authentication.getCredentials().toString(), authorities);
        }

        private String retrieveAccountData(LoginWrapper loginWrapper){
        URI uri = UriComponentsBuilder.fromUriString(BANK_LOGIN).build().toUri();
        Gson gson = new GsonBuilder().create();

        RequestEntity<String> request = RequestEntity
        .post(uri)
        .accept(MediaType.APPLICATION_JSON)
        .body(gson.toJson(loginWrapper));

        //post call
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.exchange(request, String.class);

        //check if status code is correct
        if(response.getStatusCode() != HttpStatus.OK) {
        throw new UsernameNotFoundException(loginWrapper.getUsername());
        }

        //convert to LoginWrapper
        return gson.fromJson(response.getBody(), TokenWrapper.class).getToken();
        }
        }


        And here is my custom authentication service:



        @Service
        public class AuthLogic {
        private IAccountRepository accountRepository;

        @Autowired
        public AuthLogic(IAccountRepository context) {
        this.accountRepository = context;
        }
        trough with the jwt token)
        public UserDetails loadUserByUsername(int userId, String username) throws UsernameNotFoundException {
        Optional<Account> foundAccount = accountRepository.findById(userId);

        Account account;
        //check if user has logged in to our inventory API before, if not create new account
        if (!foundAccount.isPresent()) {
        account = accountRepository.save(new Account(userId, username));
        } else {
        account = foundAccount.get();
        }

        return new JwtUserPrincipal(account);
        }
        }


        In order to call the service from the provider you need to configure your WebSecurityConfigurerAdapter properly:



        @EnableWebSecurity
        public class WebSecurity extends WebSecurityConfigurerAdapter {
        private JwtAuthenticationProvider authenticationProvider;

        @Autowired
        public WebSecurity(@Qualifier("authLogic") AuthLogic userDetailsImpl) {
        this.authenticationProvider = new JwtAuthenticationProvider(userDetailsImpl);
        }

        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
        }
        }


        I hope this answer helps.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Dec 4 '18 at 16:47









        spoilerd dospoilerd do

        205




        205






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53445809%2fspring-security-get-password-in-userdetailsservicemethod%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            What visual should I use to simply compare current year value vs last year in Power BI desktop

            How to ignore python UserWarning in pytest?

            Alexandru Averescu