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