View Javadoc

1   /*
2    * Copyright 2002,2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.jelly.tags.jetty;
18  
19  import org.apache.commons.jelly.JellyTagException;
20  import org.apache.commons.jelly.TagSupport;
21  import org.apache.commons.jelly.XMLOutput;
22  
23  import org.mortbay.http.BasicAuthenticator;
24  import org.mortbay.http.ClientCertAuthenticator;
25  import org.mortbay.http.DigestAuthenticator;
26  import org.mortbay.http.SecurityConstraint.Authenticator;
27  import org.mortbay.http.SecurityConstraint;
28  import org.mortbay.http.handler.SecurityHandler;
29  import org.mortbay.jetty.servlet.FormAuthenticator;
30  import org.mortbay.util.Code;
31  import org.mortbay.xml.XmlParser;
32  
33  import org.xml.sax.InputSource;
34  import org.xml.sax.SAXException;
35  
36  import java.io.IOException;
37  import java.io.StringReader;
38  import java.util.Iterator;
39  
40  /***
41   * Declare a security handler for a Jetty http server
42   *
43   * @author  rtl
44   * @version $Id: SecurityHandlerTag.java 155420 2005-02-26 13:06:03Z dirkv $
45   */
46  public class SecurityHandlerTag extends TagSupport {
47  
48      /*** a form authenticator used by this tag */
49      private transient FormAuthenticator _formAuthenticator;
50  
51      /*** parameter authentication method, defaults to BASIC in Jetty */
52      private String _authenticationMethod;
53  
54      /*** Creates a new instance of SecurityHandlerTag */
55      public SecurityHandlerTag() {
56      }
57  
58      /***
59       * Perform the tag functionality. In this case, add a security handler
60       * to the parent context, setting the authentication method if required
61       * The security constraints should be specified as the body of this tag
62       * using the same format as a web.xml file wrapped in a single
63       * <constraints> tag to allow parsing of a well-formed snippet, e.g.
64       *
65       * <constraints>
66       *   <security-constraint>
67       *    <web-resource-collection>
68       *     <web-resource-name>Default</web-resource-name>
69       *      <url-pattern>/</url-pattern>
70       *    </web-resource-collection>
71       *    <auth-constraint/>
72       *   </security-constraint>
73       *
74       *   <security-constraint>
75       *     <web-resource-collection>
76       *       <url-pattern>/docRoot/resourceHandlerTest/*</url-pattern>
77       *       <http-method>GET</http-method>
78       *       <http-method>HEAD</http-method>
79       *     </web-resource-collection>
80       *     <auth-constraint>
81       *       <role-name>*</role-name>
82       *     </auth-constraint>
83       *   </security-constraint>
84       *
85       *   <login-config>
86       *     <auth-method>BASIC</auth-method>
87       *     <realm-name>Jetty Demo Realm</realm-name>
88       *   </login-config>
89       *
90       * </constraints>
91       *
92       * @param xmlOutput where to send output
93       * @throws Exception when an error occurs
94       */
95      public void doTag(XMLOutput xmlOutput) throws JellyTagException {
96          HttpContextTag httpContext = (HttpContextTag) findAncestorWithClass(
97              HttpContextTag.class);
98          if ( httpContext == null ) {
99              throw new JellyTagException( "<securityHandler> tag must be enclosed inside a <httpContext> tag" );
100         }
101         SecurityHandler securityHandler = new SecurityHandler();
102         if (getauthenticationMethod() != null) {
103             securityHandler.setAuthMethod(getauthenticationMethod());
104         }
105         httpContext.addHandler(securityHandler);
106 
107         // get the security constraints from the body of this tag
108         // by parsing the body of the parent (so it will be well formed)
109         String bodyText = getBodyText();
110         StringReader reader = new StringReader(bodyText);
111         InputSource inputSource = new InputSource(reader);
112 
113         // crate a non-validating parser
114         XmlParser xmlParser = new XmlParser(false);
115 
116         XmlParser.Node node = null;
117         try {
118             node = xmlParser.parse(inputSource);
119         }
120         catch (IOException e) {
121             throw new JellyTagException(e);
122         }
123         catch (SAXException e) {
124             throw new JellyTagException(e);
125         }
126 
127         Iterator iter=node.iterator();
128         XmlParser.Node currNode = null;
129         while (iter.hasNext())
130         {
131                 Object o = iter.next();
132                 if (!(o instanceof XmlParser.Node))
133                     continue;
134 
135                 currNode=(XmlParser.Node)o;
136                 String name=currNode.getTag();
137 
138                 if ("security-constraint".equals(name)) {
139                     initSecurityConstraint(currNode, httpContext);
140                 } else if ("login-config".equals(name)) {
141                     initLoginConfig(currNode, httpContext);
142                 } else {
143                     throw new JellyTagException("Invalid element in <securityHandler> tag. Are you using the <constraints> tag?: " + currNode);
144                 }
145         }
146 
147     }
148 
149     /* ------------------------------------------------------------
150      * This is the code from Jetty's WebApplicationContext
151      * with the HttpContextTag parameter added
152      *
153      * Process a parsed xml node to setup the security constraints
154      * for an http server
155      *
156      * @param node the parsed xml starting node of the constraints
157      * @param httpContext the tag to add the security constraint to
158     */
159     protected void initSecurityConstraint(XmlParser.Node node,
160                                           HttpContextTag httpContext)
161     {
162         SecurityConstraint scBase = new SecurityConstraint();
163 
164         XmlParser.Node auths=node.get("auth-constraint");
165         if (auths!=null)
166         {
167             scBase.setAuthenticate(true);
168             // auth-constraint
169             Iterator iter= auths.iterator("role-name");
170             while(iter.hasNext())
171             {
172                 String role=((XmlParser.Node)iter.next()).toString(false,true);
173                 scBase.addRole(role);
174             }
175         }
176 
177         XmlParser.Node data=node.get("user-data-constraint");
178         if (data!=null)
179         {
180             data=data.get("transport-guarantee");
181             String guarantee = data.toString(false,true).toUpperCase();
182             if (guarantee==null || guarantee.length()==0 ||
183                 "NONE".equals(guarantee))
184                 scBase.setDataConstraint(SecurityConstraint.DC_NONE);
185             else if ("INTEGRAL".equals(guarantee))
186                 scBase.setDataConstraint(SecurityConstraint.DC_INTEGRAL);
187             else if ("CONFIDENTIAL".equals(guarantee))
188                 scBase.setDataConstraint(SecurityConstraint.DC_CONFIDENTIAL);
189             else
190             {
191                 Code.warning("Unknown user-data-constraint:"+guarantee);
192                 scBase.setDataConstraint(SecurityConstraint.DC_CONFIDENTIAL);
193             }
194         }
195 
196         Iterator iter= node.iterator("web-resource-collection");
197         while(iter.hasNext())
198         {
199             XmlParser.Node collection=(XmlParser.Node)iter.next();
200             String name=collection.getString("web-resource-name",false,true);
201             SecurityConstraint sc = (SecurityConstraint)scBase.clone();
202             sc.setName(name);
203 
204             Iterator iter2= collection.iterator("http-method");
205             while(iter2.hasNext())
206                 sc.addMethod(((XmlParser.Node)iter2.next())
207                              .toString(false,true));
208 
209             iter2= collection.iterator("url-pattern");
210             while(iter2.hasNext())
211             {
212                 String url=
213                     ((XmlParser.Node)iter2.next()).toString(false,true);
214                 httpContext.addSecurityConstraint(url,sc);
215             }
216         }
217     }
218 
219     /* ------------------------------------------------------------
220      * This is the code from Jetty's WebApplicationContext
221      * with the HttpContextTag parameter added
222      *
223      *
224      * Process a parsed xml node to setup the authenticator and realm
225      * for an http server
226      *
227      * @param node the parsed xml starting node of the login configuration
228      * @param httpContext the tag to add the authenticator and realm to
229     */
230     protected void initLoginConfig(XmlParser.Node node,
231                                    HttpContextTag httpContext)
232     {
233         XmlParser.Node method=node.get("auth-method");
234         if (method!=null)
235         {
236             Authenticator authenticator=null;
237             String m=method.toString(false,true);
238 
239             if (SecurityConstraint.__FORM_AUTH.equals(m))
240                 authenticator=_formAuthenticator=new FormAuthenticator();
241             else if (SecurityConstraint.__BASIC_AUTH.equals(m))
242                 authenticator=new BasicAuthenticator();
243             else if (SecurityConstraint.__DIGEST_AUTH.equals(m))
244                 authenticator=new DigestAuthenticator();
245             else if (SecurityConstraint.__CERT_AUTH.equals(m))
246                 authenticator=new ClientCertAuthenticator();
247             else
248                 Code.warning("UNKNOWN AUTH METHOD: "+m);
249 
250             httpContext.setAuthenticator(authenticator);
251         }
252 
253         XmlParser.Node name=node.get("realm-name");
254         if (name!=null)
255             httpContext.setRealmName(name.toString(false,true));
256 
257         XmlParser.Node formConfig = node.get("form-login-config");
258         if(formConfig != null)
259         {
260             if (_formAuthenticator==null)
261                 Code.warning("FORM Authentication miss-configured");
262             else
263             {
264                 XmlParser.Node loginPage = formConfig.get("form-login-page");
265                 if (loginPage != null)
266                     _formAuthenticator.setLoginPage(loginPage.toString(false,true));
267                 XmlParser.Node errorPage = formConfig.get("form-error-page");
268                 if (errorPage != null)
269                     _formAuthenticator.setErrorPage(errorPage.toString(false,true));
270             }
271         }
272     }
273 
274     //--------------------------------------------------------------------------
275     // Property accessors/mutators
276     //--------------------------------------------------------------------------
277 
278     /***
279      * Getter for property authenticationMethod.
280      *
281      * @return value of property authenticationMethod.
282      */
283     public String getauthenticationMethod() {
284         return _authenticationMethod;
285     }
286 
287     /***
288      * Setter for property authenticationMethod.
289      *
290      * @param authenticationMethod Type of authentication (BASIC, FORM, DIGEST, CLIENT-CERT)
291      * Note that only BASIC and CLIENT-CERT are supported by Jetty as of v4.1.1
292      */
293     public void setauthenticationMethod(String authenticationMethod) {
294         _authenticationMethod = authenticationMethod;
295     }
296 
297 
298 }