/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gravitee.am.gateway.handler.oauth2.userdetails;

import io.gravitee.am.gateway.handler.oauth2.security.IdentityProviderManager;
import io.gravitee.am.gateway.service.UserService;
import io.gravitee.am.gateway.service.exception.TechnicalManagementException;
import io.gravitee.am.gateway.service.exception.UserNotFoundException;
import io.gravitee.am.identityprovider.api.AuthenticationProvider;
import io.gravitee.am.model.Domain;
import io.gravitee.am.model.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

/**
 * @author David BRASSELY (david.brassely at graviteesource.com)
 * @author Titouan COMPIEGNE (titouan.compiegne at graviteesource.com)
 * @author GraviteeSource Team
 */
public class CustomUserDetailsService implements UserDetailsService {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomUserDetailsService.class);

    @Autowired
    private UserService userService;

    @Autowired
    private Domain domain;

    @Autowired
    private IdentityProviderManager identityProviderManager;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // use to find a pre-authenticated user
        // The user should be present in gravitee repository and should be retrieved from the user last identity provider
        User user;
        try {
            user = userService.loadUserByUsernameAndDomain(domain.getId(), username);
        } catch (UserNotFoundException e) {
            LOGGER.info("User with username : {} and for domain : {} not found", username, domain.getId(), e);
            throw new UsernameNotFoundException(username);
        } catch (TechnicalManagementException e) {
            LOGGER.error("Failed to find user by username {} and domain {}", username, domain.getId(), e);
            throw new UsernameNotFoundException(username);
        }

        AuthenticationProvider authenticationprovider = identityProviderManager.get(user.getSource());

        if (authenticationprovider == null) {
            LOGGER.info("Registered identity provider : {} not found for username : {}", user.getSource(), username);
            throw new UsernameNotFoundException("Registered identity provider : " + user.getSource() + " not found for username : " + username);
        }

        io.gravitee.am.identityprovider.api.User idpUser;
        try {
            idpUser = authenticationprovider.loadUserByUsername(username);
        } catch(Exception e) {
            LOGGER.info("User with username : {} and for domain : {} not found", username, domain.getId(), e);
            throw new UsernameNotFoundException(username);
        }

        return new CustomUserDetails(user, idpUser);
    }

}

@@ -1440,16 +1440,47 @@
 ption;%0A%0A
+import java.util.Collections;%0A%0A
 /**%0A * @
@@ -2267,16 +2267,34 @@
 rovider%0A
+        try %7B%0A    
         
@@ -2304,38 +2304,46 @@
 r user;%0A        
+    
 try %7B%0A
+    
             user
@@ -2412,32 +2412,36 @@
 rname);%0A        
+ 
+   
 %7D catch (UserNot
@@ -2452,32 +2452,36 @@
 dException e) %7B%0A
+    
             LOGG
@@ -2579,32 +2579,36 @@
 e);%0A            
+    
 throw new Userna
@@ -2638,32 +2638,36 @@
 rname);%0A        
+   
+ 
 %7D catch (Technic
@@ -2685,32 +2685,36 @@
 tException e) %7B%0A
+    
             LOGG
@@ -2808,32 +2808,36 @@
 e);%0A            
+    
 throw new Userna
@@ -2859,32 +2859,36 @@
 tion(username);%0A
+    
         %7D%0A%0A     
@@ -2890,16 +2890,20 @@
         
+    
 Authenti
@@ -2998,16 +2998,20 @@
         
+   
+ 
 if (auth
@@ -3036,24 +3036,28 @@
  == null) %7B%0A
+    
             
@@ -3166,32 +3166,36 @@
 e);%0A            
+  
+  
 throw new Userna
@@ -3311,35 +3311,43 @@
 rname);%0A        
-%7D%0A%0A
+    %7D%0A%0A    
         io.gravi
@@ -3388,38 +3388,46 @@
 dpUser;%0A        
+   
+ 
 try %7B%0A
+    
             idpU
@@ -3493,23 +3493,28 @@
         
+    
 %7D catch
+ 
 (Excepti
@@ -3525,32 +3525,36 @@
 ) %7B%0A            
+   
+ 
 LOGGER.info(%22Use
@@ -3585,32 +3585,59 @@
  for domain : %7B%7D
+ and identity provider : %7B%7D
  not found%22, use
@@ -3651,36 +3651,58 @@
 domain.getId(), 
-e);%0A
+user.getSource(), e);%0A    
             thro
@@ -3736,32 +3736,36 @@
 tion(username);%0A
+    
         %7D%0A%0A     
@@ -3767,16 +3767,20 @@
         
+    
 return n
@@ -3816,16 +3816,291 @@
 pUser);%0A
+        %7D catch (UsernameNotFoundException e) %7B%0A            LOGGER.info(%22User not found while obtaining a renewed access token, return default user%22);%0A            return new org.springframework.security.core.userdetails.User(username, %22%22, Collections.emptyList());%0A        %7D%0A
     %7D%0A%0A%7D

set default user for refresh token grant type