org.openanzo.activemq.internal.SecurityBroker.java Source code

Java tutorial

Introduction

Here is the source code for org.openanzo.activemq.internal.SecurityBroker.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2007 IBM Corporation,Cambridge Semantics Incorporated and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * File:        $Source: /cvsroot/slrp/boca/com.ibm.adtech.boca.model/src/com/ibm/adtech/boca/model/security/activemq/BocaAuthenticationBroker.java,v $
 * Created by:  Matthew Roy ( <a href="mailto:mroy@us.ibm.com">mroy@us.ibm.com </a>)
 * Created on:  Oct 4, 2006
 * Revision:   $Id: AuthenticationBroker.java 180 2007-07-31 14:24:13Z mroy $
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Cambridge Semantics Incorporated - Fork to Anzo
 *******************************************************************************/
package org.openanzo.activemq.internal;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArraySet;

import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerFilter;
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.broker.ProducerBrokerExchange;
import org.apache.activemq.broker.region.Destination;
import org.apache.activemq.broker.region.Subscription;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.command.ActiveMQTempDestination;
import org.apache.activemq.command.ConnectionInfo;
import org.apache.activemq.command.ConsumerInfo;
import org.apache.activemq.command.Message;
import org.apache.activemq.command.ProducerInfo;
import org.apache.activemq.security.SecurityContext;
import org.apache.commons.collections15.BidiMap;
import org.apache.commons.collections15.bidimap.DualHashBidiMap;
import org.openanzo.cache.ICacheProvider;
import org.openanzo.datasource.IDatasource;
import org.openanzo.datasource.IDatasourceListener;
import org.openanzo.exceptions.AnzoException;
import org.openanzo.exceptions.ExceptionConstants;
import org.openanzo.exceptions.LogUtils;
import org.openanzo.exceptions.Messages;
import org.openanzo.rdf.Constants;
import org.openanzo.rdf.URI;
import org.openanzo.rdf.Constants.COMBUS;
import org.openanzo.rdf.Constants.NAMESPACES;
import org.openanzo.rdf.utils.SerializationConstants;
import org.openanzo.rdf.utils.UriGenerator;
import org.openanzo.services.AnzoPrincipal;
import org.openanzo.services.IAuthenticationService;
import org.openanzo.services.IOperationContext;
import org.openanzo.services.Privilege;
import org.openanzo.services.impl.BaseOperationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

/**
 * SecurityBroker that provides Anzo authentication and authorization to a ActiveMQ broker.
 * 
 * @author Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com </a>)
 * 
 */
class SecurityBroker extends BrokerFilter implements IDatasourceListener {

    private static final Logger log = LoggerFactory.getLogger(SecurityBroker.class);

    private final IAuthenticationService authenticationService;

    private final List<ServerSecurityContext> securityContexts = Collections
            .synchronizedList(new ArrayList<ServerSecurityContext>());

    private final Map<String, ServerSecurityContext> userSecurityContextMap = Collections
            .synchronizedMap(new HashMap<String, ServerSecurityContext>());

    private final Map<String, Set<ConnectionContext>> userConnection = Collections
            .synchronizedMap(new HashMap<String, Set<ConnectionContext>>());

    private final BidiMap<String, URI> idToUser = new DualHashBidiMap<String, URI>();

    private final Vector<String> connections = new Vector<String>();

    private static final String ADD_CONNECTION = "addConnection";

    private static final String ADD_CONSUMER = "addConsumer";

    private static final String ADD_PRODUCER = "addProducer";

    private static final String SEND_MESSAGE = "sendMessage";

    private static final String HANDLE_ACLS_UPDATE = "handleAclUpdate";

    private final HashSet<String> serverQueueNames = new HashSet<String>();

    private final AnzoPrincipal principal;

    private IDatasource primaryDatasource = null;

    private Timer timer = new Timer(true);

    private TimerTask sweaperTask = null;

