![JAR search and dependency download from the Maven repository](/logo.png)
org.mule.security.oauth.BaseOAuthClientFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mule-module-devkit-support Show documentation
Show all versions of mule-module-devkit-support Show documentation
Interfaces and classes required by Devkit.
The newest version!
/*
* 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.security.oauth;
import org.mule.api.context.MuleContextAware;
import org.mule.api.lifecycle.Disposable;
import org.mule.api.lifecycle.Initialisable;
import org.mule.api.lifecycle.Startable;
import org.mule.api.lifecycle.Stoppable;
import org.mule.api.store.ObjectStore;
import org.mule.api.store.ObjectStoreException;
import org.mule.common.security.oauth.OAuthState;
import org.mule.common.security.oauth.exception.NotAuthorizedException;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class BaseOAuthClientFactory implements KeyedPoolableObjectFactory
{
private static transient Logger logger = LoggerFactory.getLogger(BaseOAuthClientFactory.class);
private static transient Map oauthStateProperties = new HashMap();
static
{
try
{
for (PropertyDescriptor pd : Introspector.getBeanInfo(OAuthState.class, Object.class)
.getPropertyDescriptors())
{
oauthStateProperties.put(pd.getName(), pd);
}
}
catch (IntrospectionException e)
{
throw new RuntimeException(
"Error initializing OAuthClientFactory. Could not introspect OAuthState", e);
}
}
private OAuth2Manager oauthManager;
private ObjectStore objectStore;
public BaseOAuthClientFactory(OAuth2Manager oauthManager,
ObjectStore objectStore)
{
this.oauthManager = oauthManager;
this.objectStore = objectStore;
}
/**
* Returns the class of the concrete implementation of
* {@link org.mule.security.oauth.OAuth2Adapter} that this factory is supposed to
* generate
*/
protected abstract Class extends OAuth2Adapter> getAdapterClass();
/**
* Implementors can levarage this method to move custom property values from the
* state to the adapter You can leave this method blank if not needed in your
* case.
*
* @param adapter a {@link org.mule.security.oauth.OAuth2Adapter} which supports
* custom properties
* @param state a {@link org.mule.security.oauth.OAuth2Adapter} which is carrying
* custom properties.
*/
protected abstract void setCustomAdapterProperties(OAuth2Adapter adapter, OAuthState state);
/**
* Implementos can leverage this method to move custom property values from the
* adapter to the state. You can leave this method blank if not needed in your
* case.
*
* @param adapter a {@link org.mule.security.oauth.OAuth2Adapter} which is
* carrying custom properties
* @param state a {@link org.mule.security.oauth.OAuth2Adapter}
*/
protected abstract void setCustomStateProperties(OAuth2Adapter adapter, OAuthState state);
/**
* This method creates an instance of
* {@link org.mule.security.oauth.OAuth2Adapter} which concrete type depends on
* the return of
* {@link BaseOAuthClientFactory#getAdapterClass} The
* adapter is fully initialized and interfaces such as
* {@link Initialisable},
* {@link MuleContextAware} and
* {@link Startable} are respected by invoking the
* corresponding methods in case the adapter implements them. Finally, the
* {@link OAuth2Connector#postAuth()} method is invoked.
*
* @param key the of the object at the object store
*/
@Override
public final OAuth2Adapter makeObject(String key) throws Exception
{
OAuthState state = null;
Lock lock = this.getLock(key);
lock.lock();
try
{
if (!this.objectStore.contains(key))
{
throw new NotAuthorizedException(
String.format(
"There is no access token stored under the key %s . You need to call the message processor. The key will be given to you via a flow variable after the OAuth dance is completed. You can extract it using flowVars['tokenId'].",
key));
}
state = this.retrieveOAuthState(key, true);
}
finally
{
lock.unlock();
}
OAuth2Adapter connector = this.getAdapterClass()
.getConstructor(OAuth2Manager.class)
.newInstance(this.oauthManager);
connector.setConsumerKey(oauthManager.getDefaultUnauthorizedConnector().getConsumerKey());
connector.setConsumerSecret(oauthManager.getDefaultUnauthorizedConnector().getConsumerSecret());
connector.setAccessToken(state.getAccessToken());
connector.setAuthorizationUrl(state.getAuthorizationUrl());
connector.setAccessTokenUrl(state.getAccessTokenUrl());
connector.setRefreshToken(state.getRefreshToken());
this.setCustomAdapterProperties(connector, state);
if (connector instanceof MuleContextAware)
{
((MuleContextAware) connector).setMuleContext(oauthManager.getMuleContext());
}
if (connector instanceof Initialisable)
{
((Initialisable) connector).initialise();
}
if (connector instanceof Startable)
{
((Startable) connector).start();
}
this.oauthManager.postAuth(connector, key);
return connector;
}
/**
* This method is to provide backwards compatibility with connectors generated
* using devkit 3.4.0 or lower. Those connectors used one custom OAuthState class
* per connector which disabled the possibility of token sharing. The
* {@link org.mule.common.security.oauth.OAuthState} solves that problem but
* generates a migration issues with applications using such a connector and
* wishing to upgrade. This method retrieves a value from the ObjectStore and if
* it's not a generic org.mule.common.security.oauth.OAuthState instance it
* translates it to one, generating an ongoing migration process. If
* replace
is true, then the value in the ObjectStore is replaced.
* Once Mule 3.4.0 reaches end of life status, this method can be replaced by
* simple object store lookup
*
* @param key the object store key
* @param replace if true and if the obtained value is not an instance of
* {@link org.mule.common.security.oauth.OAuthState}, then the value
* is replaced in the object store by the transformed instance
*/
private synchronized OAuthState retrieveOAuthState(String key, boolean replace)
{
Object state = null;
try
{
state = this.objectStore.retrieve(key);
}
catch (ObjectStoreException e)
{
throw new RuntimeException("Error retrieving value from object store with key " + key, e);
}
if (state != null && !(state instanceof OAuthState))
{
OAuthState newState = new OAuthState();
try
{
for (PropertyDescriptor beanProperty : Introspector.getBeanInfo(state.getClass(),
Object.class).getPropertyDescriptors())
{
Object value = beanProperty.getReadMethod().invoke(state, (Object[]) null);
if (value != null)
{
PropertyDescriptor stateProperty = oauthStateProperties.get(beanProperty.getName());
if (stateProperty != null)
{
stateProperty.getWriteMethod().invoke(newState, value);
}
else
{
newState.setCustomProperty(beanProperty.getName(), value.toString());
}
}
}
}
catch (IllegalAccessException e)
{
throw new RuntimeException("Error accessing value through reflection", e);
}
catch (IntrospectionException e)
{
throw new RuntimeException("Error introspecting object of class "
+ state.getClass().getCanonicalName(), e);
}
catch (IllegalArgumentException e)
{
throw new RuntimeException("Error setting value through reflection", e);
}
catch (InvocationTargetException e)
{
throw new RuntimeException("Object threw exception while setting value by reflection", e);
}
state = newState;
if (replace)
{
try
{
this.objectStore.remove(key);
this.objectStore.store(key, newState);
}
catch (ObjectStoreException e)
{
throw new RuntimeException("ObjectStore threw exception while replacing instance", e);
}
}
}
return (OAuthState) state;
}
/**
* If obj implements {@link org.mule.api.lifecycle.Stoppable} or
* {@link org.mule.api.lifecycle.Disposable}, the object is destroyed by invoking
* the corresponding methods
*
* @param key the key of the object at the object store
* @param obj an instance of {@link org.mule.security.oauth.OAuth2Adapter}
* @throws IllegalArgumentException if obj is not an instance of the type returned
* by {@link
* BaseOAuthClientFactory#getAdapterClass()}
*/
@Override
public final void destroyObject(String key, OAuth2Adapter obj) throws Exception
{
if (!this.getAdapterClass().isInstance(obj))
{
throw new IllegalArgumentException("Invalid connector type");
}
if (obj instanceof Stoppable)
{
((Stoppable) obj).stop();
}
if (obj instanceof Disposable)
{
((Disposable) obj).dispose();
}
}
/**
* Validates the object by checking that it exists at the object store and that
* the state of the given object is consisten with the persisted state
*
* @param key the key of the object at the object store
* @param obj an instance of {@link org.mule.security.oauth.OAuth2Adapter}
* @throws IllegalArgumentException if obj is not an instance of the type returned
* by {@link
* BaseOAuthClientFactory#getAdapterClass()}
*/
@Override
public final boolean validateObject(String key, OAuth2Adapter obj)
{
if (!this.getAdapterClass().isInstance(obj))
{
throw new IllegalArgumentException("Invalid connector type");
}
OAuth2Adapter connector = (OAuth2Adapter) obj;
Lock lock = this.getLock(key);
lock.lock();
try
{
if (!this.objectStore.contains(key))
{
return false;
}
OAuthState state = this.retrieveOAuthState(key, true);
if (connector.getAccessToken() == null)
{
return false;
}
if (!connector.getAccessToken().equals(state.getAccessToken()))
{
return false;
}
if (connector.getRefreshToken() == null && state.getRefreshToken() != null)
{
return false;
}
if (connector.getRefreshToken() != null
&& !connector.getRefreshToken().equals(state.getRefreshToken()))
{
return false;
}
}
catch (ObjectStoreException e)
{
logger.warn("Could not validate object due to object store exception", e);
return false;
}
finally
{
lock.unlock();
}
return true;
}
/**
* This default implementation does nothing
*/
@Override
public void activateObject(String key, OAuth2Adapter obj) throws Exception
{
}
/**
* Passivates the object by updating the state of the persisted object with the
* one of the given one. If the object doesn't exist in the object store then it
* is created
*
* @param key the key of the object at the object store
* @param connector an instance of {@link org.mule.security.oauth.OAuth2Adapter}
* @throws IllegalArgumentException if obj is not an instance of the type returned by {@link BaseOAuthClientFactory#getAdapterClass()}
*/
@Override
public final void passivateObject(String key, OAuth2Adapter connector) throws Exception
{
if (!this.getAdapterClass().isInstance(connector))
{
throw new IllegalArgumentException("Invalid connector type");
}
OAuthState state;
Lock lock = this.getLock(key);
lock.lock();
try
{
if (this.objectStore.contains(key))
{
state = this.retrieveOAuthState(key, false);
this.objectStore.remove(key);
}
else
{
state = new OAuthState();
}
state.setAccessToken(connector.getAccessToken());
state.setAccessTokenUrl(connector.getAccessTokenUrl());
state.setAuthorizationUrl(connector.getAuthorizationUrl());
state.setRefreshToken(connector.getRefreshToken());
this.setCustomStateProperties(connector, state);
this.objectStore.store(key, state);
}
finally
{
lock.unlock();
}
}
private Lock getLock(String key)
{
return this.oauthManager.getMuleContext()
.getLockFactory()
.createLock(String.format("OAuthTokenKeyLock-%s", key));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy