/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.module.extension.internal.runtime.connectivity.oauth; import static java.util.Optional.empty; import static java.util.Optional.of; import static org.mule.runtime.core.api.lifecycle.LifecycleUtils.initialiseIfNeeded; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.ACCESS_TOKEN_URL_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.AFTER_FLOW_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.AUTHORIZATION_URL_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.BEFORE_FLOW_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.CALLBACK_HOST_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.CALLBACK_PATH_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.CALLBACK_PORT_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.CONSUMER_KEY_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.CONSUMER_SECRET_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.LISTENER_CONFIG_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.LOCAL_AUTHORIZE_PATH_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.OAUTH_AUTHORIZATION_CODE_GROUP_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.OAUTH_CALLBACK_GROUP_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.OAUTH_STORE_CONFIG_GROUP_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.OBJECT_STORE_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.RESOURCE_OWNER_ID_PARAMETER_NAME; import static org.mule.runtime.extension.api.connectivity.oauth.ExtensionOAuthConstants.SCOPES_PARAMETER_NAME; import static org.mule.runtime.module.extension.internal.runtime.resolver.ValueResolvingContext.from; import static org.mule.runtime.module.extension.internal.util.MuleExtensionUtils.getInitialiserEvent; import org.mule.runtime.api.config.PoolingProfile; import org.mule.runtime.api.connection.ConnectionProvider; import org.mule.runtime.api.exception.MuleException; import org.mule.runtime.api.exception.MuleRuntimeException; import org.mule.runtime.api.lifecycle.Startable; import org.mule.runtime.api.meta.model.ExtensionModel; import org.mule.runtime.api.meta.model.connection.ConnectionProviderModel; import org.mule.runtime.api.meta.model.parameter.ParameterModel; import org.mule.runtime.core.api.Event; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.retry.RetryPolicyTemplate; import org.mule.runtime.core.internal.connection.ConnectionManagerAdapter; import org.mule.runtime.core.util.StringMessageUtils; import org.mule.runtime.extension.api.connectivity.oauth.AuthorizationCodeGrantType; import org.mule.runtime.extension.api.connectivity.oauth.OAuthModelProperty; import org.mule.runtime.extension.api.connectivity.oauth.OAuthParameterModelProperty; import org.mule.runtime.module.extension.internal.loader.java.property.oauth.OAuthCallbackValuesModelProperty; import org.mule.runtime.module.extension.internal.runtime.config.DefaultConnectionProviderObjectBuilder; import org.mule.runtime.module.extension.internal.runtime.resolver.MapValueResolver; import org.mule.runtime.module.extension.internal.runtime.resolver.ResolverSet; import org.mule.runtime.module.extension.internal.runtime.resolver.ResolverSetResult; import org.mule.runtime.module.extension.internal.runtime.resolver.ValueResolver; import org.mule.runtime.module.extension.internal.runtime.resolver.ValueResolvingContext; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.BiConsumer; import org.apache.commons.lang.StringUtils; /** * A specialization of {@link DefaultConnectionProviderObjectBuilder} to wrap the {@link ConnectionProvider} * into {@link OAuthConnectionProviderWrapper} instances. * * @since 4.0 */ public class OAuthConnectionProviderObjectBuilder<C> extends DefaultConnectionProviderObjectBuilder<C> implements Startable { private final ExtensionsOAuthManager oauthManager; private final AuthorizationCodeGrantType grantType; private final Map<Field, String> callbackValues; public OAuthConnectionProviderObjectBuilder(ConnectionProviderModel providerModel, ResolverSet resolverSet, PoolingProfile poolingProfile, boolean disableValidation, RetryPolicyTemplate retryPolicyTemplate, ExtensionsOAuthManager oauthManager, ConnectionManagerAdapter connectionManager, ExtensionModel extensionModel, MuleContext muleContext) { super(providerModel, resolverSet, poolingProfile, disableValidation, retryPolicyTemplate, connectionManager, extensionModel, muleContext); this.oauthManager = oauthManager; grantType = getGrantType(); callbackValues = getCallbackValues(); } @Override public void start() throws MuleException { oauthManager.register(getInitialOAuthConfig()); } @Override public ConnectionProvider<C> build(ValueResolvingContext context) throws MuleException { ResolverSetResult result = resolverSet.resolve(context); ConnectionProvider<C> provider = super.doBuild(result); OAuthConfig config = new OAuthConfig(ownerConfigName, buildAuthCodeConfig(context.getEvent()), buildOAuthCallbackConfig(context.getEvent()), buildOAuthObjectStoreConfig(context.getEvent()), grantType, getCustomParameters(result), getCallbackValues()); return new OAuthConnectionProviderWrapper<>(provider, config, getCallbackValues(), oauthManager, disableValidation, retryPolicyTemplate); } private AuthCodeConfig buildAuthCodeConfig(Event event) throws MuleException { Map<String, Object> map = (Map<String, Object>) resolverSet.getResolvers().get(OAUTH_AUTHORIZATION_CODE_GROUP_NAME).resolve(from(event)); return buildAuthCodeConfig(map); } private AuthCodeConfig buildAuthCodeConfig(Map<String, Object> map) { return new AuthCodeConfig((String) map.get(CONSUMER_KEY_PARAMETER_NAME), (String) map.get(CONSUMER_SECRET_PARAMETER_NAME), (String) map.get(AUTHORIZATION_URL_PARAMETER_NAME), (String) map.get(ACCESS_TOKEN_URL_PARAMETER_NAME), (String) map.get(SCOPES_PARAMETER_NAME), (String) map.get(RESOURCE_OWNER_ID_PARAMETER_NAME), (String) map.get(BEFORE_FLOW_PARAMETER_NAME), (String) map.get(AFTER_FLOW_PARAMETER_NAME)); } private OAuthCallbackConfig buildOAuthCallbackConfig(Event event) throws MuleException { Map<String, Object> map = (Map<String, Object>) resolverSet.getResolvers().get(OAUTH_CALLBACK_GROUP_NAME).resolve(from(event)); return buildOAuthCallbackConfig(map); } private OAuthCallbackConfig buildOAuthCallbackConfig(Map<String, Object> map) { return new OAuthCallbackConfig((String) map.get(LISTENER_CONFIG_PARAMETER_NAME), (String) map.get(CALLBACK_HOST_PARAMETER_NAME), (int) map.get(CALLBACK_PORT_PARAMETER_NAME), sanitizePath((String) map.get(CALLBACK_PATH_PARAMETER_NAME)), sanitizePath((String) map.get(LOCAL_AUTHORIZE_PATH_PARAMETER_NAME))); } private Optional<OAuthObjectStoreConfig> buildOAuthObjectStoreConfig(Event event) throws MuleException { final ValueResolver resolver = resolverSet.getResolvers().get(OAUTH_STORE_CONFIG_GROUP_NAME); if (resolver == null) { return empty(); } Map<String, Object> map = (Map<String, Object>) resolver.resolve(from(event)); return map != null ? of(new OAuthObjectStoreConfig((String) map.get(OBJECT_STORE_PARAMETER_NAME))) : empty(); } private Map<Field, String> getCallbackValues() { return providerModel.getModelProperty(OAuthCallbackValuesModelProperty.class) .map(OAuthCallbackValuesModelProperty::getCallbackValues) .orElseGet(Collections::emptyMap); } private Map<String, String> getCustomParameters(ResolverSetResult result) { Map<String, String> oauthParams = new HashMap<>(); withCustomParameters((parameter, property) -> oauthParams.put(property.getRequestAlias(), result.get(parameter.getName()).toString())); return oauthParams; } private void withCustomParameters(BiConsumer<ParameterModel, OAuthParameterModelProperty> delegate) { providerModel.getAllParameterModels().forEach(parameter -> parameter.getModelProperty(OAuthParameterModelProperty.class) .ifPresent(property -> delegate.accept(parameter, property))); } private Map<String, String> getCustomParameters(Event event) { Map<String, String> oauthParams = new HashMap<>(); withCustomParameters((parameter, property) -> { String alias = property.getRequestAlias(); if (StringUtils.isBlank(alias)) { alias = parameter.getName(); } ValueResolver resolver = resolverSet.getResolvers().get(alias); if (resolver != null) { try { oauthParams.put(alias, resolveString(event, resolver)); } catch (MuleException e) { throw new MuleRuntimeException(e); } } }); return oauthParams; } private String resolveString(Event event, ValueResolver resolver) throws MuleException { Object value = resolver.resolve(from(event)); return value != null ? StringMessageUtils.toString(value) : null; } private AuthorizationCodeGrantType getGrantType() { return providerModel.getModelProperty(OAuthModelProperty.class) .map(p -> (AuthorizationCodeGrantType) p.getGrantTypes().get(0)) .get(); } private String sanitizePath(String path) { return !path.startsWith("/") ? "/" + path : path; } private OAuthConfig getInitialOAuthConfig() throws MuleException { final Event initialiserEvent = getInitialiserEvent(); MapValueResolver mapResolver = staticOnly((MapValueResolver) resolverSet.getResolvers().get(OAUTH_AUTHORIZATION_CODE_GROUP_NAME)); AuthCodeConfig authCodeConfig = buildAuthCodeConfig(mapResolver.resolve(from(initialiserEvent))); Optional<OAuthObjectStoreConfig> storeConfig = buildOAuthObjectStoreConfig(initialiserEvent); mapResolver = staticOnly((MapValueResolver) resolverSet.getResolvers().get(OAUTH_CALLBACK_GROUP_NAME)); OAuthCallbackConfig callbackConfig = buildOAuthCallbackConfig(mapResolver.resolve(from(initialiserEvent))); return new OAuthConfig(ownerConfigName, authCodeConfig, callbackConfig, storeConfig, grantType, getCustomParameters(initialiserEvent), callbackValues); } private MapValueResolver staticOnly(MapValueResolver resolver) throws MuleException { List<ValueResolver> staticKeyResolvers = new ArrayList<>(resolver.getKeyResolvers().size()); List<ValueResolver> staticValueResolvers = new ArrayList<>(resolver.getValueResolvers().size()); Iterator<ValueResolver> keyResolvers = resolver.getKeyResolvers().iterator(); Iterator<ValueResolver> valueResolvers = resolver.getValueResolvers().iterator(); while (keyResolvers.hasNext() && valueResolvers.hasNext()) { ValueResolver keyResolver = keyResolvers.next(); ValueResolver valueResolver = valueResolvers.next(); if (!keyResolver.isDynamic() && !valueResolver.isDynamic()) { staticKeyResolvers.add(keyResolver); staticValueResolvers.add(valueResolver); } } MapValueResolver result = new MapValueResolver(HashMap.class, staticKeyResolvers, staticValueResolvers, muleContext); initialiseIfNeeded(result, muleContext); return result; } }