    /**
     * Create a new AuthenticationBroker
     * 
     * @param next
     *            activemq broker
     * @throws AnzoException
     */
    protected SecurityBroker(Broker next, IAuthenticationService authenticationService,
            ICacheProvider cacheProvider, String userName, String password) throws AnzoException {
        super(next);
        this.authenticationService = authenticationService;
        principal = authenticationService.authenticateUser(
                new BaseOperationContext("StartSecurityBroker", BaseOperationContext.generateOperationId(), null),
                userName, password);
        serverQueueNames.add(COMBUS.NOTIFICATION_UPDATES_QUEUE);
        serverQueueNames.add(COMBUS.TRANSACTIONS_TOPIC);
        sweaperTask = new TimerTask() {
            @Override
            public void run() {
                purgeTopics();
            }
        };
        timer.schedule(sweaperTask, 1000 * 10 * 60, 1000 * 10 * 60);
    }

    private void purgeTopics() {
        try {
            for (Map.Entry<ActiveMQDestination, Destination> entry : SecurityBroker.this.next.getDestinationMap()
                    .entrySet()) {
                if (entry.getKey().getPhysicalName().startsWith(NAMESPACES.NAMEDGRAPH_TOPIC_PREFIX)) {
                    if (entry.getValue().getConsumers().size() == 0) {
                        SecurityBroker.this.next.removeDestination(getAdminConnectionContext(), entry.getKey(),
                                1000);
                    }
                }
            }
        } catch (NullPointerException npe) {
            //Needed to handle activemq bug
        } catch (Exception e) {
            log.warn(LogUtils.COMBUS_MARKER, Messages.getString(ExceptionConstants.COMBUS.ERROR_PURGING_TOPICS), e);
        }
    }

    public void setDatasource(IDatasource datasource) {
        if (this.primaryDatasource != null && datasource != null && !primaryDatasource.equals(datasource)) {
            this.primaryDatasource.unregisterDatasourceListener(this);
        }
        this.primaryDatasource = datasource;
        if (this.primaryDatasource != null) {
            this.primaryDatasource.registerDatasourceListener(this);
        }
    }

    public void resetStarting() throws AnzoException {
    }

    public void reset() throws AnzoException {
        purgeTopics();
    }

    public void resetFinished() throws AnzoException {
        refresh();
        userSecurityContextMap.clear();
    }

    public void postReset() throws AnzoException {
    }

    void connect() throws AnzoException {
    }

    @Override
    public void addConnection(ConnectionContext connectionContext, ConnectionInfo info) throws Exception {
        if (connectionContext.getSecurityContext() == null) {
            IOperationContext context = null;
            try {
                context = new BaseOperationContext(ADD_CONNECTION, info.getConnectionId().toString(), principal);
                context.setMDC();
                AnzoPrincipal principal = authenticationService.authenticateUser(context, info.getUserName(),
                        info.getPassword());
                if (principal != null) {
                    idToUser.put(info.getUserName(), principal.getUserURI());
                    ServerSecurityContext securityContext = userSecurityContextMap.get(principal.getName());
                    if (securityContext == null) {
                        securityContext = new ServerSecurityContext(principal);
                        userSecurityContextMap.put(principal.getName(), securityContext);
                        securityContexts.add(securityContext);
                    }
                    connectionContext.setSecurityContext(securityContext);
                    Set<ConnectionContext> conns = userConnection.get(info.getUserName());
                    if (conns == null) {
                        conns = new CopyOnWriteArraySet<ConnectionContext>();
                        userConnection.put(info.getUserName(), conns);
                    }
                    conns.add(connectionContext);
                    connectionContext.setProducerFlowControl(false);
                } else {
                    MDC.put(LogUtils.REMOTE_ADDRESS, connectionContext.getConnection().getRemoteAddress());
                    MDC.put(LogUtils.USER, info.getUserName());
                    String errorMsg = Messages.getString(ExceptionConstants.COMBUS.ERROR_LOGGING_IN);
                    log.error(LogUtils.SECURITY_MARKER, errorMsg);
                    MDC.clear();
                    throw new SecurityException(errorMsg);
                }
            } finally {
                if (context != null) {
                    context.clearMDC();
                }
            }
        }
        connections.add(info.getConnectionId().getValue());
        super.addConnection(connectionContext, info);
    }

