001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.shiro.web.jaxrs;
020
021import org.apache.shiro.SecurityUtils;
022import org.apache.shiro.subject.PrincipalCollection;
023import org.apache.shiro.subject.Subject;
024
025import javax.ws.rs.container.ContainerRequestContext;
026import javax.ws.rs.core.SecurityContext;
027import java.security.Principal;
028
029/**
030 * A Shiro based {@link SecurityContext} that exposes the current Shiro {@link Subject} as a {@link Principal}.
031 * The {@link #isUserInRole(String)} method returns the result of {@link Subject#hasRole(String)}.
032 *
033 * @since 1.4
034 */
035public class ShiroSecurityContext implements SecurityContext {
036
037    final private ContainerRequestContext containerRequestContext;
038    final private SecurityContext originalSecurityContext;
039
040    public ShiroSecurityContext(ContainerRequestContext containerRequestContext) {
041        this.containerRequestContext = containerRequestContext;
042        this.originalSecurityContext = containerRequestContext.getSecurityContext();
043    }
044
045    @Override
046    public Principal getUserPrincipal() {
047
048        Principal result;
049
050        Subject subject = getSubject();
051        PrincipalCollection shiroPrincipals = subject.getPrincipals();
052        if (shiroPrincipals != null) {
053            result = shiroPrincipals.oneByType(Principal.class);
054
055            if (result == null) {
056                result = new ObjectPrincipal(shiroPrincipals.getPrimaryPrincipal());
057            }
058        }
059        else {
060            result = originalSecurityContext.getUserPrincipal();
061        }
062
063        return result;
064    }
065
066    @Override
067    public boolean isUserInRole(String role) {
068        return getSubject().hasRole(role);
069    }
070
071    @Override
072    public boolean isSecure() {
073        return containerRequestContext.getSecurityContext().isSecure();
074    }
075
076    @Override
077    public String getAuthenticationScheme() {
078        return containerRequestContext.getSecurityContext().getAuthenticationScheme();
079    }
080
081    private Subject getSubject() {
082        return SecurityUtils.getSubject();
083    }
084
085
086    /**
087     * Java Principal wrapper around any Shiro Principal object.s
088     */
089    private class ObjectPrincipal implements Principal {
090        private Object object = null;
091
092        public ObjectPrincipal(Object object) {
093            this.object = object;
094        }
095
096        public Object getObject() {
097            return object;
098        }
099
100        public String getName() {
101            return getObject().toString();
102        }
103
104        @Override
105        public boolean equals(Object o) {
106            if (this == o) return true;
107            if (o == null || getClass() != o.getClass()) return false;
108
109            ObjectPrincipal that = (ObjectPrincipal) o;
110
111            return object.equals(that.object);
112
113        }
114
115        public int hashCode() {
116            return object.hashCode();
117        }
118
119        public String toString() {
120            return object.toString();
121        }
122    }
123}