Create IP range helper class
[java-idp.git] / src / main / java / edu / internet2 / middleware / shibboleth / idp / StatusServlet.java
1 /*
2  * Copyright 2009 University Corporation for Advanced Internet Development, Inc.
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 edu.internet2.middleware.shibboleth.idp;
18
19 import java.io.IOException;
20 import java.io.PrintWriter;
21 import java.net.InetAddress;
22 import java.net.UnknownHostException;
23
24 import javax.servlet.ServletConfig;
25 import javax.servlet.ServletException;
26 import javax.servlet.http.HttpServlet;
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29
30 import org.apache.commons.httpclient.HttpStatus;
31 import org.joda.time.DateTime;
32 import org.joda.time.chrono.ISOChronology;
33 import org.joda.time.format.DateTimeFormatter;
34 import org.joda.time.format.ISODateTimeFormat;
35 import org.opensaml.xml.security.x509.X509Credential;
36 import org.opensaml.xml.util.Base64;
37 import org.opensaml.xml.util.DatatypeHelper;
38 import org.opensaml.xml.util.LazyList;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
43 import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver;
44 import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
45 import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfigurationManager;
46 import edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper;
47 import edu.internet2.middleware.shibboleth.idp.util.IPRange;
48
49 /** A Servlet for displaying the status of the IdP. */
50 public class StatusServlet extends HttpServlet {
51
52     /** Serial version UID. */
53     private static final long serialVersionUID = -5280549109235107879L;
54
55     private final String IP_PARAM_NAME = "AllowedIPs";
56     
57     private final Logger log = LoggerFactory.getLogger(StatusServlet.class);
58
59     private LazyList<IPRange> allowedIPs;
60
61     /** Formatter used when print date/times. */
62     private DateTimeFormatter dateFormat;
63
64     /** Time the IdP started up. */
65     private DateTime startTime;
66
67     /** Attribute resolver used by the IdP. */
68     private AttributeResolver<?> attributeResolver;
69
70     /** Relying party configuration manager used by the IdP. */
71     private RelyingPartyConfigurationManager rpConfigManager;
72
73     /** {@inheritDoc} */
74     public void init(ServletConfig config) throws ServletException {
75         super.init(config);
76
77         allowedIPs = new LazyList<IPRange>();
78
79         String cidrBlocks = DatatypeHelper.safeTrimOrNullString(config.getInitParameter(IP_PARAM_NAME));
80         if (cidrBlocks != null) {
81             for (String cidrBlock : cidrBlocks.split(" ")) {
82                 allowedIPs.add(IPRange.parseCIDRBlock(cidrBlock));
83             }
84         }
85
86         dateFormat = ISODateTimeFormat.dateTimeNoMillis();
87         startTime = new DateTime(ISOChronology.getInstanceUTC());
88         attributeResolver = HttpServletHelper.getAttributeResolver(config.getServletContext());
89         rpConfigManager = HttpServletHelper.getRelyingPartyConfirmationManager(config.getServletContext());
90     }
91
92     /** {@inheritDoc} */
93     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
94         if (!isAuthenticated(request)) {
95             response.sendError(HttpStatus.SC_UNAUTHORIZED);
96             return;
97         }
98
99         response.setContentType("text/plain");
100         PrintWriter output = response.getWriter();
101
102         printOperatingEnvironmentInformation(output);
103         output.println();
104         printIdPInformation(output);
105         output.println();
106         printRelyingPartyConfigurationsInformation(output, request.getParameter("relyingParty"));
107
108         output.flush();
109     }
110
111     /**
112      * Checks whether the client is authenticated.
113      * 
114      * @param request client request
115      * 
116      * @return true if the client is authenticated, false if not
117      */
118     protected boolean isAuthenticated(HttpServletRequest request) throws ServletException {
119         log.debug("Attempting to authenticate client '{}'", request.getRemoteAddr());
120         try {
121             InetAddress clientAddress = InetAddress.getByName(request.getRemoteAddr());
122
123             for (IPRange range : allowedIPs) {
124                 if (range.contains(clientAddress)) {
125                     return true;
126                 }
127             }
128
129             return false;
130         } catch (UnknownHostException e) {
131             throw new ServletException(e);
132         }
133     }
134
135     /**
136      * Prints out information about the operating environment. This includes the operating system name, version and
137      * architecture, the JDK version, available CPU cores, memory currently used by the JVM process, the maximum amount
138      * of memory that may be used by the JVM, and the current time in UTC.
139      * 
140      * @param out output writer to which information will be written
141      */
142     protected void printOperatingEnvironmentInformation(PrintWriter out) {
143         Runtime runtime = Runtime.getRuntime();
144
145         out.println("### Operating Environment Information");
146         out.println("operating_system: " + System.getProperty("os.name"));
147         out.println("operating_system_version: " + System.getProperty("os.version"));
148         out.println("operating_system_architecture: " + System.getProperty("os.arch"));
149         out.println("jdk_version: " + System.getProperty("java.version"));
150         out.println("available_cores: " + runtime.availableProcessors());
151         out.println("used_memory: " + runtime.totalMemory() / 1048576 + "MB");
152         out.println("maximum_memory: " + runtime.maxMemory() / 1048576 + "MB");
153         out.println("current_time: " + new DateTime(ISOChronology.getInstanceUTC()).toString(dateFormat));
154     }
155
156     /**
157      * Prints out general IdP information. This includes IdP version, start up time, and whether the attribute resolver
158      * is currently operational.
159      * 
160      * @param out output writer to which information will be written
161      */
162     protected void printIdPInformation(PrintWriter out) {
163         Package pkg = Version.class.getPackage();
164
165         out.println("### Identity Provider Information");
166         out.println("idp_version: " + pkg.getImplementationVersion());
167         out.println("idp_start_time: " + startTime.toString(dateFormat));
168         try {
169             attributeResolver.validate();
170             out.println("attribute_resolver_valid: " + Boolean.TRUE);
171         } catch (AttributeResolutionException e) {
172             out.println("attribute_resolver_valid: " + Boolean.FALSE);
173         }
174     }
175
176     /**
177      * Prints information about relying party configurations. If the given relying party is null then the configuration
178      * for all relying parties is printed. If the relying party ID is not null then the relying party configurations for
179      * that entity is printed.
180      * 
181      * @param out output writer to which information will be written
182      * @param relyingPartyId entity ID of the relying party whose configuration should be printed
183      */
184     protected void printRelyingPartyConfigurationsInformation(PrintWriter out, String relyingPartyId) {
185         out.println("### Relying Party Configurations");
186
187         if (relyingPartyId == null) {
188             for (RelyingPartyConfiguration config : rpConfigManager.getRelyingPartyConfigurations().values()) {
189                 printRelyingPartyConfigurationInformation(out, config);
190                 out.println();
191             }
192         } else {
193             RelyingPartyConfiguration config = rpConfigManager.getRelyingPartyConfiguration(relyingPartyId);
194             printRelyingPartyConfigurationInformation(out, config);
195             out.println();
196         }
197     }
198
199     /**
200      * Prints out the information for a specific relying party configuration. This information includes the relying
201      * party or relying party group ID, the entity ID of the IdP when it responds when using this configuration, the
202      * default authentication method used for this config, and configured communication profiles.
203      * 
204      * @param out output writer to which information will be written
205      * @param config the relying party configuration
206      */
207     protected void printRelyingPartyConfigurationInformation(PrintWriter out, RelyingPartyConfiguration config) {
208         out.println("relying_party_id: " + config.getRelyingPartyId());
209         out.println("idp_entity_id: " + config.getProviderId());
210
211         if (config.getDefaultAuthenticationMethod() != null) {
212             out.println("default_authentication_method: " + config.getDefaultAuthenticationMethod());
213         } else {
214             out.println("default_authentication_method: none");
215         }
216
217         try {
218             X509Credential signingCredential = (X509Credential) config.getDefaultSigningCredential();
219             out
220                     .println("default_signing_tls_key: "
221                             + Base64.encodeBytes(signingCredential.getEntityCertificate().getEncoded(),
222                                     Base64.DONT_BREAK_LINES));
223         } catch (Throwable t) {
224             // swallow error
225         }
226
227         for (String profileId : config.getProfileConfigurations().keySet()) {
228             out.println("configured_communication_profile: " + profileId);
229         }
230     }
231 }