    @Override
    public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception {
        super.removeConnection(context, info, error);

        Set<ConnectionContext> conns = userConnection.get(info.getUserName());
        if (conns != null) {
            conns.remove(context);
        }
        connections.remove(info.getConnectionId().getValue());
        if (!userSecurityContextMap.values().contains(context.getSecurityContext())) {
            securityContexts.remove(context.getSecurityContext());
        }
    }

    /**
     * Previously logged in users may no longer have the same access anymore. Refresh all the logged into users.
     */
    private void refresh() {
        for (SecurityContext sc : securityContexts) {
            sc.getAuthorizedReadDests().clear();
            sc.getAuthorizedWriteDests().clear();
        }
    }

    @Override
    public void removeDestination(ConnectionContext context, ActiveMQDestination destination, long timeout)
            throws Exception {
        final ServerSecurityContext securityContext = (ServerSecurityContext) context.getSecurityContext();
        if (securityContext == null) {
            MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
            String errorMsg = Messages.formatString(ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED,
                    context.getConnectionId().toString());
            log.error(LogUtils.SECURITY_MARKER, errorMsg);
            MDC.clear();
            throw new SecurityException(errorMsg);
        }
        // You don't need to be an admin to remove temp destinations.
        if (!destination.isTemporary()) {
            if (destination.getPhysicalName().startsWith("services/")) {
                if (!securityContext.getAnzoPrincipal().isSysadmin()) {
                    MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
                    MDC.put(LogUtils.USER, securityContext.getAnzoPrincipal().getName());
                    String errorMsg = Messages.formatString(
                            ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED,
                            securityContext.getUserName(), "remove", destination.toString());
                    log.info(LogUtils.SECURITY_MARKER, errorMsg);
                    MDC.clear();
                    throw new SecurityException(errorMsg);
                }
            } else if (destination.getPhysicalName().startsWith(NAMESPACES.NAMEDGRAPH_TOPIC_PREFIX)) {

            } else if (destination.getPhysicalName().startsWith(NAMESPACES.STREAM_TOPIC_PREFIX)) {

            }
        } else {
            if (!((ActiveMQTempDestination) destination).getConnectionId()
                    .equals(context.getConnectionId().getValue())) {
                MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
                MDC.put(LogUtils.USER, securityContext.getAnzoPrincipal().getName());
                String errorMsg = Messages.formatString(
                        ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED, securityContext.getUserName(),
                        "remove", destination.toString());
                log.info(LogUtils.SECURITY_MARKER, errorMsg);
                MDC.clear();
                throw new SecurityException(errorMsg);
            }
        }
        super.removeDestination(context, destination, timeout);
    }

