001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.shiro.subject;
018
019import java.security.Principal;
020import java.util.Set;
021import java.util.concurrent.ConcurrentMap;
022
023import org.apache.activemq.command.ActiveMQDestination;
024import org.apache.activemq.security.SecurityContext;
025import org.apache.shiro.subject.Subject;
026
027/**
028 * ActiveMQ {@code SecurityContext} implementation that retains a Shiro {@code Subject} instance for use during
029 * security checks and other security-related operations.
030 *
031 * @since 5.10.0
032 */
033public class SubjectSecurityContext extends SecurityContext {
034
035    private final Subject subject;
036
037    public SubjectSecurityContext(SubjectConnectionReference conn) {
038        //The username might not be available at the time this object is instantiated (the Subject might be
039        //anonymous).  Instead we override the getUserName() method below and that will always delegate to the
040        //Subject to return the most accurate/freshest username available.
041        super(null);
042        this.subject = conn.getSubject();
043    }
044
045    public Subject getSubject() {
046        return subject;
047    }
048
049    private static String getUsername(Subject subject) {
050        if (subject != null) {
051            Object principal = subject.getPrincipal();
052            if (principal != null) {
053                return String.valueOf(principal);
054            }
055        }
056        return null;
057    }
058
059    @Override
060    public String getUserName() {
061        return getUsername(this.subject);
062    }
063
064    private static UnsupportedOperationException notAllowed(String methodName) {
065        String msg = "Do not invoke the '" + methodName + "' method or use a broker filter that invokes it.  Use one " +
066                "of the Shiro-based security filters instead.";
067        return new UnsupportedOperationException(msg);
068    }
069
070    @Override
071    public boolean isInOneOf(Set<?> allowedPrincipals) {
072        throw notAllowed("isInOneOf");
073    }
074
075    @Override
076    public ConcurrentMap<ActiveMQDestination, ActiveMQDestination> getAuthorizedWriteDests() {
077        throw notAllowed("getAuthorizedWriteDests");
078    }
079
080    @Override
081    public Set<Principal> getPrincipals() {
082        throw notAllowed("getPrincipals");
083    }
084}