/*
* Copyright (c) 2006, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed 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.registry.info.services.utils;
import org.apache.axis2.context.MessageContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.registry.event.core.exception.EventBrokerException;
import org.wso2.carbon.registry.event.core.subscription.Subscription;
import org.wso2.carbon.registry.event.ws.internal.builders.exceptions.InvalidMessageException;
import org.wso2.carbon.registry.event.ws.internal.builders.utils.BuilderUtils;
import org.wso2.carbon.registry.common.ResourceData;
import org.wso2.carbon.registry.common.beans.SubscriptionBean;
import org.wso2.carbon.registry.common.beans.utils.SubscriptionInstance;
import org.wso2.carbon.registry.common.eventing.RegistryEvent;
import org.wso2.carbon.registry.core.ActionConstants;
import org.wso2.carbon.registry.core.RegistryConstants;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.ResourcePath;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.pagination.PaginationContext;
import org.wso2.carbon.registry.core.pagination.PaginationUtils;
import org.wso2.carbon.registry.core.session.UserRegistry;
import org.wso2.carbon.registry.core.utils.AccessControlConstants;
import org.wso2.carbon.registry.eventing.RegistryEventingConstants;
import org.wso2.carbon.registry.info.internal.InfoDataHolder;
import org.wso2.carbon.user.core.UserRealm;
import org.wso2.carbon.user.core.UserStoreException;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import java.util.*;
public class SubscriptionBeanPopulator {
private static final Log log = LogFactory.getLog(SubscriptionBeanPopulator.class);
private InfoDataHolder dataHolder = InfoDataHolder.getInstance();
public static final String RECURSE = "-R";
private static SubscriptionInstance populate(String path, Subscription subscription) {
String delimiter = null;
if (subscription.getTopicName().contains("#") || subscription.getTopicName().contains("*")) {
delimiter = subscription.getTopicName().substring(subscription.getTopicName().lastIndexOf("/") + 1);
}
return populate(path, subscription, delimiter);
}
private static SubscriptionInstance populate(String path, Subscription subscription, String delimiter) {
SubscriptionInstance subscriptionInstance = new SubscriptionInstance();
if (subscription != null) {
if (subscription.getId() == null || subscription.getTopicName() == null) {
log.error("Failed getting ID or Filter Value");
return null;
}
String[] temp = subscription.getTopicName().split(RegistryEvent.TOPIC_SEPARATOR);
String eventName = "";
if (subscription.getEventDispatcherName() != null &&
subscription.getEventDispatcherName().startsWith("/registry")) {
//handle registry subscription
if (temp[0].equals("")) {
eventName = temp[3];
} else {
eventName = temp[2];
}
} else {
//handle non registry related(ESB topic) subscription
if (temp[0].equals("")) {
eventName = temp[temp.length - 1];
} else {
eventName = temp[0];
}
}
String tempTopic = RegistryEventingConstants.TOPIC_PREFIX + RegistryEvent.TOPIC_SEPARATOR + eventName + path;
if (delimiter != null) {
if (delimiter.equals("#") || delimiter.equals("*")) {
if(tempTopic.endsWith("/")){
tempTopic = tempTopic + delimiter;
} else{
tempTopic = tempTopic + RegistryEvent.TOPIC_SEPARATOR + delimiter;
}
}
}
if (!subscription.getTopicName().equals(tempTopic)) {
log.debug("Filter name is: " + subscription.getTopicName() +
". Expected: " + RegistryEventingConstants.TOPIC_PREFIX + eventName +
RegistryEvent.TOPIC_SEPARATOR + path + ".");
return null;
}
subscriptionInstance.setId(subscription.getId());
subscriptionInstance.setAddress(subscription.getEventSinkURL());
subscriptionInstance.setTopic(subscription.getTopicName());
subscriptionInstance.setEventName(eventName);
String address = subscriptionInstance.getAddress();
if (address.startsWith("digest://")) {
subscriptionInstance.setDigestType(address.substring(9, 10));
address = address.substring(11);
} else {
subscriptionInstance.setDigestType("");
}
if (address.startsWith("mailto:")) {
subscriptionInstance.setNotificationMethod("email");
} else if (address.startsWith("user://")) {
subscriptionInstance.setNotificationMethod("username");
} else if (address.startsWith("role://")) {
subscriptionInstance.setNotificationMethod("role");
} else if (address.startsWith("jmx://")) {
subscriptionInstance.setNotificationMethod("jmx");
} else if (address.startsWith("work://")) {
subscriptionInstance.setNotificationMethod("work");
} else if (subscription.getProperties() != null &&
subscription.getProperties().get(
RegistryEventingConstants.DO_REST) != null &&
((String)subscription.getProperties().get(
RegistryEventingConstants.DO_REST)).equals(
Boolean.toString(Boolean.TRUE))) {
subscriptionInstance.setNotificationMethod("html.plain.text");
} else {
subscriptionInstance.setNotificationMethod("soap");
}
} else {
throw new IllegalStateException("A valid subscription was not present");
}
log.debug("Found subscription instance");
return subscriptionInstance;
}
public static SubscriptionBean populate(UserRegistry userRegistry, String path) {
Resource resource = null;
boolean recurse = false;
String url = null;
String userName = null;
if (!path.startsWith(SubscriptionBeanPopulator.RECURSE)) {
try {
resource = userRegistry.get(path);
} catch (Exception e) {
log.warn("Unable to fetch Resource at path: " + path);
resource = null;
}
} else {
path = path.substring(RECURSE.length());
recurse = true;
}
if (resource != null) {
String isLink = resource.getProperty("registry.link");
String mountPoint = resource.getProperty("registry.mountpoint");
String targetPoint = resource.getProperty("registry.targetpoint");
String realPath = resource.getProperty("registry.realpath");
String actualPath = resource.getProperty("registry.actualpath");
userName = resource.getProperty("registry.user");
if (isLink != null && mountPoint != null && targetPoint != null) {
// path = path.replace(mountPoint, targetPoint);
path = actualPath;
} else if (isLink != null && realPath != null && userName != null) {
log.debug("Found mounted resource at: " + realPath);
if (!realPath.contains("/registry/resourceContent?")) {
path = realPath;
} else {
boolean isLocalMount = false;
try {
isLocalMount = ResourceUtil.isLocalMount(realPath);
} catch (RegistryException e) {
log.error("Unable to check whether resource is locally mounted", e);
}
if(!isLocalMount) {
url = realPath.substring(0, realPath.indexOf("/resourceContent?path="));
}
}
}
}
SubscriptionBean subscriptionBean = new SubscriptionBean();
ResourcePath resourcePath = new ResourcePath(path);
try {
if (url == null || userName == null) {
if (InfoDataHolder.getInstance().getRegistryEventingService() == null) {
throw new IllegalStateException("Subscription Manager not found");
}
} else if (InfoDataHolder.getInstance().getRegistryEventingService() == null) {
throw new IllegalStateException("Remote Subscription Manager not found at: " + url);
}
List<Subscription> subscriptions = null;
if (url == null || userName == null) {
subscriptions = InfoDataHolder.getInstance().getRegistryEventingService().getAllSubscriptions();
} else {
try {
subscriptions = InfoDataHolder.getInstance().getRegistryEventingService().getAllSubscriptions(userName, url);
} catch(UnsupportedOperationException ex) {
log.debug("Since getAllSubscriptions(userName, url) method is unsupported getAllSubscriptions() will be called");
subscriptions = InfoDataHolder.getInstance().getRegistryEventingService().getAllSubscriptions();
}
}
log.debug("Found " + subscriptions.size() + " subscriptions");
String currentUser = userRegistry.getUserName();
List<SubscriptionInstance> subscriptionInstances = new LinkedList<SubscriptionInstance>();
for (Subscription subscription : subscriptions) {
String testPath;
if (!recurse) {
testPath = path;
} else {
testPath = subscription.getTopicName();
if (testPath == null || testPath.lastIndexOf(RegistryConstants.PATH_SEPARATOR) <= 0
|| !testPath.contains(path)) {
log.debug("path (invalid): " + testPath);
continue;
}
if(testPath.contains("#")||testPath.contains("*")){
String tempTestPath = testPath.substring(RegistryEventingConstants.TOPIC_PREFIX.length()+1,
testPath.lastIndexOf(RegistryConstants.PATH_SEPARATOR));
if(tempTestPath.contains(RegistryConstants.PATH_SEPARATOR)){
testPath =tempTestPath.split(RegistryConstants.PATH_SEPARATOR,2)[1];
}else{
testPath="/"; //only when the resource is ROOT the tempTestPath would not contain any "/"
}
}else{
testPath = (testPath.substring(RegistryEventingConstants.TOPIC_PREFIX.length()+1,testPath.length()))
.split(RegistryConstants.PATH_SEPARATOR,2)[1];
}
if(!testPath.startsWith(RegistryConstants.PATH_SEPARATOR)){
testPath=RegistryConstants.PATH_SEPARATOR+testPath;
}
}
log.debug("path: " + testPath);
String username = null;
if (subscription.getProperties() != null) {
if (subscription.getTenantId() != userRegistry.getCallerTenantId()) {
log.debug("TenantId for subscription doesn't match with the logged-in tenant");
continue;
}
username = subscription.getOwner();
if (username.indexOf("@") > 0) {
username = username.split("@")[0];
}
log.debug("Current User is: " + userRegistry.getUserName() + ". Owner of subscription is: " + username + ".");
if (username == null || !username.equals(userRegistry.getUserName())) {
if (!isAuthorized(userRegistry, testPath, AccessControlConstants.AUTHORIZE)) {
log.debug("User does not have AUTHORIZE priviledge to see this subscription");
continue;
}
} else if (!isAuthorized(userRegistry, testPath, ActionConstants.GET)) {
log.debug("User does not have GET priviledge to see this subscription");
continue;
}
}
if (currentUser != null && currentUser.equals(username)) {
SubscriptionInstance subscriptionInstance = populate(testPath, subscription);
if (subscriptionInstance != null) {
subscriptionInstance.setOwner(username);
subscriptionInstances.add(subscriptionInstance);
}
}
}
subscriptionBean.setSubscriptionInstances(subscriptionInstances.toArray(new SubscriptionInstance[0]));
log.debug("Returning " + subscriptionInstances.size() + " subscriptions");
subscriptionBean.setPathWithVersion(resourcePath.getPathWithVersion());
subscriptionBean.setVersionView(!resourcePath.isCurrentVersion());
subscriptionBean.setLoggedIn(
!RegistryConstants.ANONYMOUS_USER.equals(userRegistry.getUserName()));
subscriptionBean.setUserName(userRegistry.getUserName());
subscriptionBean.setRoles(getRolesOfUser(userRegistry, userRegistry.getUserName()));
if (isAuthorized(userRegistry, path, AccessControlConstants.AUTHORIZE)) {
subscriptionBean.setUserAccessLevel(SubscriptionBean.UserAccessLevel.AUTHORIZE);
} else if (isAuthorized(userRegistry, path, ActionConstants.DELETE)) {
subscriptionBean.setUserAccessLevel(SubscriptionBean.UserAccessLevel.DELETE);
} else if (isAuthorized(userRegistry, path, ActionConstants.GET)) {
subscriptionBean.setUserAccessLevel(SubscriptionBean.UserAccessLevel.READ);
} else {
subscriptionBean.setUserAccessLevel(SubscriptionBean.UserAccessLevel.NONE);
}
if (isAdmin(userRegistry, getRolesOfUser(userRegistry, userRegistry.getUserName()))) {
subscriptionBean.setRoleAccessLevel(1);
} else {
subscriptionBean.setRoleAccessLevel(0);
}
} catch (EventBrokerException e) {
String msg = "Failed to get subscriptions information of the resource " +
resourcePath + ". " + e.getMessage();
log.error("Failed to get subscriptions information of the resource " +
resourcePath + ".", e);
subscriptionBean.setErrorMessage(msg);
}
return getPaginatedResult(subscriptionBean);
}
private static SubscriptionBean getPaginatedResult( SubscriptionBean subscriptionBean) {
SubscriptionInstance[] paginatedResult;
MessageContext messageContext = MessageContext.getCurrentMessageContext();
if (messageContext != null && PaginationUtils.isPaginationHeadersExist(messageContext)) {
int rowCount = subscriptionBean.getSubscriptionInstances().length;
try {
PaginationUtils.setRowCount(messageContext, Integer.toString(rowCount));
PaginationContext paginationContext = PaginationUtils.initPaginationContext(messageContext);
int start = paginationContext.getStart();
int count = paginationContext.getCount();
int startIndex;
if (start == 1) {
startIndex = 0;
} else {
startIndex = start;
}
if (rowCount < start + count) {
paginatedResult = new SubscriptionInstance[rowCount - startIndex];
System.arraycopy(subscriptionBean.getSubscriptionInstances(), startIndex, paginatedResult, 0,
(rowCount - startIndex));
} else {
paginatedResult = new SubscriptionInstance[count];
System.arraycopy(subscriptionBean.getSubscriptionInstances(), startIndex, paginatedResult, 0,
count);
}
subscriptionBean.setSubscriptionInstances(paginatedResult);
return subscriptionBean;
} finally {
PaginationContext.destroy();
}
}else {
return subscriptionBean;
}
}
public static SubscriptionBean subscribeAndPopulate(UserRegistry userRegistry, String path, String endpoint, String eventName) {
return subscribeAndPopulate(userRegistry, path, endpoint, eventName, false);
}
public static boolean isAuthorized(UserRegistry userRegistry, String path, String action) {
try {
UserRealm realm = userRegistry.getUserRealm();
if (realm.getAuthorizationManager() != null) {
return realm.getAuthorizationManager().isUserAuthorized(userRegistry.getUserName(), path, action);
}
return false;
} catch (UserStoreException e) {
return false;
}
}
public static String[] getRolesOfUser(UserRegistry userRegistry, String username) {
try {
UserRealm realm = userRegistry.getUserRealm();
if (realm.getUserStoreManager() != null) {
return realm.getUserStoreManager().getRoleListOfUser(username);
}
return new String[0];
} catch (UserStoreException e) {
return new String[0];
}
}
public static boolean isAdmin(UserRegistry userRegistry, String[] rolesOfUser) {
try {
UserRealm realm = userRegistry.getUserRealm();
if (realm.getRealmConfiguration() != null) {
String adminRole = realm.getRealmConfiguration().getAdminRoleName();
return Arrays.asList(rolesOfUser).contains(adminRole);
}
return false;
} catch (UserStoreException e) {
return false;
}
}
private static boolean hasPermissionToSubscribeViaEmail(UserRegistry userRegistry, String path, String endpoint) {
if (endpoint != null) {
String address = endpoint;
if (address.toLowerCase().startsWith("digest://")) {
address = address.substring(11);
}
if (address.toLowerCase().startsWith("role://")) {
String roleToSubscribe = address.substring(7).trim();
String[] rolesOfUser = getRolesOfUser(userRegistry, userRegistry.getUserName());
return Arrays.asList(rolesOfUser).contains(roleToSubscribe) ||
isAdmin(userRegistry, rolesOfUser);
}
}
return true;
}
public static SubscriptionBean subscribeAndPopulate(UserRegistry userRegistry, String path, String endpoint, String eventName, boolean doRest) {
SubscriptionBean subscriptionBean = new SubscriptionBean();
Resource resource = null;
String url = null;
String userName = null;
String delimiter="";
String[] temp = path.split("/");
if (path.lastIndexOf("/") != 0) {
path = path.substring(0, path.lastIndexOf("/"));
if (temp != null && temp.length != 0) {
if (temp[temp.length - 1].equals("#") || temp[temp.length - 1].equals("*")) {
delimiter = temp[temp.length - 1];
} else {
if (!path.endsWith("/")) {
path = path + "/" + temp[temp.length - 1];
}
}
}
} else {
if (path.contains("*") || path.contains("#")) {
path = path.substring(0, path.length() - 1);
if (temp != null && temp.length != 0) {
if (temp[temp.length - 1].equals("#") || temp[temp.length - 1].equals("*")) {
delimiter = temp[temp.length - 1];
}
}
}
}
try {
resource = userRegistry.get(path);
} catch (Exception e) {
log.warn("Unable to fetch Resource at path: " + path);
resource = null;
}
if (resource != null) {
String isLink = resource.getProperty("registry.link");
String mountPoint = resource.getProperty("registry.mountpoint");
String targetPoint = resource.getProperty("registry.targetpoint");
String realPath = resource.getProperty("registry.realpath");
String actualPath = resource.getProperty("registry.actualpath");
userName = resource.getProperty("registry.user");
if (isLink != null && mountPoint != null && targetPoint != null) {
// path = path.replace(mountPoint, targetPoint);
path = actualPath;
} else if (isLink != null && realPath != null && userName != null) {
log.debug("Found mounted resource at: " + realPath);
if (!realPath.contains("/registry/resourceContent?")) {
path = realPath;
} else {
boolean isLocalMount = false;
try {
isLocalMount = ResourceUtil.isLocalMount(realPath);
} catch (RegistryException e) {
log.error("Unable to check whether resource is locally mounted", e);
}
if(!isLocalMount) {
url = realPath.substring(0, realPath.indexOf("/resourceContent?path="));
}
}
}
}
ResourcePath resourcePath = new ResourcePath(path);
try {
subscriptionBean.setLoggedIn(!RegistryConstants.ANONYMOUS_USER.equals(userRegistry.getUserName()));
List<SubscriptionInstance> subscriptionInstances = new LinkedList<SubscriptionInstance>();
if (!subscriptionBean.getLoggedIn()) {
throw new SecurityException("User is not logged in");
} else if (!isAuthorized(userRegistry, path, ActionConstants.GET)) {
throw new SecurityException("User does not have enough priviledges to subscribe");
} else if (!hasPermissionToSubscribeViaEmail(userRegistry, path, endpoint)) {
throw new SecurityException("User does not have enough priviledges to subscribe another user");
} else if (InfoDataHolder.getInstance().getRegistryEventingService() == null) {
throw new IllegalStateException("Registry Eventing Service Not Found");
} else {
String topic = RegistryEventingConstants.TOPIC_PREFIX + RegistryEvent.TOPIC_SEPARATOR + eventName + path;
if (delimiter.equals("#") || delimiter.equals("*")) {
if (topic.endsWith("/")) {
topic = topic + delimiter;
} else {
topic = topic + RegistryEvent.TOPIC_SEPARATOR + delimiter;
}
}
Subscription subscription =
BuilderUtils.createSubscription(endpoint,
"http://wso2.org/registry/eventing/dialect/topicFilter", topic);
subscription.setEventDispatcherName(RegistryEventingConstants.TOPIC_PREFIX);
int callerTenantId = userRegistry.getCallerTenantId();
subscription.setTenantId(callerTenantId);
String name = userRegistry.getUserName();
if (callerTenantId != MultitenantConstants.SUPER_TENANT_ID &&
callerTenantId > -1) {
try {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext currentContext =
PrivilegedCarbonContext.getThreadLocalCarbonContext();
currentContext.setTenantId(callerTenantId, true);
String tenantDomain = currentContext.getTenantDomain();
if (tenantDomain != null &&
!tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) {
name = name + "@" + tenantDomain;
}
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
subscription.setOwner(name);
Map<String, String> data = new HashMap<String, String>();
if (doRest) {
data.put(RegistryEventingConstants.DO_REST, Boolean.toString(Boolean.TRUE));
}
subscription.setProperties(data);
String subscriptionId;
if (url == null || userName == null) {
subscriptionId =
InfoDataHolder.getInstance().getRegistryEventingService().subscribe(subscription);
} else {
throw new UnsupportedOperationException("You cannot directly subscribe to a " +
"Remote Resource. Use the Registry Browser User Interface to add a " +
"Remote Subscription.");
}
if (subscriptionId == null) {
throw new IllegalStateException("Subscription Id invalid");
}
subscription.setId(subscriptionId);
SubscriptionInstance subscriptionInstance = populate(path,subscription,delimiter);
if (subscriptionInstance != null) {
subscriptionInstance.setOwner(userRegistry.getUserName());
subscriptionInstances.add(subscriptionInstance);
}
}
subscriptionBean.setSubscriptionInstances(subscriptionInstances.toArray(new SubscriptionInstance[0]));
subscriptionBean.setPathWithVersion(resourcePath.getPathWithVersion());
subscriptionBean.setVersionView(!resourcePath.isCurrentVersion());
subscriptionBean.setUserName(userRegistry.getUserName());
subscriptionBean.setRoles(getRolesOfUser(userRegistry, userRegistry.getUserName()));
if (isAuthorized(userRegistry, path, AccessControlConstants.AUTHORIZE)) {
subscriptionBean.setUserAccessLevel(SubscriptionBean.UserAccessLevel.AUTHORIZE);
} else if (isAuthorized(userRegistry, path, ActionConstants.DELETE)) {
subscriptionBean.setUserAccessLevel(SubscriptionBean.UserAccessLevel.DELETE);
} else if (isAuthorized(userRegistry, path, ActionConstants.GET)) {
subscriptionBean.setUserAccessLevel(SubscriptionBean.UserAccessLevel.READ);
} else {
subscriptionBean.setUserAccessLevel(SubscriptionBean.UserAccessLevel.NONE);
}
if (isAdmin(userRegistry, getRolesOfUser(userRegistry, userRegistry.getUserName()))) {
subscriptionBean.setRoleAccessLevel(1);
} else {
subscriptionBean.setRoleAccessLevel(0);
}
} catch (RuntimeException e) {
String msg = "Failed to subscribe to information of the resource " +
resourcePath + ". " + e.getMessage();
log.error("Failed to subscribe to information of the resource " +
resourcePath + ".", e);
subscriptionBean.setErrorMessage(msg);
} catch (InvalidMessageException e) {
String msg = "Failed to subscribe to information of the resource " +
resourcePath + ". " + e.getMessage();
log.error("Failed to subscribe to information of the resource " +
resourcePath + ".", e);
subscriptionBean.setErrorMessage(msg);
}
return subscriptionBean;
}
}