1 /*
2  * JBoss, Home of Professional Open Source.
3  * Copyright 2014 Red Hat, Inc., and individual contributors
4  * as indicated by the @author tags.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */

18 package io.undertow.security.handlers;
19
20 import java.net.URI;
21 import java.net.URISyntaxException;
22
23 import io.undertow.UndertowLogger;
24 import io.undertow.server.HttpHandler;
25 import io.undertow.server.HttpServerExchange;
26 import io.undertow.util.Headers;
27 import io.undertow.util.StatusCodes;
28
29 /**
30  * Handler responsible for checking of confidentiality is required for the requested resource and if so rejecting the request
31  * and redirecting to a secure address.
32  *
33  * @author <a href="mailto:darran.lofthouse@jboss.com">Darran Lofthouse</a>
34  */

35 public abstract class AbstractConfidentialityHandler implements HttpHandler {
36
37     private final HttpHandler next;
38
39     protected AbstractConfidentialityHandler(final HttpHandler next) {
40         this.next = next;
41     }
42
43     @Override
44     public void handleRequest(HttpServerExchange exchange) throws Exception {
45         if (isConfidential(exchange) || !confidentialityRequired(exchange)) {
46             next.handleRequest(exchange);
47         } else {
48             try {
49                 URI redirectUri = getRedirectURI(exchange);
50                 UndertowLogger.SECURITY_LOGGER.debugf("Redirecting request %s to %s to meet confidentiality requirements", exchange, redirectUri);
51                 exchange.setStatusCode(StatusCodes.FOUND);
52                 exchange.getResponseHeaders().put(Headers.LOCATION, redirectUri.toString());
53             } catch (Exception e) {
54                 UndertowLogger.REQUEST_LOGGER.exceptionProcessingRequest(e);
55                 exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR);
56             }
57             exchange.endExchange();
58         }
59     }
60
61     /**
62      * Use the HttpServerExchange supplied to check if this request is already 'sufficiently' confidential.
63      *
64      * Here we say 'sufficiently' as sub-classes can override this and maybe even go so far as querying the actual SSLSession.
65      *
66      * @param exchange - The {@link HttpServerExchange} for the request being processed.
67      * @return true if the request is 'sufficiently' confidential, false otherwise.
68      */

69     protected boolean isConfidential(final HttpServerExchange exchange) {
70         return exchange.getRequestScheme().equals("https");
71     }
72
73     /**
74      * Use the HttpServerExchange to identify if confidentiality is required.
75      *
76      * This method currently returns true for all requests, sub-classes can override this to provide a custom check.
77      *
78      * TODO: we should deprecate this and just use a predicate to decide to execute the handler instead
79      *
80      * @param exchange - The {@link HttpServerExchange} for the request being processed.
81      * @return true if the request requires confidentiality, false otherwise.
82      */

83     protected boolean confidentialityRequired(final HttpServerExchange exchange) {
84         return true;
85     }
86
87     /**
88      * All sub-classes are required to provide an implementation of this method, using the HttpServerExchange for the current
89      * request return the address to use for a redirect should confidentiality be required and the request not be confidential.
90      *
91      * @param exchange - The {@link HttpServerExchange} for the request being processed.
92      * @return The {@link URI} to redirect to.
93      */

94     protected abstract URI getRedirectURI(final HttpServerExchange exchange) throws URISyntaxException;
95
96 }
97