001/** 
002 * Copyright (C) 2009 "Darwin V. Felix" <darwinfelix@users.sourceforge.net>
003 * 
004 * This library is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU Lesser General Public
006 * License as published by the Free Software Foundation; either
007 * version 2.1 of the License, or (at your option) any later version.
008 * 
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012 * Lesser General Public License for more details.
013 * 
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this library; if not, write to the Free Software
016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017 */
018
019package net.sourceforge.spnego;
020
021import java.security.Principal;
022
023import javax.servlet.http.HttpServletRequest;
024import javax.servlet.http.HttpServletRequestWrapper;
025
026import net.sourceforge.spnego.SpnegoHttpFilter.Constants;
027
028import org.ietf.jgss.GSSCredential;
029
030/**
031 * Wrap ServletRequest so we can do our own handling of the 
032 * principal and auth types.
033 * 
034 * <p>Also, see the documentation on the {@link DelegateServletRequest} class.</p>
035 * 
036 * <p>Finally, a credential delegation example can be found on 
037 * <a href="http://spnego.sourceforge.net" target="_blank">http://spnego.sourceforge.net</a>
038 * </p>
039 * 
040 * @author Darwin V. Felix
041 *
042 */
043final class SpnegoHttpServletRequest extends HttpServletRequestWrapper 
044    implements DelegateServletRequest, SpnegoAccessControl {
045    
046    private static final String MESSAGE_UNSUPPORTED = 
047            "User Access Control has NOT been defined or is NOT supported.";
048    
049    /** Client Principal. */
050    private final transient SpnegoPrincipal principal;
051    
052    /** authZ framework interface. */
053    private final transient UserAccessControl accessControl;
054    
055    /**
056     * Creates Servlet Request specifying KerberosPrincipal of user.
057     * 
058     * @param request
059     * @param spnegoPrincipal 
060     */
061    SpnegoHttpServletRequest(final HttpServletRequest request
062        , final SpnegoPrincipal spnegoPrincipal) {
063        
064        this(request, spnegoPrincipal, null);
065    }
066    
067    /**
068     * Creates Servlet Request specifying KerberosPrincipal of user 
069     * and a specified User Access Control (authZ).
070     * @param request
071     * @param spnegoPrincipal
072     * @param userAccessControl
073     */
074    SpnegoHttpServletRequest(final HttpServletRequest request
075        , final SpnegoPrincipal spnegoPrincipal
076        , final UserAccessControl userAccessControl) {
077        
078        super(request);
079        
080        this.principal = spnegoPrincipal;
081        this.accessControl = userAccessControl;
082    }
083    
084    /**
085     * Returns "Negotiate" or "Basic" else default auth type.
086     * 
087     * @see javax.servlet.http.HttpServletRequest#getAuthType()
088     */
089    @Override
090    public String getAuthType() {
091        
092        final String authType;
093        final String header = this.getHeader(Constants.AUTHZ_HEADER);
094        
095        if (null == header) {
096            authType = super.getAuthType();
097            
098        } else if (header.startsWith(Constants.NEGOTIATE_HEADER)) {
099            authType = Constants.NEGOTIATE_HEADER;
100
101        } else if (header.startsWith(Constants.BASIC_HEADER)) {
102            authType = Constants.BASIC_HEADER;
103            
104        } else {
105            authType = super.getAuthType();
106        }
107        
108        return authType;
109    }
110    
111    /*
112     * (non-Javadoc)
113     * @see net.sourceforge.spnego.DelegateServletRequest#getDelegatedCredential()
114     */
115    @Override
116    public GSSCredential getDelegatedCredential() {
117        return this.principal.getDelegatedCredential();
118    }
119    
120    /**
121     * Returns authenticated username (sans domain/realm) else default username.
122     * 
123     * @see javax.servlet.http.HttpServletRequest#getRemoteUser()
124     */
125    @Override
126    public String getRemoteUser() {
127        
128        if (null == this.principal) {
129            return super.getRemoteUser();
130            
131        } else {
132            final String[] username = this.principal.getName().split("@", 2);
133            return username[0];
134        }
135    }
136    
137    /**
138     * Returns KerberosPrincipal of user.
139     * 
140     * @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
141     */
142    @Override
143    public Principal getUserPrincipal() {
144        return this.principal;
145    }
146    
147    /*
148     * (non-Javadoc)
149     * @see net.sourceforge.spnego.SpnegoAccessControl#anyRole(java.lang.String[])
150     */
151    @Override
152    public boolean anyRole(final String... roles) {
153        if (null == this.accessControl) {
154            throw new UnsupportedOperationException(MESSAGE_UNSUPPORTED);
155        }
156        
157        return this.accessControl.anyRole(this.getRemoteUser(), roles);
158    }
159    
160    /*
161     * (non-Javadoc)
162     * @see net.sourceforge.spnego.SpnegoAccessControl#hasRole(java.lang.String)
163     */
164    @Override
165    public boolean hasRole(final String role) {
166        if (null == this.accessControl) {
167            throw new UnsupportedOperationException(MESSAGE_UNSUPPORTED);
168        }
169        
170        return this.accessControl.hasRole(this.getRemoteUser(), role);        
171    }
172    
173    /*
174     * (non-Javadoc)
175     * @see net.sourceforge.spnego.SpnegoAccessControl#hasRole(java.lang.String, java.lang.String[])
176     */
177    @Override
178    public boolean hasRole(final String featureX, final String... featureYs) {
179        // assert
180        if (null == this.accessControl) {
181            throw new UnsupportedOperationException(MESSAGE_UNSUPPORTED);
182        }
183        
184        return this.accessControl.hasRole(this.getRemoteUser(), featureX, featureYs);
185    }
186    
187    /*
188     * (non-Javadoc)
189     * @see net.sourceforge.spnego.SpnegoAccessControl#anyAccess(java.lang.String[])
190     */
191    @Override
192    public boolean anyAccess(final String... resources) {
193        if (null == this.accessControl) {
194            throw new UnsupportedOperationException(MESSAGE_UNSUPPORTED);
195        }
196        
197        return this.accessControl.anyAccess(this.getRemoteUser(), resources);        
198    }
199    
200    /*
201     * (non-Javadoc)
202     * @see net.sourceforge.spnego.SpnegoAccessControl#hasAccess(java.lang.String)
203     */
204    @Override
205    public boolean hasAccess(final String resource) {
206     // assert
207        if (null == this.accessControl) {
208            throw new UnsupportedOperationException(MESSAGE_UNSUPPORTED);
209        }
210        
211        return this.accessControl.hasAccess(this.getRemoteUser(), resource);
212    }
213    
214    /*
215     * (non-Javadoc)
216     * @see net.sourceforge.spnego.SpnegoAccessControl#hasAccess(java.lang.String, java.lang.String[])
217     */
218    @Override
219    public boolean hasAccess(final String resourceX, final String... resourceYs) {
220        // assert
221        if (null == this.accessControl) {
222            throw new UnsupportedOperationException(MESSAGE_UNSUPPORTED);
223        }
224        
225        return this.accessControl.hasAccess(this.getRemoteUser(), resourceX, resourceYs);        
226    }
227
228    /*
229     * (non-Javadoc)
230     * @see net.sourceforge.spnego.SpnegoAccessControl#getUserInfo()
231     */
232    @Override
233    public UserInfo getUserInfo() {
234        // assert
235        if (null == this.accessControl) {
236            throw new UnsupportedOperationException(MESSAGE_UNSUPPORTED);
237        }
238        
239        final UserInfo userInfo = this.accessControl.getUserInfo(this.getRemoteUser());
240        
241        if (null == userInfo) {
242            throw new UnsupportedOperationException("UserInfo was NULL and/or not configured");
243        } else {
244            return userInfo;
245        }
246    }
247    
248    /*
249     * (non-Javadoc)
250     * @see javax.servlet.http.HttpServletRequestWrapper#isUserInRole(java.lang.String)
251     */
252    @Override
253    public boolean isUserInRole(final String role) {
254        if (null == this.accessControl) {
255            throw new UnsupportedOperationException(MESSAGE_UNSUPPORTED);
256        }
257        
258        return this.accessControl.hasRole(this.getRemoteUser(), role);
259    }
260}