/**
 * 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.provider.security;


import io.gravitee.am.gateway.handler.oauth2.provider.client.DelegateClientDetails;
import io.gravitee.am.gateway.handler.oauth2.security.IdentityProviderManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @author David BRASSELY (david.brassely at graviteesource.com)
 * @author GraviteeSource Team
 */
public class ClientBasedAuthenticationProvider implements AuthenticationProvider {

    /**
     * Logger.
     */
    private final Logger logger = LoggerFactory.getLogger(ClientBasedAuthenticationProvider.class);

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private IdentityProviderManager identityProviderManager;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Map<String, String> details = (Map<String, String>) authentication.getDetails();
        String clientId = details.get("client_id");

        // TODO: is there an other way to access client details without calling storage again ?
        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
        if (clientDetails instanceof DelegateClientDetails) {
            Set<String> identities = ((DelegateClientDetails) clientDetails).getClient().getIdentities();
            Iterator<String> iter = identities.iterator();
            io.gravitee.am.identityprovider.api.User user = null;
            while (iter.hasNext() && user == null) {
                String provider = iter.next();
                io.gravitee.am.identityprovider.api.AuthenticationProvider authenticationProvider =
                        identityProviderManager.get(provider);

                try {
                    user = authenticationProvider.loadUserByUsername(new io.gravitee.am.identityprovider.api.Authentication() {
                        @Override
                        public Object getCredentials() {
                            return authentication.getCredentials().toString();
                        }

                        @Override
                        public Object getPrincipal() {
                            return authentication.getName();
                        }
                    });
                } catch (Exception ex) {
                    logger.info("Unable to authenticate user {} with provider {}",
                            authentication.getName(), provider);
                }
            }

            if (user != null) {
                return new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(),
                        AuthorityUtils.NO_AUTHORITIES);
            }

            throw new BadCredentialsException("Bad credentials.");
        }

        throw new BadCredentialsException("Authentication can not be handle");
    }

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

@@ -2440,16 +2440,34 @@
 again ?%0A
+        try %7B%0A    
         
@@ -2549,16 +2549,20 @@
 entId);%0A
+    
         
@@ -2627,16 +2627,20 @@
         
+    
 Set%3CStri
@@ -2737,16 +2737,20 @@
         
+    
 Iterator
@@ -2792,32 +2792,36 @@
 ();%0A            
+   
+ 
 io.gravitee.am.i
@@ -2858,16 +2858,20 @@
 = null;%0A
+    
         
@@ -2927,24 +2927,28 @@
             
+    
 String provi
@@ -2974,32 +2974,36 @@
                 
+ 
+   
 io.gravitee.am.i
@@ -3094,16 +3094,20 @@
         
+    
 identity
@@ -3134,24 +3134,28 @@
 provider);%0A%0A
+    
             
@@ -3184,16 +3184,20 @@
         
+    
 user = a
@@ -3312,32 +3312,36 @@
                 
+    
 @Override%0A      
@@ -3350,32 +3350,36 @@
                 
+   
+ 
 public Object ge
@@ -3391,24 +3391,28 @@
 entials() %7B%0A
+    
             
@@ -3494,32 +3494,36 @@
                 
+    
 %7D%0A%0A             
@@ -3525,32 +3525,36 @@
                 
+  
+  
 @Override%0A      
@@ -3539,32 +3539,36 @@
       @Override%0A
+    
                 
@@ -3602,24 +3602,28 @@
 incipal() %7B%0A
+    
             
@@ -3687,34 +3687,42 @@
                 
-%7D%0A
+    %7D%0A    
                 
@@ -3745,16 +3745,20 @@
         
+   
+ 
 %7D catch 
@@ -3770,24 +3770,28 @@
 ption ex) %7B%0A
+    
             
@@ -3889,16 +3889,20 @@
         
+    
 authenti
@@ -3938,34 +3938,42 @@
                 
+  
-%7D%0A
+  %7D%0A    
             %7D%0A%0A 
@@ -3963,32 +3963,36 @@
              %7D%0A%0A
+    
             if (
@@ -3999,32 +3999,36 @@
 user != null) %7B%0A
+    
                 
@@ -4138,16 +4138,20 @@
         
+    
 Authorit
@@ -4178,35 +4178,43 @@
 S);%0A            
+   
+ 
 %7D%0A%0A
+    
             thro
@@ -4264,32 +4264,70 @@
 als.%22);%0A        
+    %7D%0A        %7D catch (Exception ex) %7B
 %7D%0A%0A        throw

Check client_id while doing authentication