    @Override
    public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) throws Exception {
        //   resetlock.readLock().lock();
        //   try {
        final ServerSecurityContext subject = (ServerSecurityContext) context.getSecurityContext();
        if (subject == null) {
            MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
            String errorMsg = "Connection is not authenticated:" + context.getClientId();
            log.error(LogUtils.SECURITY_MARKER, errorMsg);
            MDC.clear();
            throw new SecurityException(errorMsg);
        }
        if (!subject.getAuthorizedReadDests().containsKey(info.getDestination())) {
            if (info.getDestination().getPhysicalName().startsWith("services/")) {
                if (!subject.getAnzoPrincipal().isSysadmin()) {
                    MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
                    MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                    String errorMsg = Messages.formatString(
                            ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED, subject.getUserName(),
                            "read", info.getDestination().toString());
                    log.info(LogUtils.SECURITY_MARKER, errorMsg);
                    MDC.clear();
                    throw new SecurityException(errorMsg);
                }
            } else if (info.getDestination().isTemporary() && !((ActiveMQTempDestination) info.getDestination())
                    .getConnectionId().equals(context.getConnectionId().getValue())) {
                MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
                MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                String errorMsg = Messages.formatString(
                        ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED, subject.getUserName(), "read",
                        info.getDestination().toString());
                log.info(LogUtils.SECURITY_MARKER, errorMsg);
                MDC.clear();
                throw new SecurityException(errorMsg);
            } else {
                IOperationContext opContext = null;
                try {
                    String destinationName = info.getDestination().getPhysicalName();
                    if (destinationName.startsWith(NAMESPACES.NAMEDGRAPH_TOPIC_PREFIX)
                            || destinationName.startsWith(NAMESPACES.STREAM_TOPIC_PREFIX)) {
                        opContext = new BaseOperationContext(ADD_CONSUMER, context.getConnectionId().toString(),
                                principal);
                        opContext.setMDC();
                        if (!subject.getAnzoPrincipal().isSysadmin()) {
                            if (primaryDatasource == null) {
                                MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
                                MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                                String logMsg = Messages
                                        .formatString(ExceptionConstants.COMBUS.ERROR_SERVER_NOT_READY);
                                log.warn(LogUtils.COMBUS_MARKER, logMsg);
                                MDC.clear();
                                throw new SecurityException(logMsg);
                            }
                            String namedGraphUUIDUri = null;
                            if (destinationName.startsWith(NAMESPACES.NAMEDGRAPH_TOPIC_PREFIX)) {
                                namedGraphUUIDUri = UriGenerator.stripEncapsulatedString(
                                        NAMESPACES.NAMEDGRAPH_TOPIC_PREFIX, destinationName);
                            } else {
                                namedGraphUUIDUri = UriGenerator
                                        .stripEncapsulatedString(NAMESPACES.STREAM_TOPIC_PREFIX, destinationName);
                            }
                            URI namedGraphUri = null;
                            try {
                                namedGraphUri = primaryDatasource.getModelService().getUriForUUID(opContext,
                                        Constants.valueFactory.createURI(namedGraphUUIDUri));
                            } catch (AnzoException e) {
                                String logMsg = Messages.formatString(
                                        ExceptionConstants.DATASOURCE.NAMEDGRAPH.GRAPH_NOT_VALID,
                                        namedGraphUUIDUri);
                                log.debug(LogUtils.DATASOURCE_MARKER, logMsg, e);
                                throw new SecurityException(logMsg, e);
                            }
                            if (namedGraphUri == null) {
                                String logMsg = Messages.formatString(
                                        ExceptionConstants.DATASOURCE.NAMEDGRAPH.GRAPH_NOT_VALID,
                                        namedGraphUUIDUri);
                                log.debug(LogUtils.DATASOURCE_MARKER, logMsg);
                                throw new SecurityException(logMsg);
                            }
                            Set<URI> roles = primaryDatasource.getAuthorizationService().getRolesForGraph(opContext,
                                    namedGraphUri, Privilege.READ);
                            if (!org.openanzo.rdf.utils.Collections.memberOf(roles,
                                    subject.getAnzoPrincipal().getRoles())) {
                                MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
                                MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                                String errorMsg = Messages.formatString(
                                        ExceptionConstants.COMBUS.NOT_AUTHORIZED_FOR_TOPIC, subject.getUserName(),
                                        "read", info.getDestination().toString());
                                log.info(LogUtils.SECURITY_MARKER, errorMsg);
                                MDC.clear();
                                throw new SecurityException(errorMsg);
                            }
                        }
                    }
                } finally {
                    if (opContext != null) {
                        opContext.clearMDC();
                    }
                }
            }
            subject.getAuthorizedReadDests().put(info.getDestination(), info.getDestination());
        }
        return super.addConsumer(context, info);
    }

    @Override
    public void removeConsumer(ConnectionContext context, ConsumerInfo info) throws Exception {
        super.removeConsumer(context, info);
        if (info.getDestination().getPhysicalName().startsWith(NAMESPACES.NAMEDGRAPH_TOPIC_PREFIX)) {
            Set<Destination> dests = next.getDestinations(info.getDestination());
            if (dests != null) {
                for (Destination dest : dests) {
                    if (dest.getConsumers().size() == 0) {
                        //                       dest.dispose(getAdminConnectionContext());
                    }
                }
            }
        }
    }

    @Override
    public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception {
        final ServerSecurityContext subject = (ServerSecurityContext) context.getSecurityContext();
        if (subject == null) {
            MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
            String errorMsg = Messages.formatString(ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED,
                    context.getConnectionId().toString());
            log.error(LogUtils.SECURITY_MARKER, errorMsg);
            MDC.clear();
            throw new SecurityException(errorMsg);
        }
        if (info.getDestination() != null) {
            if (serverQueueNames.contains(info.getDestination().getPhysicalName())) {
                if (!subject.getAnzoPrincipal().isSysadmin()) {
                    MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
                    MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                    String errorMsg = Messages.formatString(
                            ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED, subject.getUserName(),
                            "write", info.getDestination().toString());

                    log.info(LogUtils.SECURITY_MARKER, errorMsg);
                    MDC.clear();
                    throw new SecurityException(errorMsg);
                }
            } else if (info.getDestination().isTemporary()) {
                if (!subject.getAnzoPrincipal().isSysadmin()) {
                    MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
                    MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                    String errorMsg = Messages.formatString(
                            ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED, subject.getUserName(),
                            "write", info.getDestination().toString());
                    log.info(LogUtils.SECURITY_MARKER, errorMsg);
                    MDC.clear();
                    throw new SecurityException(errorMsg);
                }
            } else if (info.getDestination().getPhysicalName().startsWith(NAMESPACES.NAMEDGRAPH_TOPIC_PREFIX)) {
                if (!subject.getAnzoPrincipal().isSysadmin()) {
                    MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
                    MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                    String errorMsg = Messages.formatString(
                            ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED, subject.getUserName(),
                            "write", info.getDestination().toString());
                    log.info(LogUtils.SECURITY_MARKER, errorMsg);
                    MDC.clear();
                    throw new SecurityException(errorMsg);
                }
            } else if (info.getDestination().getPhysicalName().startsWith(NAMESPACES.STREAM_TOPIC_PREFIX)) {
                if (primaryDatasource == null) {
                    String logMsg = Messages.formatString(ExceptionConstants.COMBUS.ERROR_SERVER_NOT_READY);
                    log.warn(LogUtils.COMBUS_MARKER, logMsg);
                    throw new SecurityException(logMsg);
                }
                IOperationContext opContext = null;
                try {
                    opContext = new BaseOperationContext(ADD_PRODUCER, context.getConnectionId().toString(),
                            principal);
                    opContext.setMDC();
                    if (!subject.getAnzoPrincipal().isSysadmin()) {
                        String namedGraphUUIDUri = UriGenerator.stripEncapsulatedString(
                                NAMESPACES.STREAM_TOPIC_PREFIX, info.getDestination().getPhysicalName());
                        URI namedGraphUri = null;
                        try {
                            namedGraphUri = primaryDatasource.getModelService().getUriForUUID(opContext,
                                    Constants.valueFactory.createURI(namedGraphUUIDUri));
                        } catch (AnzoException e) {
                            String logMsg = Messages.formatString(
                                    ExceptionConstants.DATASOURCE.NAMEDGRAPH.GRAPH_NOT_VALID, namedGraphUUIDUri);
                            log.debug(LogUtils.DATASOURCE_MARKER, logMsg, e);
                            throw new SecurityException(logMsg, e);
                        }
                        if (namedGraphUri == null) {
                            String logMsg = Messages.formatString(
                                    ExceptionConstants.DATASOURCE.NAMEDGRAPH.GRAPH_NOT_VALID, namedGraphUUIDUri);
                            log.debug(LogUtils.DATASOURCE_MARKER, logMsg);
                            throw new SecurityException(logMsg);
                        }
                        Set<URI> roles = primaryDatasource.getAuthorizationService().getRolesForGraph(opContext,
                                namedGraphUri, Privilege.ADD);
                        if (!org.openanzo.rdf.utils.Collections.memberOf(roles,
                                subject.getAnzoPrincipal().getRoles())) {
                            MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
                            MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                            String errorMsg = Messages.formatString(
                                    ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED,
                                    subject.getUserName(), "write", info.getDestination().toString());
                            log.info(LogUtils.SECURITY_MARKER, errorMsg);
                            MDC.clear();
                            throw new SecurityException(errorMsg);
                        }
                    }
                } finally {
                    if (opContext != null) {
                        opContext.clearMDC();
                    }
                }
            } else if (info.getDestination().getPhysicalName().startsWith("services/")) {
                Set<Destination> dests = next.getDestinations(info.getDestination());
                if (dests == null || dests.size() == 0) {
                    MDC.put(LogUtils.REMOTE_ADDRESS, context.getConnection().getRemoteAddress());
                    MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                    String errorMsg = Messages.formatString(ExceptionConstants.COMBUS.ERROR_TOPIC_NOT_EXIST_YET,
                            subject.getUserName(), info.getDestination().toString());
                    log.info(LogUtils.SECURITY_MARKER, errorMsg);
                    MDC.clear();
                    throw new SecurityException(errorMsg);
                }
            }
            subject.getAuthorizedWriteDests().put(info.getDestination(), info.getDestination());
        }
        super.addProducer(context, info);
    }

    @Override
    public void send(ProducerBrokerExchange exchange, Message messageSend) throws Exception {
        final ServerSecurityContext subject = (ServerSecurityContext) exchange.getConnectionContext()
                .getSecurityContext();
        if (subject == null) {
            MDC.put(LogUtils.REMOTE_ADDRESS, exchange.getConnectionContext().getConnection().getRemoteAddress());
            String errorMsg = Messages.formatString(ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED,
                    exchange.getConnectionContext().getConnectionId().toString());
            log.error(LogUtils.SECURITY_MARKER, errorMsg);
            MDC.clear();
            throw new SecurityException(errorMsg);
        }
        if (!subject.getAuthorizedWriteDests().contains(messageSend.getDestination())) {
            if (serverQueueNames.contains(messageSend.getDestination().getPhysicalName()) || messageSend
                    .getDestination().getPhysicalName().startsWith(NAMESPACES.NAMEDGRAPH_TOPIC_PREFIX)) {
                if (!subject.getAnzoPrincipal().isSysadmin()) {
                    MDC.put(LogUtils.REMOTE_ADDRESS,
                            exchange.getConnectionContext().getConnection().getRemoteAddress());
                    MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                    String errorMsg = Messages.formatString(
                            ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED, subject.getUserName(),
                            "write", messageSend.getDestination().toString());
                    log.info(LogUtils.SECURITY_MARKER, errorMsg);
                    MDC.clear();
                    throw new SecurityException(errorMsg);
                }
            } else if (messageSend.getDestination().getPhysicalName().startsWith(NAMESPACES.STREAM_TOPIC_PREFIX)) {
                if (primaryDatasource == null) {
                    MDC.put(LogUtils.REMOTE_ADDRESS,
                            exchange.getConnectionContext().getConnection().getRemoteAddress());
                    MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                    String logMsg = Messages.formatString(ExceptionConstants.COMBUS.ERROR_SERVER_NOT_READY);
                    log.warn(LogUtils.COMBUS_MARKER, logMsg);
                    MDC.clear();
                    throw new SecurityException(logMsg);
                }
                IOperationContext opContext = null;
                try {
                    opContext = new BaseOperationContext(SEND_MESSAGE,
                            exchange.getConnectionContext().getConnectionId().toString(), principal);
                    opContext.setMDC();
                    if (!subject.getAnzoPrincipal().isSysadmin()) {
                        String namedGraphUUIDUri = UriGenerator.stripEncapsulatedString(
                                NAMESPACES.STREAM_TOPIC_PREFIX, messageSend.getDestination().getPhysicalName());
                        URI namedGraphUri = null;
                        try {
                            namedGraphUri = primaryDatasource.getModelService().getUriForUUID(opContext,
                                    Constants.valueFactory.createURI(namedGraphUUIDUri));
                        } catch (AnzoException e) {
                            String logMsg = Messages.formatString(
                                    ExceptionConstants.DATASOURCE.NAMEDGRAPH.GRAPH_NOT_VALID, namedGraphUUIDUri);
                            log.debug(LogUtils.COMBUS_MARKER, logMsg, e);
                            throw new SecurityException(logMsg, e);
                        }
                        if (namedGraphUri == null) {
                            String logMsg = Messages.formatString(
                                    ExceptionConstants.DATASOURCE.NAMEDGRAPH.GRAPH_NOT_VALID, namedGraphUUIDUri);
                            log.debug(LogUtils.COMBUS_MARKER, logMsg);
                            throw new SecurityException(logMsg);
                        }
                        Set<URI> roles = primaryDatasource.getAuthorizationService().getRolesForGraph(opContext,
                                namedGraphUri, Privilege.ADD);
                        if (!org.openanzo.rdf.utils.Collections.memberOf(roles,
                                subject.getAnzoPrincipal().getRoles())) {
                            MDC.put(LogUtils.REMOTE_ADDRESS,
                                    exchange.getConnectionContext().getConnection().getRemoteAddress());
                            MDC.put(LogUtils.USER, subject.getAnzoPrincipal().getName());
                            String errorMsg = Messages.formatString(
                                    ExceptionConstants.COMBUS.ERROR_CONNECTION_NOT_AUTHENTICATED,
                                    subject.getUserName(), "write", messageSend.getDestination().toString());
                            log.info(LogUtils.SECURITY_MARKER, errorMsg);
                            MDC.clear();
                            throw new SecurityException(errorMsg);
                        }
                        subject.getAuthorizedWriteDests().put(messageSend.getDestination(),
                                messageSend.getDestination());
                        messageSend.setProperty(SerializationConstants.userUri,
                                subject.getAnzoPrincipal().getUserURI().toString());
                    }
                } finally {
                    if (opContext != null) {
                        opContext.clearMDC();
                    }
                }
            } /*else if (messageSend.getDestination().getPhysicalName().startsWith("services/")) {
                         Set<Destination> dests = next.getDestinations(messageSend.getDestination());
                         if (dests == null || dests.size() == 0) {
                             if (messageSend.getReplyTo() != null && messageSend.getCorrelationId() != null) {
                                 Message reply = messageSend.copy();
                                 reply.setDestination(messageSend.getReplyTo());
                                 try {
                                     reply.clearBody();
                                 } catch (javax.jms.JMSException e) {
                  
                                 }
                                 reply.setProperty("error", "true");
                                 next.send(exchange, reply);
                             }
                             //throw new IllegalArgumentException("User " + subject.getUserName() + " is not authorized to publish to: " + messageSend.getDestination() + " since is does not yet exist");
                         }
                     }*/
            subject.getAuthorizedWriteDests().put(messageSend.getDestination(), messageSend.getDestination());
        }
        super.send(exchange, messageSend);
        //     } finally {
        //         resetlock.readLock().unlock();
        //     }
    }

    void refreshNamedGraphAcl(URI namedGraphUri) throws AnzoException {
        if (primaryDatasource != null) {
            String uuid = null;
            IOperationContext opContext = null;
            try {
                opContext = new BaseOperationContext(HANDLE_ACLS_UPDATE, HANDLE_ACLS_UPDATE + namedGraphUri,
                        principal);
                opContext.setMDC();
                uuid = primaryDatasource.getModelService().getUUIDforUri(opContext, namedGraphUri).toString();
            } catch (AnzoException e) {
                String logMsg = Messages.formatString(ExceptionConstants.DATASOURCE.NAMEDGRAPH.GRAPH_NOT_VALID,
                        namedGraphUri.toString());
                log.warn(LogUtils.COMBUS_MARKER, logMsg);
            } finally {
                if (opContext != null) {
                    opContext.clearMDC();
                }
            }

            if (uuid != null) {
                String destName = UriGenerator.generateEncapsulatedString(NAMESPACES.NAMEDGRAPH_TOPIC_PREFIX, uuid);
                ActiveMQDestination destination = ActiveMQDestination.createDestination(destName,
                        ActiveMQDestination.TOPIC_TYPE);
                for (SecurityContext sc : securityContexts) {
                    sc.getAuthorizedReadDests().remove(destination);
                    sc.getAuthorizedWriteDests().remove(destination);
                }
            }
        }
    }

    static class ServerSecurityContext extends SecurityContext {

        private final Set<String> roles;

        private final AnzoPrincipal principal;

        ServerSecurityContext(AnzoPrincipal principal) {
            super(principal.getName());
            this.principal = principal;
            this.roles = new HashSet<String>();
            for (URI uri : principal.getRoles()) {
                roles.add(uri.toString());
            }
        }

        /**
         * @return the principal
         */
        public AnzoPrincipal getAnzoPrincipal() {
            return principal;
        }

        @Override
        public Set<String> getPrincipals() {
            return roles;
        }
    }

}