001/*
002 *  Copyright 2021 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.extrausermgt.authentication.msal;
017
018import java.util.Map;
019import java.util.Set;
020
021import org.apache.avalon.framework.service.ServiceException;
022import org.apache.avalon.framework.service.ServiceManager;
023import org.apache.avalon.framework.service.Serviceable;
024import org.apache.commons.lang3.StringUtils;
025
026import org.ametys.plugins.extrausermgt.users.entraid.EntraIDUserDirectory;
027
028import com.azure.identity.ClientSecretCredential;
029import com.azure.identity.ClientSecretCredentialBuilder;
030import com.microsoft.aad.msal4j.IAuthenticationResult;
031import com.microsoft.graph.models.User;
032import com.microsoft.graph.serviceclient.GraphServiceClient;
033
034/**
035 * Sign in through Entra ID, using the OpenId Connect protocol.
036 */
037public class EntraIDCredentialProvider extends AbstractMSALCredentialProvider implements Serviceable
038{
039    private String _tenant;
040    private String _loginAttribute;
041    
042    private OIDCScopesExtensionPoint _scopesExtensionPoint;
043    
044    public void service(ServiceManager manager) throws ServiceException
045    {
046        _scopesExtensionPoint = (OIDCScopesExtensionPoint) manager.lookup(OIDCScopesExtensionPoint.ROLE);
047    }
048    
049    @Override
050    public void init(String id, String cpModelId, Map<String, Object> paramValues, String label) throws Exception
051    {
052        super.init(id, cpModelId, paramValues, label);
053        
054        _tenant = (String) paramValues.get("authentication.entraid.tenant");
055
056        String clientID = (String) paramValues.get("authentication.entraid.appid");
057        String clientSecret = (String) paramValues.get("authentication.entraid.clientsecret");
058        boolean silent = (boolean) paramValues.get("authentication.entraid.silent");
059        boolean prompt = (boolean) paramValues.get("authentication.entraid.prompt");
060
061        init(clientID, clientSecret, prompt, silent);
062        
063        _loginAttribute = (String) paramValues.get("authentication.entraid.loginattribute");
064    }
065    
066    @Override
067    protected String getAuthority()
068    {
069        return "https://login.microsoftonline.com/" + _tenant;
070    }
071    
072    @Override
073    protected Set<String> getScopes()
074    {
075        return _scopesExtensionPoint.getScopes();
076    }
077    
078    @Override
079    protected String getLogin(IAuthenticationResult result)
080    {
081        String upn = result.account().username();
082        
083        if (_loginAttribute.equals(EntraIDUserDirectory.ON_PREMISES_SAM_ACCOUNT_NAME))
084        {
085            // get the samAccountName from Entra ID
086            ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder().clientId(_clientID)
087                                                                                               .clientSecret(_clientSecret)
088                                                                                               .tenantId(_tenant)
089                                                                                               .build();
090
091            GraphServiceClient graphClient = new GraphServiceClient(clientSecretCredential);
092            
093            User user = graphClient.users().byUserId(upn).get(requestConfiguration -> {
094                requestConfiguration.queryParameters.select = new String[]{"onPremisesSamAccountName"};
095            });
096            
097            if (user != null && StringUtils.isNotBlank(user.getOnPremisesSamAccountName()))
098            {
099                return user.getOnPremisesSamAccountName();
100            }
101        }
102
103        return upn;
104    }
105}