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     */
017    package org.apache.geronimo.tomcat;
018    
019    
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.io.OutputStream;
023    import java.net.URI;
024    import java.net.URISyntaxException;
025    import java.util.HashMap;
026    import java.util.Map;
027    
028    import javax.servlet.ServletException;
029    import javax.servlet.http.HttpServlet;
030    import javax.servlet.http.HttpServletRequest;
031    import javax.servlet.http.HttpServletResponse;
032    
033    import org.apache.catalina.Wrapper;
034    import org.apache.catalina.authenticator.BasicAuthenticator;
035    import org.apache.catalina.authenticator.DigestAuthenticator;
036    import org.apache.catalina.authenticator.NonLoginAuthenticator;
037    import org.apache.catalina.authenticator.SSLAuthenticator;
038    import org.apache.catalina.connector.Request;
039    import org.apache.catalina.connector.Response;
040    import org.apache.catalina.core.StandardContext;
041    import org.apache.catalina.deploy.LoginConfig;
042    import org.apache.catalina.deploy.SecurityCollection;
043    import org.apache.catalina.deploy.SecurityConstraint;
044    import org.apache.catalina.valves.ValveBase;
045    import org.apache.commons.logging.Log;
046    import org.apache.commons.logging.LogFactory;
047    import org.apache.geronimo.tomcat.realm.TomcatEJBWSGeronimoRealm;
048    import org.apache.geronimo.webservices.WebServiceContainer;
049    
050    public class TomcatEJBWebServiceContext extends StandardContext{
051    
052        private static final Log log = LogFactory.getLog(TomcatEJBWebServiceContext.class);
053    
054        private final String contextPath;
055        private final WebServiceContainer webServiceContainer;
056        private final boolean isSecureTransportGuarantee;
057        private final ClassLoader classLoader;
058    
059        public TomcatEJBWebServiceContext(String contextPath, WebServiceContainer webServiceContainer, String securityRealmName, String realmName, String transportGuarantee, String authMethod, ClassLoader classLoader) {
060    
061            super();
062    
063            this.contextPath = contextPath;
064            this.webServiceContainer = webServiceContainer;
065            this.setPath(contextPath);
066            this.setDocBase("");
067            this.setParentClassLoader(classLoader);
068            this.setDelegate(true);
069    
070            log.debug("EJB Webservice Context = " + contextPath);
071            if (securityRealmName != null) {
072    
073                TomcatEJBWSGeronimoRealm realm = new TomcatEJBWSGeronimoRealm();
074                realm.setAppName(securityRealmName);
075                realm.setUserClassNames("org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal");
076                realm.setRoleClassNames("org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal");
077                setRealm(realm);
078                this.realm = realm;
079    
080                if ("NONE".equals(transportGuarantee)) {
081                    isSecureTransportGuarantee = false;
082                } else if ("INTEGRAL".equals(transportGuarantee) ||
083                           "CONFIDENTIAL".equals(transportGuarantee)) {
084                    isSecureTransportGuarantee = true;
085                } else {
086                    throw new IllegalArgumentException("Invalid transport-guarantee: " + transportGuarantee);
087                }
088    
089                if ("NONE".equals(authMethod) ||
090                    "BASIC".equals(authMethod) ||
091                    "DIGEST".equals(authMethod) ||
092                    "CLIENT-CERT".equals(authMethod)) {
093    
094                    //Setup a login configuration
095                    LoginConfig loginConfig = new LoginConfig();
096                    loginConfig.setAuthMethod(authMethod);
097                    loginConfig.setRealmName(realmName);
098                    this.setLoginConfig(loginConfig);
099    
100                    //Setup a default Security Constraint
101                    SecurityCollection collection = new SecurityCollection();
102                    collection.addMethod("GET");
103                    collection.addMethod("POST");
104                    collection.addPattern("/*");
105                    collection.setName("default");
106                    SecurityConstraint sc = new SecurityConstraint();
107                    sc.addAuthRole("*");
108                    sc.addCollection(collection);
109                    sc.setAuthConstraint(true);
110                    sc.setUserConstraint(transportGuarantee);
111                    this.addConstraint(sc);
112                    this.addSecurityRole("default");
113    
114                    //Set the proper authenticator
115                    if ("BASIC".equals(authMethod) ){
116                        this.addValve(new BasicAuthenticator());
117                    } else if ("DIGEST".equals(authMethod) ){
118                        this.addValve(new DigestAuthenticator());
119                    } else if ("CLIENT-CERT".equals(authMethod) ){
120                        this.addValve(new SSLAuthenticator());
121                    } else if ("NONE".equals(authMethod)) {
122                        this.addValve(new NonLoginAuthenticator());
123                    }
124    
125                } else {
126                    throw new IllegalArgumentException("Invalid authMethod: " + authMethod);
127                }
128            } else {
129                isSecureTransportGuarantee = false;
130            }
131            
132            this.classLoader = classLoader;
133            this.addValve(new EJBWebServiceValve());
134            
135            //Create a dummy wrapper
136            Wrapper wrapper = this.createWrapper();
137            String name = System.currentTimeMillis() + "";
138            wrapper.setName(name);
139            this.addChild(wrapper);
140            this.addServletMapping("/*", name);
141    
142        }
143        
144        public class EJBWebServiceValve extends ValveBase{
145    
146            public void invoke(Request req, Response res) throws IOException, ServletException {
147                res.setContentType("text/xml");            
148                RequestAdapter request = new RequestAdapter(req);
149                ResponseAdapter response = new ResponseAdapter(res);
150    
151                request.setAttribute(WebServiceContainer.SERVLET_REQUEST, (HttpServletRequest)req);
152                request.setAttribute(WebServiceContainer.SERVLET_RESPONSE, (HttpServletResponse)res);
153                // TODO: add support for context
154                request.setAttribute(WebServiceContainer.SERVLET_CONTEXT, null);
155    
156                req.finishRequest();
157                if (req.getParameter("wsdl") != null) {
158                    try {
159                        webServiceContainer.getWsdl(request, response);
160                        //WHO IS RESPONSIBLE FOR CLOSING OUT?
161                    } catch (IOException e) {
162                        throw e;
163                    } catch (Exception e) {
164                        log.error(e);
165                        res.sendError(500,"Could not fetch wsdl!");
166                        return;
167                    }
168                } else {
169                    if (isSecureTransportGuarantee) {
170                        if (!req.isSecure()) {
171                            res.sendError(403);
172                            return;
173                        }
174                    }
175                    Thread currentThread = Thread.currentThread();
176                    ClassLoader oldClassLoader = currentThread.getContextClassLoader();
177                    currentThread.setContextClassLoader(classLoader);
178                    try {
179                        try {
180                            webServiceContainer.invoke(request, response);
181                            req.finishRequest();
182                        } catch (IOException e) {
183                            throw e;
184                        } catch (Exception e) {
185                            res.sendError(500, "Could not process message!");
186                        }
187                    } finally {
188                        currentThread.setContextClassLoader(oldClassLoader);
189                    }
190                }
191            }
192    
193        }
194    
195        public static class RequestAdapter implements WebServiceContainer.Request {
196            private final Request request;
197            private URI uri;
198    
199            public RequestAdapter(Request request) {
200                this.request = request;
201            }
202    
203            public String getHeader(String name) {
204                return request.getHeader(name);
205            }
206    
207            public java.net.URI getURI() {
208                if (uri == null) {
209                    try {
210                        //String uriString = request.getScheme() + "://" + request.getServerName() + ":" + request.getLocalPort() + request.getRequestURI();
211                        //return new java.net.URI(uri.getScheme(),uri.getHost(),uri.getPath(),uri.);
212                        uri = new java.net.URI(request.getScheme(), null, request.getServerName(), request.getServerPort(), request.getRequestURI(), request.getQueryString(), null);
213                    } catch (URISyntaxException e) {
214                        throw new IllegalStateException(e.getMessage(), e);
215                    }
216                }
217                return uri;
218            }
219    
220            public int getContentLength() {
221                return request.getContentLength();
222            }
223    
224            public String getContentType() {
225                return request.getContentType();
226            }
227    
228            public InputStream getInputStream() throws IOException {
229                return request.getInputStream();
230            }
231    
232            public int getMethod() {
233                Integer method = (Integer) methods.get(request.getMethod());
234                return method == null ? UNSUPPORTED : method.intValue();
235            }
236    
237            public String getParameter(String name) {
238                return request.getParameter(name);
239            }
240    
241            public Map getParameters() {
242                return request.getParameterMap();
243            }
244    
245            public Object getAttribute(String name) {
246                return request.getAttribute(name);
247            }
248    
249            public void setAttribute(String name, Object value) {
250                request.setAttribute(name, value);
251            }
252    
253            public String getRemoteAddr() {
254                return request.getRemoteAddr();
255            }
256    
257            public String getContextPath() {
258                return request.getContextPath();
259            }
260    
261            private static final Map methods = new HashMap();
262    
263            static {
264                methods.put("OPTIONS", new Integer(OPTIONS));
265                methods.put("GET", new Integer(GET));
266                methods.put("HEAD", new Integer(HEAD));
267                methods.put("POST", new Integer(POST));
268                methods.put("PUT", new Integer(PUT));
269                methods.put("DELETE", new Integer(DELETE));
270                methods.put("TRACE", new Integer(TRACE));
271                methods.put("CONNECT", new Integer(CONNECT));
272            }
273    
274        }
275    
276        public static class ResponseAdapter implements WebServiceContainer.Response {
277            private final Response response;
278    
279            public ResponseAdapter(Response response) {
280                this.response = response;
281            }
282    
283            public void setHeader(String name, String value) {
284                response.setHeader(name, value);
285            }
286    
287            public String getHeader(String name) {
288                return response.getHeader(name);
289            }
290    
291            public OutputStream getOutputStream() {
292                return response.getStream();
293            }
294    
295            public void setStatusCode(int code) {
296                response.setStatus(code);
297            }
298    
299            public int getStatusCode() {
300                return response.getStatus();
301            }
302    
303            public void setContentType(String type) {
304                response.setContentType(type);
305            }
306    
307            public String getContentType() {
308                return response.getContentType();
309            }
310    
311            public void setStatusMessage(String responseString) {
312                response.setStatus(response.getStatus(), responseString);
313            }
314    
315            public void flushBuffer() throws java.io.IOException{
316                response.flushBuffer();
317            }
318    
319        }
320    
321    }