001/*
002 *  Copyright 2025 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.mobileapp.action;
017
018import java.text.ParseException;
019import java.util.Map;
020
021import org.apache.cocoon.environment.Request;
022
023import org.ametys.core.authentication.CredentialProvider;
024import org.ametys.core.user.UserIdentity;
025import org.ametys.core.user.directory.UserDirectory;
026import org.ametys.core.user.population.UserPopulation;
027import org.ametys.plugins.extrausermgt.authentication.oidc.OIDCBasedCredentialProvider;
028
029import com.nimbusds.jose.JOSEException;
030import com.nimbusds.jose.JWSAlgorithm;
031import com.nimbusds.jose.proc.BadJOSEException;
032import com.nimbusds.jwt.JWT;
033import com.nimbusds.jwt.JWTParser;
034import com.nimbusds.oauth2.sdk.id.ClientID;
035import com.nimbusds.oauth2.sdk.id.Issuer;
036import com.nimbusds.openid.connect.sdk.claims.IDTokenClaimsSet;
037import com.nimbusds.openid.connect.sdk.validators.IDTokenValidator;
038
039/**
040 * Action exchanging an OIDC access token for an Ametys mobile app token.
041 */
042public class GetTokenFromOIDCAction extends AbstractGetTokenAction
043{
044    @Override
045    protected UserIdentity tryConnect(Map<String, Object> params, Request request, String context, UserPopulation userPopulation, CredentialProvider credentialProvider, int credentialProviderIndex)
046    {
047        if (credentialProvider instanceof OIDCBasedCredentialProvider oidcCredentialProvider)
048        {
049            try
050            {
051                String idToken = (String) getParameter("idToken", params, request);
052
053                JWT token = JWTParser.parse(idToken);
054                IDTokenValidator validator = new IDTokenValidator(new Issuer(oidcCredentialProvider.getIssuer()),
055                                                                  new ClientID(oidcCredentialProvider.getClientId()),
056                                                                  JWSAlgorithm.RS256,
057                                                                  oidcCredentialProvider.getJwkSetURL());
058                IDTokenClaimsSet claims = validator.validate(token, null);
059                
060                String login = claims.getStringClaim("preferred_username");
061                
062                for (UserDirectory userDirectory : userPopulation.getUserDirectories())
063                {
064                    if (userDirectory.getStoredUser(login) != null)
065                    {
066                        return new UserIdentity(login, userPopulation.getId());
067                    }
068                }
069            }
070            catch (ParseException | BadJOSEException | JOSEException e)
071            {
072                getLogger().error("Impossible to validate id token  on population '" + userPopulation.getId() + "' using credential provider at position '" + credentialProviderIndex + "'", e);
073            }
074        }
075        
076        return null;
077    }
078}