001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Sam
028: */
029:
030: package com.caucho.server.admin;
031:
032: import com.caucho.config.ConfigException;
033: import com.caucho.config.program.ContainerProgram;
034: import com.caucho.config.program.PropertyValueProgram;
035: import com.caucho.config.types.RawString;
036: import com.caucho.server.dispatch.ServletMapping;
037: import com.caucho.server.hmux.HmuxRequest;
038: import com.caucho.server.host.HostConfig;
039: import com.caucho.server.security.AbstractConstraint;
040: import com.caucho.server.security.SecurityConstraint;
041: import com.caucho.server.webapp.WebAppConfig;
042: import com.caucho.util.InetNetwork;
043: import com.caucho.util.L10N;
044:
045: import javax.servlet.ServletContext;
046: import javax.servlet.ServletException;
047: import javax.servlet.ServletRequest;
048: import javax.servlet.ServletResponse;
049: import javax.servlet.http.HttpServletRequest;
050: import javax.servlet.http.HttpServletResponse;
051: import java.io.IOException;
052: import java.net.InetAddress;
053: import java.net.UnknownHostException;
054: import java.util.Enumeration;
055: import java.util.logging.Logger;
056:
057: abstract public class ManagementService {
058: private static final L10N L = new L10N(ManagementService.class);
059: protected final Logger log = Logger.getLogger(getClass().getName());
060:
061: private final Management _management;
062: private final String _serviceName;
063:
064: private String _password;
065:
066: private InetNetwork[] _allowedNetworks;
067:
068: protected ManagementService(Management management,
069: String serviceName) {
070: _management = management;
071: _serviceName = serviceName;
072: }
073:
074: public void start() {
075: _password = _management.getRemoteCookie();
076:
077: if (_password == null) {
078: log
079: .warning(L
080: .l("jmx-remote disabled. jmx-remote requires at least one enabled management <user>"));
081: return;
082: }
083:
084: HostConfig hostConfig = _management.getHostConfig();
085:
086: WebAppConfig webAppConfig = new WebAppConfig();
087: webAppConfig.setId(_serviceName);
088: webAppConfig
089: .setRootDirectory(new RawString("/admin-dummy-root"));
090:
091: hostConfig.addBuilderProgram(new PropertyValueProgram(
092: "web-app", webAppConfig));
093:
094: ServletMapping servlet = new ServletMapping();
095:
096: servlet.setServletName(_serviceName);
097: servlet.addURLPattern("/*");
098: servlet.addURLRegexp(".*");
099: servlet.setServletClass(ManagementServlet.class.getName());
100:
101: ContainerProgram servletInit = new ContainerProgram();
102: servletInit
103: .addProgram(new PropertyValueProgram("service", this ));
104: servlet.setInit(servletInit);
105:
106: webAppConfig.addBuilderProgram(new PropertyValueProgram(
107: "servlet-mapping", servlet));
108:
109: SecurityConstraint constraint = new SecurityConstraint();
110: constraint.setURLPattern("/*");
111: constraint.addConstraint(new HmuxConstraint(this ));
112: constraint.init();
113: webAppConfig.addBuilderProgram(new PropertyValueProgram(
114: "security-constraint", constraint));
115:
116: try {
117: _allowedNetworks = new InetNetwork[] {
118: new InetNetwork(InetAddress.getByName("127.0.0.1"),
119: 24),
120: new InetNetwork(InetAddress.getByName("10.0.0.0"),
121: 24),
122: new InetNetwork(
123: InetAddress.getByName("172.16.0.0"), 20),
124: new InetNetwork(InetAddress
125: .getByName("192.168.0.0"), 16), };
126: } catch (UnknownHostException e) {
127: throw new RuntimeException(e);
128: }
129: }
130:
131: // first stage security - security constraint authorization
132: public boolean isAuthorized(HttpServletRequest request,
133: HttpServletResponse response, ServletContext application)
134: throws ServletException, IOException {
135: // The order of tests is important for the QA, see server/2e2-
136:
137: HttpServletResponse res = (HttpServletResponse) response;
138:
139: if (!(request instanceof HmuxRequest)) {
140: log
141: .warning(L
142: .l(
143: "{0} attempt with non-hmux-request '{1}' from ip {2}",
144: _serviceName, request, request
145: .getRemoteAddr()));
146:
147: res.sendError(HttpServletResponse.SC_NOT_FOUND);
148: return false;
149: }
150:
151: HmuxRequest hmuxRequest = (HmuxRequest) request;
152:
153: if (!request.getServletPath().equals("")) {
154: log
155: .warning(L
156: .l(
157: "{0} attempt with invalid servlet-path '{1}' from address '{2}'",
158: _serviceName, request
159: .getServletPath(), request
160: .getRemoteAddr()));
161:
162: res.sendError(HttpServletResponse.SC_NOT_FOUND);
163: return false;
164:
165: }
166:
167: if (request.getPathInfo() != null) {
168: log
169: .warning(L
170: .l(
171: "{0} attempt with invalid path-info '{1}' from address '{2}'",
172: _serviceName,
173: request.getPathInfo(), request
174: .getRemoteAddr()));
175:
176: res.sendError(HttpServletResponse.SC_NOT_FOUND);
177: return false;
178:
179: }
180:
181: // The remote test needs to be last to allow the other QA to work properly
182: // XXX: this should be configurable, i.e. setReadConstraints and setWriteConstraints
183:
184: String remoteAddr = hmuxRequest.getRemoteAddr();
185:
186: boolean isValidAddr = false;
187: for (int i = 0; i < _allowedNetworks.length; i++) {
188: if (_allowedNetworks[i].isMatch(remoteAddr))
189: isValidAddr = true;
190: }
191:
192: if (!isValidAddr) {
193: log.warning(L.l("{0} attempt from invalid address '{1}'",
194: _serviceName, remoteAddr));
195:
196: res.sendError(HttpServletResponse.SC_NOT_FOUND);
197: return false;
198: }
199:
200: return true;
201: }
202:
203: // second stage security - read/write permission
204:
205: private boolean isRequestAllowed(ServletRequest request,
206: ServletResponse response) throws IOException,
207: ServletException {
208: HttpServletResponse res = (HttpServletResponse) response;
209:
210: // check attributes for evidence of forward, includes, error page handling
211: Enumeration<String> attributeNames = request
212: .getAttributeNames();
213:
214: while (attributeNames.hasMoreElements()) {
215: String attributeName = attributeNames.nextElement();
216:
217: if (attributeName
218: .equals("javax.servlet.request.X509Certificate"))
219: continue;
220:
221: log
222: .warning(L
223: .l(
224: "management service request attribute '{0}' invalidates request",
225: attributeName));
226:
227: res.sendError(HttpServletResponse.SC_NOT_FOUND);
228: return false;
229: }
230:
231: return true;
232: }
233:
234: protected boolean isReadAllowed(ServletRequest request,
235: ServletResponse response) throws IOException,
236: ServletException {
237: if (!isRequestAllowed(request, response))
238: return false;
239:
240: return true;
241: }
242:
243: protected boolean isWriteAllowed(ServletRequest request,
244: ServletResponse response) throws IOException,
245: ServletException {
246: if (!isRequestAllowed(request, response))
247: return false;
248:
249: return true;
250: }
251:
252: abstract public void service(ServletRequest request,
253: ServletResponse response) throws IOException,
254: ServletException;
255:
256: public String toString() {
257: return getClass().getName() + "[" + _serviceName + ","
258: + _management.getServerId() + "]";
259: }
260:
261: private static class HmuxConstraint extends AbstractConstraint {
262: private final ManagementService _service;
263:
264: public HmuxConstraint(ManagementService service) {
265: _service = service;
266: }
267:
268: public boolean isAuthorized(HttpServletRequest request,
269: HttpServletResponse response, ServletContext application)
270: throws ServletException, IOException {
271: return _service
272: .isAuthorized(request, response, application);
273: }
274: }
275: }
|