/*
* Copyright (c) 2013, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.identity.oauth.callback;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.identity.oauth.config.OAuthCallbackHandlerMetaData;
import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
import org.wso2.carbon.utils.CarbonUtils;
import javax.security.auth.callback.Callback;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
/**
* This is used to maintain the list of OAuthCallback Handlers registered in the system. It handles
* <Code>OAuthCallbackHandler</Code>, etc which are called during the OAuth token
* issuance process.
*/
public class OAuthCallbackHandlerRegistry {
private static Log log = LogFactory.getLog(OAuthCallbackHandlerRegistry.class);
private static OAuthCallbackHandlerRegistry instance;
private transient boolean initAuthzHandlers = false;
private OAuthCallbackHandler[] authzCallbackHandlers;
private OAuthCallbackHandlerRegistry() throws IdentityOAuth2Exception {
initAuthzCallbackHandlers();
}
public static OAuthCallbackHandlerRegistry getInstance() throws IdentityOAuth2Exception {
CarbonUtils.checkSecurity();
if (instance == null) {
synchronized (OAuthCallbackHandlerRegistry.class) {
if (instance == null) {
instance = new OAuthCallbackHandlerRegistry();
}
}
}
return instance;
}
/**
* Initialize the OAuthAuthorizationCallbackHandlers. This is a one-time operation.
*
* @throws IdentityOAuth2Exception Error when instantiating the
* OAuthCallbackHandler instances
*/
private void initAuthzCallbackHandlers() throws IdentityOAuth2Exception {
if (!initAuthzHandlers) {
synchronized (this) {
if (!initAuthzHandlers) {
if (log.isDebugEnabled()) {
log.debug("initializing the OAuth Authorization Callback Handlers.");
}
List<OAuthCallbackHandler> oauthAuthzHandlers = new ArrayList<>();
Set<OAuthCallbackHandlerMetaData> callbackHandlerMetaData =
OAuthServerConfiguration.getInstance().getCallbackHandlerMetaData();
// create an object of each OAuthCallbackHandler registered.
for (OAuthCallbackHandlerMetaData metaData : callbackHandlerMetaData) {
String className = metaData.getClassName();
Class clazz;
OAuthCallbackHandler callbackHandler;
try {
clazz = Thread.currentThread().getContextClassLoader().loadClass(metaData.getClassName());
callbackHandler = (OAuthCallbackHandler) clazz.newInstance();
callbackHandler.setPriority(metaData.getPriority());
callbackHandler.setProperties(metaData.getProperties());
oauthAuthzHandlers.add(callbackHandler);
if (log.isDebugEnabled()) {
log.debug("Instantiated an OAuth Authorization Callback Handler. Class : " + clazz
.getName());
}
} catch (ClassNotFoundException e) {
throw new IdentityOAuth2Exception("Error when loading the OAuthCallbackHandler : " +
className, e);
} catch (InstantiationException | IllegalAccessException e) {
throw new IdentityOAuth2Exception("Error when instantiating the OAuthCallbackHandler : "
+ className, e);
}
}
if (log.isDebugEnabled()) {
log.debug("Finished initializing OAuth Authorization Callback Handlers. No. of Authz Handlers" +
" registered : " + oauthAuthzHandlers.size());
}
authzCallbackHandlers = oauthAuthzHandlers.toArray(
new OAuthCallbackHandler[oauthAuthzHandlers.size()]);
// sort the OAuth Authorization Handlers based on priorities.
Arrays.sort(authzCallbackHandlers, new OAuthAuthzCbHandlerComparator());
initAuthzHandlers = true;
}
}
}
}
/**
* Get the appropriate <Code>OAuthCallbackHandler</Code> for the given callback
*
* @param authzCallback <Code>OAuthCallback</Code> object
* @return <Code>OAuthCallbackHandler</Code> instance which can handle the
* given callback, return <Code>null</Code> if there is no OAuthCallbackHandler which
* can handle the given callback
* @throws IdentityOAuth2Exception Error while evaluating the canHandle method
*/
public OAuthCallbackHandler getOAuthAuthzHandler(
OAuthCallback authzCallback) throws IdentityOAuth2Exception {
for (OAuthCallbackHandler oauthAuthzCbHandler : authzCallbackHandlers) {
if (oauthAuthzCbHandler.canHandle(new Callback[]{authzCallback})) {
if (log.isDebugEnabled()) {
log.debug("OAuthCallbackHandler was found for the callback. Class Name : " + oauthAuthzCbHandler
.getClass().getName() + " Resource Owner : " + authzCallback.getResourceOwner() + " " +
"Client Id : " + authzCallback.getClient() + " Scope : " + OAuth2Util.buildScopeString
(authzCallback.getRequestedScope()));
}
return oauthAuthzCbHandler;
}
}
if (log.isDebugEnabled()) {
log.debug("No OAuthAuthorizationCallbackHandlers were found for the callback. Resource Owner : " +
authzCallback.getResourceOwner() + " Client Id : " + authzCallback.getClient() + " Scope : " +
OAuth2Util.buildScopeString(authzCallback.getRequestedScope()));
}
return null;
}
/**
* Comparator for OAuthCallbackHandler based on their priority.
*/
private class OAuthAuthzCbHandlerComparator implements Comparator<OAuthCallbackHandler> {
@Override
public int compare(OAuthCallbackHandler o1, OAuthCallbackHandler o2) {
return o1.getPriority() - o2.getPriority();
}
}
}