blob: ae74a051d6d0a5fbc2f77daf1004a6d15712c22a [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.camel.component.spring.security;
import java.util.List;
import javax.security.auth.Subject;
import org.apache.camel.CamelAuthorizationException;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.model.IdentifiedType;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.processor.DelegateProcessor;
import org.apache.camel.spi.AuthorizationPolicy;
import org.apache.camel.spi.RouteContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.event.AuthorizationFailureEvent;
import org.springframework.security.access.event.AuthorizedEvent;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.Assert;
public class SpringSecurityAuthorizationPolicy extends IdentifiedType implements AuthorizationPolicy, InitializingBean, ApplicationEventPublisherAware {
private static final transient Logger LOG = LoggerFactory.getLogger(SpringSecurityAuthorizationPolicy.class);
private AccessDecisionManager accessDecisionManager;
private AuthenticationManager authenticationManager;
private AuthenticationAdapter authenticationAdapter;
private ApplicationEventPublisher eventPublisher;
private SpringSecurityAccessPolicy accessPolicy;
private boolean alwaysReauthenticate;
private boolean useThreadSecurityContext = true;
public void beforeWrap(RouteContext routeContext, ProcessorDefinition<?> definition) {
}
public Processor wrap(RouteContext routeContext, Processor processor) {
// wrap the processor with authorizeDelegateProcessor
return new AuthorizeDelegateProcess(processor);
}
protected void beforeProcess(Exchange exchange) throws Exception {
List<ConfigAttribute> attributes = accessPolicy.getConfigAttributes();
try {
Authentication authToken = getAuthentication(exchange.getIn());
if (authToken == null) {
CamelAuthorizationException authorizationException =
new CamelAuthorizationException("Cannot find the Authentication instance.", exchange);
throw authorizationException;
}
Authentication authenticated = authenticateIfRequired(authToken);
// Attempt authorization with exchange
try {
this.accessDecisionManager.decide(authenticated, exchange, attributes);
} catch (AccessDeniedException accessDeniedException) {
exchange.getIn().setHeader(Exchange.AUTHENTICATION_FAILURE_POLICY_ID, getId());
AuthorizationFailureEvent event = new AuthorizationFailureEvent(exchange, attributes, authenticated,
accessDeniedException);
publishEvent(event);
throw accessDeniedException;
}
publishEvent(new AuthorizedEvent(exchange, attributes, authenticated));
} catch (RuntimeException exception) {
exchange.getIn().setHeader(Exchange.AUTHENTICATION_FAILURE_POLICY_ID, getId());
CamelAuthorizationException authorizationException =
new CamelAuthorizationException("Cannot access the processor which has been protected.", exchange, exception);
throw authorizationException;
}
}
protected Authentication getAuthentication(Message message) {
Subject subject = message.getHeader(Exchange.AUTHENTICATION, Subject.class);
Authentication answer = null;
if (subject != null) {
answer = getAuthenticationAdapter().toAuthentication(subject);
}
// try to get it from thread context as a fallback
if (answer == null && useThreadSecurityContext) {
answer = SecurityContextHolder.getContext().getAuthentication();
LOG.debug("Get the authentication from SecurityContextHolder");
}
return answer;
}
private class AuthorizeDelegateProcess extends DelegateProcessor {
AuthorizeDelegateProcess(Processor processor) {
super(processor);
}
public void process(Exchange exchange) throws Exception {
beforeProcess(exchange);
processNext(exchange);
}
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.authenticationManager, "An AuthenticationManager is required");
Assert.notNull(this.accessDecisionManager, "An AccessDecisionManager is required");
Assert.notNull(this.accessPolicy, "The accessPolicy is required");
}
private Authentication authenticateIfRequired(Authentication authentication) {
if (authentication.isAuthenticated() && !alwaysReauthenticate) {
LOG.debug("Previously Authenticated: {}", authentication);
return authentication;
}
authentication = authenticationManager.authenticate(authentication);
LOG.debug("Successfully Authenticated: {}", authentication);
return authentication;
}
private void publishEvent(ApplicationEvent event) {
if (this.eventPublisher != null) {
this.eventPublisher.publishEvent(event);
}
}
public AuthenticationAdapter getAuthenticationAdapter() {
if (authenticationAdapter == null) {
synchronized (this) {
if (authenticationAdapter != null) {
return authenticationAdapter;
} else {
authenticationAdapter = new DefaultAuthenticationAdapter();
}
}
}
return authenticationAdapter;
}
public void setAuthenticationAdapter(AuthenticationAdapter adapter) {
this.authenticationAdapter = adapter;
}
public AccessDecisionManager getAccessDecisionManager() {
return accessDecisionManager;
}
public AuthenticationManager getAuthenticationManager() {
return this.authenticationManager;
}
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.eventPublisher = applicationEventPublisher;
}
public void setSpringSecurityAccessPolicy(SpringSecurityAccessPolicy policy) {
this.accessPolicy = policy;
}
public SpringSecurityAccessPolicy getSpringSecurityAccessPolicy() {
return accessPolicy;
}
public boolean isAlwaysReauthenticate() {
return alwaysReauthenticate;
}
public void setAlwaysReauthenticate(boolean alwaysReauthenticate) {
this.alwaysReauthenticate = alwaysReauthenticate;
}
public boolean isUseThreadSecurityContext() {
return useThreadSecurityContext;
}
public void setUseThreadSecurityContext(boolean useThreadSecurityContext) {
this.useThreadSecurityContext = useThreadSecurityContext;
}
public void setAuthenticationManager(AuthenticationManager newManager) {
this.authenticationManager = newManager;
}
public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager) {
this.accessDecisionManager = accessDecisionManager;
}
}