001/*
002 *  Copyright 2022 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.oidc;
017
018import java.io.InputStream;
019import java.net.URI;
020import java.net.URL;
021import java.nio.charset.StandardCharsets;
022import java.util.Map;
023
024import org.apache.commons.io.IOUtils;
025
026import org.ametys.runtime.authentication.AccessDeniedException;
027
028import com.nimbusds.oauth2.sdk.Scope;
029import com.nimbusds.openid.connect.sdk.OIDCScopeValue;
030import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
031
032
033/**
034 * Sign in through an OIDC application (finding URIs by itself) using the OpenId Connect protocol.
035 */
036public class AutoDiscoveringOIDCCredentialProvider extends AbstractOIDCCredentialProvider
037{
038    /** 
039     * Returns the provider meta data which contains the URIs retrieved from the "/.well-known/openid-configuration" of the issuer
040     * @return The provider meta data which contains the URIs
041     */
042    private OIDCProviderMetadata _getProviderMetadata(URI issuerURI) throws Exception
043    {
044        URL providerConfigurationURL = issuerURI.resolve(".well-known/openid-configuration").toURL();
045        try (InputStream stream = providerConfigurationURL.openStream()) 
046        {
047            // Read all data from URL
048            String providerInfo = IOUtils.toString(stream, StandardCharsets.UTF_8);
049            return OIDCProviderMetadata.parse(providerInfo);
050        }
051    }
052    
053    @Override
054    protected void initUrisScope() throws AccessDeniedException
055    {  
056        Map<String, Object> paramValues = getParameterValues();
057        try
058        {  
059            URI issuerURI = URI.create((String) paramValues.get("authentication.oidc.issuerURI"));
060            OIDCProviderMetadata providerMetadata = _getProviderMetadata(issuerURI);
061            _authUri = providerMetadata.getAuthorizationEndpointURI();
062            _tokenEndpointUri = providerMetadata.getTokenEndpointURI();
063            _iss = providerMetadata.getIssuer();
064            _jwkSetURL = providerMetadata.getJWKSetURI().toURL();
065            _userInfoEndpoint = providerMetadata.getUserInfoEndpointURI();
066            
067            _scope = Scope.parse((String) paramValues.get("authentication.oidc.scopes"));
068            _scope.add(OIDCScopeValue.OPENID);
069        }
070        catch (Exception e)
071        {
072            getLogger().error("Encountered a problem while retrieving provider metadata", e);
073            throw new AccessDeniedException("Encountered a problem while retrieving provider metadata");
074        }
075    }
076}