/* * Copyright 2016 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.keycloak.proxy; import io.undertow.security.api.AuthenticationMechanism; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.util.AttachmentKey; import org.jboss.logging.Logger; import java.util.List; /** * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @version $Revision: 1 $ */ public class ConstraintMatcherHandler implements HttpHandler { protected static Logger log = Logger.getLogger(ConstraintMatcherHandler.class); public static final AttachmentKey<SingleConstraintMatch> CONSTRAINT_KEY = AttachmentKey.create(SingleConstraintMatch.class); protected SecurityPathMatches matcher; protected HttpHandler securedHandler; protected HttpHandler unsecuredHandler; protected String errorPage; public ConstraintMatcherHandler(SecurityPathMatches matcher, HttpHandler securedHandler, HttpHandler unsecuredHandler, String errorPage) { this.matcher = matcher; this.securedHandler = securedHandler; this.unsecuredHandler = unsecuredHandler; this.errorPage = errorPage; } @Override public void handleRequest(HttpServerExchange exchange) throws Exception { log.debugv("ConstraintMatcherHandler: {0}", exchange.getRelativePath()); SingleConstraintMatch match = matcher.getSecurityInfo(exchange.getRelativePath(), exchange.getRequestMethod().toString()); if (match == null || (match.getRequiredRoles().isEmpty() && match.getEmptyRoleSemantic() == SecurityInfo.EmptyRoleSemantic.PERMIT)) { unsecuredHandler.handleRequest(exchange); return; } if (match.getRequiredRoles().isEmpty() && match.getEmptyRoleSemantic() == SecurityInfo.EmptyRoleSemantic.DENY) { if (errorPage != null) { exchange.setRequestPath(errorPage); exchange.setRelativePath(errorPage); exchange.setResolvedPath(errorPage); unsecuredHandler.handleRequest(exchange); } else { exchange.setResponseCode(403); exchange.endExchange(); } return; } if (match.getRequiredRoles().isEmpty() && match.getEmptyRoleSemantic() == SecurityInfo.EmptyRoleSemantic.PERMIT_AND_INJECT_IF_AUTHENTICATED) { boolean successfulAuthenticatedMethodFound = isSuccessfulAuthenticatedMethodFound(exchange); if(successfulAuthenticatedMethodFound) { //in case of authenticated we go for injecting headers exchange.putAttachment(CONSTRAINT_KEY, match); securedHandler.handleRequest(exchange); return; } else { //in case of not authenticated we just show the resource unsecuredHandler.handleRequest(exchange); return; } } log.debug("found constraint"); exchange.getSecurityContext().setAuthenticationRequired(); exchange.putAttachment(CONSTRAINT_KEY, match); securedHandler.handleRequest(exchange); } private boolean isSuccessfulAuthenticatedMethodFound(HttpServerExchange exchange) { boolean successfulAuthenticatedMethodFound = false; List<AuthenticationMechanism> authenticationMechanisms = exchange.getSecurityContext().getAuthenticationMechanisms(); for (AuthenticationMechanism authenticationMechanism : authenticationMechanisms) { AuthenticationMechanism.AuthenticationMechanismOutcome authenticationMechanismOutcome = authenticationMechanism.authenticate(exchange, exchange.getSecurityContext()); if(authenticationMechanismOutcome.equals(AuthenticationMechanism.AuthenticationMechanismOutcome.AUTHENTICATED)) { successfulAuthenticatedMethodFound = true; } } return successfulAuthenticatedMethodFound; } }