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.subject;
020
021import org.apache.shiro.SecurityUtils;
022import org.apache.shiro.mgt.SecurityManager;
023import org.apache.shiro.subject.Subject;
024import org.apache.shiro.subject.SubjectContext;
025import org.apache.shiro.web.subject.support.DefaultWebSubjectContext;
026import org.apache.shiro.web.util.RequestPairSource;
027
028import javax.servlet.ServletRequest;
029import javax.servlet.ServletResponse;
030
031/**
032 * A {@code WebSubject} represents a Subject instance that was acquired as a result of an incoming
033 * {@link ServletRequest}.
034 *
035 * @since 1.0
036 */
037public interface WebSubject extends Subject, RequestPairSource {
038
039    /**
040     * Returns the {@code ServletRequest} accessible when the Subject instance was created.
041     *
042     * @return the {@code ServletRequest} accessible when the Subject instance was created.
043     */
044    ServletRequest getServletRequest();
045
046    /**
047     * Returns the {@code ServletResponse} accessible when the Subject instance was created.
048     *
049     * @return the {@code ServletResponse} accessible when the Subject instance was created.
050     */
051    ServletResponse getServletResponse();
052
053    /**
054     * A {@code WebSubject.Builder} performs the same function as a {@link Subject.Builder Subject.Builder}, but
055     * additionally ensures that the Servlet request/response pair that is triggering the Subject instance's creation
056     * is retained for use by internal Shiro components as necessary.
057     */
058    public static class Builder extends Subject.Builder {
059
060        /**
061         * Constructs a new {@code Web.Builder} instance using the {@link SecurityManager SecurityManager} obtained by
062         * calling {@code SecurityUtils.}{@link SecurityUtils#getSecurityManager() getSecurityManager()}.  If you want
063         * to specify your own SecurityManager instance, use the
064         * {@link #Builder(SecurityManager, ServletRequest, ServletResponse)} constructor instead.
065         *
066         * @param request  the incoming ServletRequest that will be associated with the built {@code WebSubject} instance.
067         * @param response the outgoing ServletRequest paired with the ServletRequest that will be associated with the
068         *                 built {@code WebSubject} instance.
069         */
070        public Builder(ServletRequest request, ServletResponse response) {
071            this(SecurityUtils.getSecurityManager(), request, response);
072        }
073
074        /**
075         * Constructs a new {@code Web.Builder} instance using the specified {@code SecurityManager} instance to
076         * create the {@link WebSubject WebSubject} instance.
077         *
078         * @param securityManager the {@code SecurityManager SecurityManager} instance to use to build the
079         *                        {@code WebSubject} instance.
080         * @param request         the incoming ServletRequest that will be associated with the built {@code WebSubject}
081         *                        instance.
082         * @param response        the outgoing ServletRequest paired with the ServletRequest that will be associated
083         *                        with the built {@code WebSubject} instance.
084         */
085        public Builder(SecurityManager securityManager, ServletRequest request, ServletResponse response) {
086            super(securityManager);
087            if (request == null) {
088                throw new IllegalArgumentException("ServletRequest argument cannot be null.");
089            }
090            if (response == null) {
091                throw new IllegalArgumentException("ServletResponse argument cannot be null.");
092            }
093            setRequest(request);
094            setResponse(response);
095        }
096
097        /**
098         * Overrides the parent implementation to return a new instance of a
099         * {@link DefaultWebSubjectContext DefaultWebSubjectContext} to account for the additional request/response
100         * pair.
101         *
102         * @return a new instance of a {@link DefaultWebSubjectContext DefaultWebSubjectContext} to account for the
103         *         additional request/response pair.
104         */
105        @Override
106        protected SubjectContext newSubjectContextInstance() {
107            return new DefaultWebSubjectContext();
108        }
109
110        /**
111         * Called by the {@code WebSubject.Builder} constructor, this method places the request object in the
112         * context map for later retrieval.
113         *
114         * @param request the incoming ServletRequest that triggered the creation of the {@code WebSubject} instance.
115         * @return 'this' for method chaining.
116         */
117        protected Builder setRequest(ServletRequest request) {
118            if (request != null) {
119                ((WebSubjectContext) getSubjectContext()).setServletRequest(request);
120            }
121            return this;
122        }
123
124        /**
125         * Called by the {@code WebSubject.Builder} constructor, this method places the response object in the
126         * context map for later retrieval.
127         *
128         * @param response the outgoing ServletRequest paired with the ServletRequest that triggered the creation of
129         *                 the {@code WebSubject} instance.
130         * @return 'this' for method chaining.
131         */
132        protected Builder setResponse(ServletResponse response) {
133            if (response != null) {
134                ((WebSubjectContext) getSubjectContext()).setServletResponse(response);
135            }
136            return this;
137        }
138
139        /**
140         * Returns {@link #buildSubject() super.buildSubject()}, but additionally ensures that the returned instance
141         * is an {@code instanceof} {@link WebSubject WebSubject} and to support a type-safe method so a caller
142         * does not have to cast.   Per the parent class's method JavaDoc, this method will return a new instance
143         * each time it is called.
144         *
145         * @return a new {@link WebSubject WebSubject} instance built by this {@code Builder}.
146         */
147        public WebSubject buildWebSubject() {
148            Subject subject = super.buildSubject();
149            if (!(subject instanceof WebSubject)) {
150                String msg = "Subject implementation returned from the SecurityManager was not a " +
151                        WebSubject.class.getName() + " implementation.  Please ensure a Web-enabled SecurityManager " +
152                        "has been configured and made available to this builder.";
153                throw new IllegalStateException(msg);
154            }
155            return (WebSubject) subject;
156        }
157    }
158
159}