/*
 * Copyright 2002-2013 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.web.authentication.session;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;

/**
 * A {@link SessionAuthenticationStrategy} that accepts multiple
 * {@link SessionAuthenticationStrategy} implementations to delegate to. Each
 * {@link SessionAuthenticationStrategy} is invoked in turn. The invocations are short
 * circuited if any exception, (i.e. SessionAuthenticationException) is thrown.
 *
 *

 * Typical usage would include having the following delegates (in this order)
 *

 *
 *

 *
{@link ConcurrentSessionControlAuthenticationStrategy} - verifies that a user is
 * allowed to authenticate (i.e. they have not already logged into the application.

 *
{@link SessionFixationProtectionStrategy} - If session fixation is desired,
 * {@link SessionFixationProtectionStrategy} should be after
 * {@link ConcurrentSessionControlAuthenticationStrategy} to prevent unnecessary
 * {@link HttpSession} creation if the
 * {@link ConcurrentSessionControlAuthenticationStrategy} rejects authentication.

 *
{@link RegisterSessionAuthenticationStrategy} - It is important this is after
 * {@link SessionFixationProtectionStrategy} so that the correct session is registered.
 *

 *

 *
 * @author Rob Winch
 * @since 3.2
 */
public class CompositeSessionAuthenticationStrategy
		implements SessionAuthenticationStrategy {
	private final Log logger = LogFactory.getLog(getClass());
	private final List<SessionAuthenticationStrategy> delegateStrategies;

	public CompositeSessionAuthenticationStrategy(
			List<SessionAuthenticationStrategy> delegateStrategies) {
		Assert.notEmpty(delegateStrategies, "delegateStrategies cannot be null or empty");
		for (SessionAuthenticationStrategy strategy : delegateStrategies) {
			if (strategy == null) {
				throw new IllegalArgumentException(
						"delegateStrategies cannot contain null entires. Got "
								+ delegateStrategies);
			}
		}
		this.delegateStrategies = delegateStrategies;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.springframework.security.web.authentication.session.
	 * SessionAuthenticationStrategy
	 * #onAuthentication(org.springframework.security.core.Authentication,
	 * javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	public void onAuthentication(Authentication authentication,
			HttpServletRequest request, HttpServletResponse response)
					throws SessionAuthenticationException {
		for (SessionAuthenticationStrategy delegate : this.delegateStrategies) {
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Delegating to " + delegate);
			}
			delegate.onAuthentication(authentication, request, response);
		}
	}

	@Override
	public String toString() {
		return getClass().getName() + " [delegateStrategies = " + this.delegateStrategies
				+ "]";
	}
}


/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * 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
 *
 *      https://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.springframework.security.ldap.authentication;

import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.ldap.search.LdapUserSearch;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.ldap.core.ContextSource;
import org.springframework.util.Assert;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Base class for the authenticator implementations.
 *
 * @author Luke Taylor
 */
public abstract class AbstractLdapAuthenticator implements LdapAuthenticator,
		InitializingBean, MessageSourceAware {
	// ~ Instance fields
	// ================================================================================================

	private final ContextSource contextSource;

	/**
	 * Optional search object which can be used to locate a user when a simple DN match
	 * isn't sufficient
	 */
	private LdapUserSearch userSearch;
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();

	/**
	 * The attributes which will be retrieved from the directory. Null means all
	 * attributes
	 */
	private String[] userAttributes = null;

	// private String[] userDnPattern = null;
	/** Stores the patterns which are used as potential DN matches */
	private MessageFormat[] userDnFormat = null;

	// ~ Constructors
	// ===================================================================================================

	/**
	 * Create an initialized instance with the {@link ContextSource} provided.
	 *
	 * @param contextSource
	 */
	public AbstractLdapAuthenticator(ContextSource contextSource) {
		Assert.notNull(contextSource, "contextSource must not be null.");
		this.contextSource = contextSource;
	}

	// ~ Methods
	// ========================================================================================================

	public void afterPropertiesSet() throws Exception {
		Assert.isTrue((userDnFormat != null) || (userSearch != null),
				"Either an LdapUserSearch or DN pattern (or both) must be supplied.");
	}

	protected ContextSource getContextSource() {
		return contextSource;
	}

	public String[] getUserAttributes() {
		return userAttributes;
	}

	/**
	 * Builds list of possible DNs for the user, worked out from the
	 * <tt>userDnPatterns</tt> property.
	 *
	 * @param username the user's login name
	 *
	 * @return the list of possible DN matches, empty if <tt>userDnPatterns</tt> wasn't
	 * set.
	 */
	protected List<String> getUserDns(String username) {
		if (userDnFormat == null) {
			return Collections.emptyList();
		}

		List<String> userDns = new ArrayList<>(userDnFormat.length);
		String[] args = new String[] { LdapEncoder.nameEncode(username) };

		synchronized (userDnFormat) {
			for (MessageFormat formatter : userDnFormat) {
				userDns.add(formatter.format(args));
			}
		}

		return userDns;
	}

	protected LdapUserSearch getUserSearch() {
		return userSearch;
	}

	public void setMessageSource(MessageSource messageSource) {
		Assert.notNull(messageSource, "Message source must not be null");
		this.messages = new MessageSourceAccessor(messageSource);
	}

	/**
	 * Sets the user attributes which will be retrieved from the directory.
	 *
	 * @param userAttributes
	 */
	public void setUserAttributes(String[] userAttributes) {
		Assert.notNull(userAttributes,
				"The userAttributes property cannot be set to null");
		this.userAttributes = userAttributes;
	}

	/**
	 * Sets the pattern which will be used to supply a DN for the user. The pattern should
	 * be the name relative to the root DN. The pattern argument {0} will contain the
	 * username. An example would be "cn={0},ou=people".
	 *
	 * @param dnPattern the array of patterns which will be tried when converting a
	 * username to a DN.
	 */
	public void setUserDnPatterns(String[] dnPattern) {
		Assert.notNull(dnPattern, "The array of DN patterns cannot be set to null");
		// this.userDnPattern = dnPattern;
		userDnFormat = new MessageFormat[dnPattern.length];

		for (int i = 0; i < dnPattern.length; i++) {
			userDnFormat[i] = new MessageFormat(dnPattern[i]);
		}
	}

	public void setUserSearch(LdapUserSearch userSearch) {
		Assert.notNull(userSearch, "The userSearch cannot be set to null");
		this.userSearch = userSearch;
	}
}


/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * 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
 *
 *      https://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.springframework.security.access.event;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationListener;

/**
 * Outputs interceptor-related application events to Commons Logging.
 * <p>
 * All failures are logged at the warning level, with success events logged at the
 * information level, and public invocation events logged at the debug level.
 * </p>
 *
 * @author Ben Alex
 */
public class LoggerListener implements ApplicationListener<AbstractAuthorizationEvent> {
	// ~ Static fields/initializers
	// =====================================================================================

	private static final Log logger = LogFactory.getLog(LoggerListener.class);

	// ~ Methods
	// ========================================================================================================

	public void onApplicationEvent(AbstractAuthorizationEvent event) {
		if (event instanceof AuthenticationCredentialsNotFoundEvent) {
			AuthenticationCredentialsNotFoundEvent authEvent = (AuthenticationCredentialsNotFoundEvent) event;

			if (logger.isWarnEnabled()) {
				logger.warn("Security interception failed due to: "
						+ authEvent.getCredentialsNotFoundException()
						+ "; secure object: " + authEvent.getSource()
						+ "; configuration attributes: "
						+ authEvent.getConfigAttributes());
			}
		}

		if (event instanceof AuthorizationFailureEvent) {
			AuthorizationFailureEvent authEvent = (AuthorizationFailureEvent) event;

			if (logger.isWarnEnabled()) {
				logger.warn("Security authorization failed due to: "
						+ authEvent.getAccessDeniedException()
						+ "; authenticated principal: " + authEvent.getAuthentication()
						+ "; secure object: " + authEvent.getSource()
						+ "; configuration attributes: "
						+ authEvent.getConfigAttributes());
			}
		}

		if (event instanceof AuthorizedEvent) {
			AuthorizedEvent authEvent = (AuthorizedEvent) event;

			if (logger.isInfoEnabled()) {
				logger.info("Security authorized for authenticated principal: "
						+ authEvent.getAuthentication() + "; secure object: "
						+ authEvent.getSource() + "; configuration attributes: "
						+ authEvent.getConfigAttributes());
			}
		}

		if (event instanceof PublicInvocationEvent) {
			PublicInvocationEvent authEvent = (PublicInvocationEvent) event;

			if (logger.isInfoEnabled()) {
				logger.info("Security interception not required for public secure object: "
						+ authEvent.getSource());
			}
		}
	}
}


/*
 * Copyright 2002-2013 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.config.annotation.web.configurers;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;

import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
import org.springframework.security.web.util.matcher.RequestMatcher;

/**
 * A base class for registering {@link RequestMatcher}'s. For example, it might allow for
 * specifying which {@link RequestMatcher} require a certain level of authorization.
 *
 * @author Rob Winch
 * @since 3.2
 *
 * @param <C> The object that is returned or Chained after creating the RequestMatcher
 *
 * @see ChannelSecurityConfigurer
 * @see UrlAuthorizationConfigurer
 * @see ExpressionUrlAuthorizationConfigurer
 */
public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends
		AbstractRequestMatcherRegistry<C> {
	private List<UrlMapping> urlMappings = new ArrayList<>();
	private List<RequestMatcher> unmappedMatchers;

	/**
	 * Gets the {@link UrlMapping} added by subclasses in
	 * {@link #chainRequestMatchers(java.util.List)}. May be empty.
	 *
	 * @return the {@link UrlMapping} added by subclasses in
	 * {@link #chainRequestMatchers(java.util.List)}
	 */
	final List<UrlMapping> getUrlMappings() {
		return urlMappings;
	}

	/**
	 * Adds a {@link UrlMapping} added by subclasses in
	 * {@link #chainRequestMatchers(java.util.List)} and resets the unmapped
	 * {@link RequestMatcher}'s.
	 *
	 * @param urlMapping {@link UrlMapping} the mapping to add
	 */
	final void addMapping(UrlMapping urlMapping) {
		this.unmappedMatchers = null;
		this.urlMappings.add(urlMapping);
	}

	/**
	 * Marks the {@link RequestMatcher}'s as unmapped and then calls
	 * {@link #chainRequestMatchersInternal(List)}.
	 *
	 * @param requestMatchers the {@link RequestMatcher} instances that were created
	 * @return the chained Object for the subclass which allows association of something
	 * else to the {@link RequestMatcher}
	 */
	protected final C chainRequestMatchers(List<RequestMatcher> requestMatchers) {
		this.unmappedMatchers = requestMatchers;
		return chainRequestMatchersInternal(requestMatchers);
	}

	/**
	 * Subclasses should implement this method for returning the object that is chained to
	 * the creation of the {@link RequestMatcher} instances.
	 *
	 * @param requestMatchers the {@link RequestMatcher} instances that were created
	 * @return the chained Object for the subclass which allows association of something
	 * else to the {@link RequestMatcher}
	 */
	protected abstract C chainRequestMatchersInternal(List<RequestMatcher> requestMatchers);

	/**
	 * Adds a {@link UrlMapping} added by subclasses in
	 * {@link #chainRequestMatchers(java.util.List)} at a particular index.
	 *
	 * @param index the index to add a {@link UrlMapping}
	 * @param urlMapping {@link UrlMapping} the mapping to add
	 */
	final void addMapping(int index, UrlMapping urlMapping) {
		this.urlMappings.add(index, urlMapping);
	}

	/**
	 * Creates the mapping of {@link RequestMatcher} to {@link Collection} of
	 * {@link ConfigAttribute} instances
	 *
	 * @return the mapping of {@link RequestMatcher} to {@link Collection} of
	 * {@link ConfigAttribute} instances. Cannot be null.
	 */
	final LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> createRequestMap() {
		if (unmappedMatchers != null) {
			throw new IllegalStateException(
					"An incomplete mapping was found for "
							+ unmappedMatchers
							+ ". Try completing it with something like requestUrls().<something>.hasRole('USER')");
		}

		LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
		for (UrlMapping mapping : getUrlMappings()) {
			RequestMatcher matcher = mapping.getRequestMatcher();
			Collection<ConfigAttribute> configAttrs = mapping.getConfigAttrs();
			requestMap.put(matcher, configAttrs);
		}
		return requestMap;
	}

	/**
	 * A mapping of {@link RequestMatcher} to {@link Collection} of
	 * {@link ConfigAttribute} instances
	 */
	static final class UrlMapping {
		private RequestMatcher requestMatcher;
		private Collection<ConfigAttribute> configAttrs;

		UrlMapping(RequestMatcher requestMatcher, Collection<ConfigAttribute> configAttrs) {
			this.requestMatcher = requestMatcher;
			this.configAttrs = configAttrs;
		}

		public RequestMatcher getRequestMatcher() {
			return requestMatcher;
		}

		public Collection<ConfigAttribute> getConfigAttrs() {
			return configAttrs;
		}
	}
}


/*
 * Copyright 2002-2016 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.web.authentication.logout;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;

/**
 * Implementation of the {@link LogoutSuccessHandler}. By default returns an HTTP status
 * code of {@code 200}. This is useful in REST-type scenarios where a redirect upon a
 * successful logout is not desired.
 *
 * @author Gunnar Hillert
 * @since 4.0.2
 */
public class HttpStatusReturningLogoutSuccessHandler implements LogoutSuccessHandler {

	private final HttpStatus httpStatusToReturn;

	/**
	 * Initialize the {@code HttpStatusLogoutSuccessHandler} with a user-defined
	 * {@link HttpStatus}.
	 *
	 * @param httpStatusToReturn Must not be {@code null}.
	 */
	public HttpStatusReturningLogoutSuccessHandler(HttpStatus httpStatusToReturn) {
		Assert.notNull(httpStatusToReturn, "The provided HttpStatus must not be null.");
		this.httpStatusToReturn = httpStatusToReturn;
	}

	/**
	 * Initialize the {@code HttpStatusLogoutSuccessHandler} with the default
	 * {@link HttpStatus#OK}.
	 */
	public HttpStatusReturningLogoutSuccessHandler() {
		this.httpStatusToReturn = HttpStatus.OK;
	}

	/**
	 * Implementation of
	 * {@link LogoutSuccessHandler#onLogoutSuccess(HttpServletRequest, HttpServletResponse, Authentication)}
	 * . Sets the status on the {@link HttpServletResponse}.
	 */
	public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		response.setStatus(this.httpStatusToReturn.value());
		response.getWriter().flush();
	}

}


/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * 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
 *
 *      https://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.springframework.security.web.access;

import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.util.Assert;

/**
 * Allows users to determine whether they have privileges for a given web URI.
 *
 * @author Ben Alex
 * @author Luke Taylor
 * @since 3.0
 */
public class DefaultWebInvocationPrivilegeEvaluator implements
		WebInvocationPrivilegeEvaluator {
	// ~ Static fields/initializers
	// =====================================================================================

	protected static final Log logger = LogFactory
			.getLog(DefaultWebInvocationPrivilegeEvaluator.class);

	// ~ Instance fields
	// ================================================================================================

	private final AbstractSecurityInterceptor securityInterceptor;

	// ~ Constructors
	// ===================================================================================================

	public DefaultWebInvocationPrivilegeEvaluator(
			AbstractSecurityInterceptor securityInterceptor) {
		Assert.notNull(securityInterceptor, "SecurityInterceptor cannot be null");
		Assert.isTrue(
				FilterInvocation.class.equals(securityInterceptor.getSecureObjectClass()),
				"AbstractSecurityInterceptor does not support FilterInvocations");
		Assert.notNull(securityInterceptor.getAccessDecisionManager(),
				"AbstractSecurityInterceptor must provide a non-null AccessDecisionManager");

		this.securityInterceptor = securityInterceptor;
	}

	// ~ Methods
	// ========================================================================================================

	/**
	 * Determines whether the user represented by the supplied <tt>Authentication</tt>
	 * object is allowed to invoke the supplied URI.
	 *
	 * @param uri the URI excluding the context path (a default context path setting will
	 * be used)
	 */
	public boolean isAllowed(String uri, Authentication authentication) {
		return isAllowed(null, uri, null, authentication);
	}

	/**
	 * Determines whether the user represented by the supplied <tt>Authentication</tt>
	 * object is allowed to invoke the supplied URI, with the given .
	 *

	 * Note the default implementation of <tt>FilterInvocationSecurityMetadataSource</tt>
	 * disregards the contextPath when evaluating which secure object
	 * metadata applies to a given request URI, so generally the contextPath
	 * is unimportant unless you are using a custom
	 * FilterInvocationSecurityMetadataSource.
	 *
	 * @param uri the URI excluding the context path
	 * @param contextPath the context path (may be null, in which case a default value
	 * will be used).
	 * @param method the HTTP method (or null, for any method)
	 * @param authentication the <tt>Authentication</tt> instance whose authorities should
	 * be used in evaluation whether access should be granted.
	 * @return true if access is allowed, false if denied
	 */
	public boolean isAllowed(String contextPath, String uri, String method,
			Authentication authentication) {
		Assert.notNull(uri, "uri parameter is required");

		FilterInvocation fi = new FilterInvocation(contextPath, uri, method);
		Collection<ConfigAttribute> attrs = securityInterceptor
				.obtainSecurityMetadataSource().getAttributes(fi);

		if (attrs == null) {
			if (securityInterceptor.isRejectPublicInvocations()) {
				return false;
			}

			return true;
		}

		if (authentication == null) {
			return false;
		}

		try {
			securityInterceptor.getAccessDecisionManager().decide(authentication, fi,
					attrs);
		}
		catch (AccessDeniedException unauthorized) {
			if (logger.isDebugEnabled()) {
				logger.debug(fi.toString() + " denied for " + authentication.toString(),
						unauthorized);
			}

			return false;
		}

		return true;
	}
}


/*
 * Copyright 2012-2016 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.web.servlet.util.matcher;

import java.util.Collections;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.http.HttpMethod;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestVariablesExtractor;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import org.springframework.web.servlet.handler.MatchableHandlerMapping;
import org.springframework.web.servlet.handler.RequestMatchResult;
import org.springframework.web.util.UrlPathHelper;

/**
 * A {@link RequestMatcher} that uses Spring MVC's {@link HandlerMappingIntrospector} to
 * match the path and extract variables.
 *
 * <p>
 * It is important to understand that Spring MVC's matching is relative to the servlet
 * path. This means if you have mapped any servlet to a path that starts with "/" and is
 * greater than one, you should also specify the {@link #setServletPath(String)} attribute
 * to differentiate mappings.
 * </p>
 *
 * @author Rob Winch
 * @since 4.1.1
 */
public class MvcRequestMatcher implements RequestMatcher, RequestVariablesExtractor {

	private final DefaultMatcher defaultMatcher = new DefaultMatcher();

	private final HandlerMappingIntrospector introspector;
	private final String pattern;
	private HttpMethod method;
	private String servletPath;

	public MvcRequestMatcher(HandlerMappingIntrospector introspector, String pattern) {
		this.introspector = introspector;
		this.pattern = pattern;
	}

	@Override
	public boolean matches(HttpServletRequest request) {
		if (this.method != null && !this.method.name().equals(request.getMethod())) {
			return false;
		}
		if (this.servletPath != null
				&& !this.servletPath.equals(request.getServletPath())) {
			return false;
		}
		MatchableHandlerMapping mapping = getMapping(request);
		if (mapping == null) {
			return this.defaultMatcher.matches(request);
		}
		RequestMatchResult matchResult = mapping.match(request, this.pattern);
		return matchResult != null;
	}

	private MatchableHandlerMapping getMapping(HttpServletRequest request) {
		try {
			return this.introspector.getMatchableHandlerMapping(request);
		}
		catch (Throwable t) {
			return null;
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.springframework.security.web.util.matcher.RequestVariablesExtractor#
	 * extractUriTemplateVariables(javax.servlet.http.HttpServletRequest)
	 */
	@Override
	public Map<String, String> extractUriTemplateVariables(HttpServletRequest request) {
		MatchableHandlerMapping mapping = getMapping(request);
		if (mapping == null) {
			return this.defaultMatcher.extractUriTemplateVariables(request);
		}
		RequestMatchResult result = mapping.match(request, this.pattern);
		return result == null ? Collections.<String, String>emptyMap()
				: result.extractUriTemplateVariables();
	}

	/**
	 * @param method the method to set
	 */
	public void setMethod(HttpMethod method) {
		this.method = method;
	}

	/**
	 * The servlet path to match on. The default is undefined which means any servlet
	 * path.
	 *
	 * @param servletPath the servletPath to set
	 */
	public void setServletPath(String servletPath) {
		this.servletPath = servletPath;
	}

	protected final String getServletPath() {
		return this.servletPath;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("Mvc [pattern='").append(this.pattern).append("'");

		if (this.servletPath != null) {
			sb.append(", servletPath='").append(this.servletPath).append("'");
		}

		if (this.method != null) {
			sb.append(", ").append(this.method);
		}

		sb.append("]");

		return sb.toString();
	}

	private class DefaultMatcher implements RequestMatcher, RequestVariablesExtractor {

		private final UrlPathHelper pathHelper = new UrlPathHelper();

		private final PathMatcher pathMatcher = new AntPathMatcher();

		@Override
		public boolean matches(HttpServletRequest request) {
			String lookupPath = this.pathHelper.getLookupPathForRequest(request);
			return matches(lookupPath);
		}

		private boolean matches(String lookupPath) {
			return this.pathMatcher.match(MvcRequestMatcher.this.pattern, lookupPath);
		}

		@Override
		public Map<String, String> extractUriTemplateVariables(
				HttpServletRequest request) {
			String lookupPath = this.pathHelper.getLookupPathForRequest(request);
			if (matches(lookupPath)) {
				return this.pathMatcher.extractUriTemplateVariables(
						MvcRequestMatcher.this.pattern, lookupPath);
			}
			return Collections.emptyMap();
		}
	}
}


/*
 * Copyright 2011-2016 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.samples.cas.web;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jasig.cas.client.util.CommonUtils;
import org.springframework.security.cas.authentication.CasAuthenticationToken;

/**
 *

 * {@link ProxyTicketSampleServlet} demonstrates how to obtain a proxy ticket and then use
 * it to make a remote call. To learn how proxy tickets work, see the Proxy CAS
 * Walkthrough
 *

 *
 * @author Rob Winch
 */
public final class ProxyTicketSampleServlet extends HttpServlet {
	/**
	 * This is the URL that will be called and authenticate a proxy ticket.
	 */
	private String targetUrl;

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// NOTE: The CasAuthenticationToken can also be obtained using
		// SecurityContextHolder.getContext().getAuthentication()
		final CasAuthenticationToken token = (CasAuthenticationToken) request
				.getUserPrincipal();
		// proxyTicket could be reused to make calls to the CAS service even if the
		// target url differs
		final String proxyTicket = token.getAssertion().getPrincipal()
				.getProxyTicketFor(targetUrl);

		// Make a remote call to ourself. This is a bit silly, but it works well to
		// demonstrate how to use proxy tickets.
		final String serviceUrl = targetUrl + "?ticket="
				+ URLEncoder.encode(proxyTicket, "UTF-8");
		String proxyResponse = CommonUtils.getResponseFromServer(serviceUrl, "UTF-8");

		// modify the response and write it out to inform the user that it was obtained
		// using a proxy ticket.
		proxyResponse = proxyResponse.replaceFirst("Secure Page",
				"Secure Page using a Proxy Ticket");
		proxyResponse = proxyResponse.replaceFirst("
", "
This page is rendered by "
				+ getClass().getSimpleName()
				+ " by making a remote call to the Secure Page using a proxy ticket ("
				+ proxyTicket + ") and inserts this message. ");
		final PrintWriter writer = response.getWriter();
		writer.write(proxyResponse);
	}

	/**
	 * Initialize the target URL. It allows for the host to change based upon the
	 * "cas.service.host" system property. If the property is not set, the default is
	 * "localhost:8443".
	 */
	@Override
	public void init() throws ServletException {
		super.init();
		String casServiceHost = System.getProperty("cas.service.host", "localhost:8443");
		targetUrl = "https://" + casServiceHost + "/cas-sample/secure/";
	}

	private static final long serialVersionUID = -7720161771819727775L;
}


/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * 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
 *
 *      https://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.springframework.security.web.savedrequest;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Provides request parameters, headers and cookies from either an original request or a
 * saved request.
 *
 *

 * Note that not all request parameters in the original request are emulated by this
 * wrapper. Nevertheless, the important data from the original request is emulated and
 * this should prove adequate for most purposes (in particular standard HTTP GET and POST
 * operations).
 *
 *

 * Added into a request by
 * {@link org.springframework.security.web.savedrequest.RequestCacheAwareFilter}.
 *
 * @author Andrey Grebnev
 * @author Ben Alex
 * @author Luke Taylor
 */
class SavedRequestAwareWrapper extends HttpServletRequestWrapper {
	// ~ Static fields/initializers
	// =====================================================================================

	protected static final Log logger = LogFactory.getLog(SavedRequestAwareWrapper.class);
	protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");

	/** The default Locale if none are specified. */
	protected static Locale defaultLocale = Locale.getDefault();

	// ~ Instance fields
	// ================================================================================================

	protected SavedRequest savedRequest = null;

	/**
	 * The set of SimpleDateFormat formats to use in getDateHeader(). Notice that because
	 * SimpleDateFormat is not thread-safe, we can't declare formats[] as a static
	 * variable.
	 */
	protected final SimpleDateFormat[] formats = new SimpleDateFormat[3];

	// ~ Constructors
	// ===================================================================================================

	public SavedRequestAwareWrapper(SavedRequest saved, HttpServletRequest request) {
		super(request);
		savedRequest = saved;

		formats[0] = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
		formats[1] = new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US);
		formats[2] = new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US);

		formats[0].setTimeZone(GMT_ZONE);
		formats[1].setTimeZone(GMT_ZONE);
		formats[2].setTimeZone(GMT_ZONE);
	}

	// ~ Methods
	// ========================================================================================================

	@Override
	public long getDateHeader(String name) {
		String value = getHeader(name);

		if (value == null) {
			return -1L;
		}

		// Attempt to convert the date header in a variety of formats
		long result = FastHttpDateFormat.parseDate(value, formats);

		if (result != -1L) {
			return result;
		}

		throw new IllegalArgumentException(value);
	}

	@Override
	public String getHeader(String name) {
		List<String> values = savedRequest.getHeaderValues(name);

		return values.isEmpty() ? null : values.get(0);
	}

	@Override
	@SuppressWarnings("unchecked")
	public Enumeration getHeaderNames() {
		return new Enumerator<>(savedRequest.getHeaderNames());
	}

	@Override
	@SuppressWarnings("unchecked")
	public Enumeration getHeaders(String name) {
		return new Enumerator<>(savedRequest.getHeaderValues(name));
	}

	@Override
	public int getIntHeader(String name) {
		String value = getHeader(name);

		if (value == null) {
			return -1;
		}
		else {
			return Integer.parseInt(value);
		}
	}

	@Override
	public Locale getLocale() {
		List<Locale> locales = savedRequest.getLocales();

		return locales.isEmpty() ? Locale.getDefault() : locales.get(0);
	}

	@Override
	@SuppressWarnings("unchecked")
	public Enumeration getLocales() {
		List<Locale> locales = savedRequest.getLocales();

		if (locales.isEmpty()) {
			// Fall back to default locale
			locales = new ArrayList<>(1);
			locales.add(Locale.getDefault());
		}

		return new Enumerator<>(locales);
	}

	@Override
	public String getMethod() {
		return savedRequest.getMethod();
	}

	/**
	 * If the parameter is available from the wrapped request then the request has been
	 * forwarded/included to a URL with parameters, either supplementing or overriding the
	 * saved request values.
	 *

	 * In this case, the value from the wrapped request should be used.
	 *

	 * If the value from the wrapped request is null, an attempt will be made to retrieve
	 * the parameter from the saved request.
	 */
	@Override
	public String getParameter(String name) {
		String value = super.getParameter(name);

		if (value != null) {
			return value;
		}

		String[] values = savedRequest.getParameterValues(name);

		if (values == null || values.length == 0) {
			return null;
		}

		return values[0];
	}

	@Override
	@SuppressWarnings("unchecked")
	public Map getParameterMap() {
		Set<String> names = getCombinedParameterNames();
		Map<String, String[]> parameterMap = new HashMap<>(names.size());

		for (String name : names) {
			parameterMap.put(name, getParameterValues(name));
		}

		return parameterMap;
	}

	@SuppressWarnings("unchecked")
	private Set<String> getCombinedParameterNames() {
		Set<String> names = new HashSet<>();
		names.addAll(super.getParameterMap().keySet());
		names.addAll(savedRequest.getParameterMap().keySet());

		return names;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Enumeration getParameterNames() {
		return new Enumerator(getCombinedParameterNames());
	}

	@Override
	public String[] getParameterValues(String name) {
		String[] savedRequestParams = savedRequest.getParameterValues(name);
		String[] wrappedRequestParams = super.getParameterValues(name);

		if (savedRequestParams == null) {
			return wrappedRequestParams;
		}

		if (wrappedRequestParams == null) {
			return savedRequestParams;
		}

		// We have parameters in both saved and wrapped requests so have to merge them
		List<String> wrappedParamsList = Arrays.asList(wrappedRequestParams);
		List<String> combinedParams = new ArrayList<>(wrappedParamsList);

		// We want to add all parameters of the saved request *apart from* duplicates of
		// those already added
		for (String savedRequestParam : savedRequestParams) {
			if (!wrappedParamsList.contains(savedRequestParam)) {
				combinedParams.add(savedRequestParam);
			}
		}

		return combinedParams.toArray(new String[combinedParams.size()]);
	}
}


/*
 * Copyright 2002-2016 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.web.authentication.preauth;

import javax.servlet.http.HttpServletRequest;

import org.springframework.util.Assert;

/**
 * A simple pre-authenticated filter which obtains the username from request attributes,
 * for use with SSO systems such as
 * Stanford WebAuth or
 * Shibboleth.
 *

 * As with most pre-authenticated scenarios, it is essential that the external
 * authentication system is set up correctly as this filter does no authentication
 * whatsoever.
 *

 * The property {@code principalEnvironmentVariable} is the name of the request attribute
 * that contains the username. It defaults to "REMOTE_USER" for compatibility with WebAuth
 * and Shibboleth.
 *

 * If the environment variable is missing from the request,
 * {@code getPreAuthenticatedPrincipal} will throw an exception. You can override this
 * behaviour by setting the {@code exceptionIfVariableMissing} property.
 *
 *
 * @author Milan Sevcik
 * @since 4.2
 */
public class RequestAttributeAuthenticationFilter
		extends AbstractPreAuthenticatedProcessingFilter {
	private String principalEnvironmentVariable = "REMOTE_USER";
	private String credentialsEnvironmentVariable;
	private boolean exceptionIfVariableMissing = true;

	/**
	 * Read and returns the variable named by {@code principalEnvironmentVariable} from
	 * the request.
	 *
	 * @throws PreAuthenticatedCredentialsNotFoundException if the environment variable is
	 * missing and {@code exceptionIfVariableMissing} is set to {@code true}.
	 */
	protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
		String principal = (String) request.getAttribute(principalEnvironmentVariable);

		if (principal == null && exceptionIfVariableMissing) {
			throw new PreAuthenticatedCredentialsNotFoundException(
					principalEnvironmentVariable + " variable not found in request.");
		}

		return principal;
	}

	/**
	 * Credentials aren't usually applicable, but if a
	 * {@code credentialsEnvironmentVariable} is set, this will be read and used as the
	 * credentials value. Otherwise a dummy value will be used.
	 */
	protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
		if (credentialsEnvironmentVariable != null) {
			return request.getAttribute(credentialsEnvironmentVariable);
		}

		return "N/A";
	}

	public void setPrincipalEnvironmentVariable(String principalEnvironmentVariable) {
		Assert.hasText(principalEnvironmentVariable,
				"principalEnvironmentVariable must not be empty or null");
		this.principalEnvironmentVariable = principalEnvironmentVariable;
	}

	public void setCredentialsEnvironmentVariable(String credentialsEnvironmentVariable) {
		Assert.hasText(credentialsEnvironmentVariable,
				"credentialsEnvironmentVariable must not be empty or null");
		this.credentialsEnvironmentVariable = credentialsEnvironmentVariable;
	}

	/**
	 * Defines whether an exception should be raised if the principal variable is missing.
	 * Defaults to {@code true}.
	 *
	 * @param exceptionIfVariableMissing set to {@code false} to override the default
	 * behaviour and allow the request to proceed if no variable is found.
	 */
	public void setExceptionIfVariableMissing(boolean exceptionIfVariableMissing) {
		this.exceptionIfVariableMissing = exceptionIfVariableMissing;
	}
}


/*
 * Copyright 2002-2016 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.web.authentication.session;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.util.Assert;

/**
 * Strategy used to register a user with the {@link SessionRegistry} after successful
 * {@link Authentication}.
 *
 *

 * {@link RegisterSessionAuthenticationStrategy} is typically used in combination with
 * {@link CompositeSessionAuthenticationStrategy} and
 * {@link ConcurrentSessionControlAuthenticationStrategy}, but can be used on its own if
 * tracking of sessions is desired but no need to control concurrency.
 *
 *

 * NOTE: When using a {@link SessionRegistry} it is important that all sessions (including
 * timed out sessions) are removed. This is typically done by adding
 * {@link HttpSessionEventPublisher}.
 *
 * @see CompositeSessionAuthenticationStrategy
 *
 * @author Luke Taylor
 * @author Rob Winch
 * @since 3.2
 */
public class RegisterSessionAuthenticationStrategy implements
		SessionAuthenticationStrategy {
	private final SessionRegistry sessionRegistry;

	/**
	 * @param sessionRegistry the session registry which should be updated when the
	 * authenticated session is changed.
	 */
	public RegisterSessionAuthenticationStrategy(SessionRegistry sessionRegistry) {
		Assert.notNull(sessionRegistry, "The sessionRegistry cannot be null");
		this.sessionRegistry = sessionRegistry;
	}

	/**
	 * In addition to the steps from the superclass, the sessionRegistry will be updated
	 * with the new session information.
	 */
	public void onAuthentication(Authentication authentication,
			HttpServletRequest request, HttpServletResponse response) {
		sessionRegistry.registerNewSession(request.getSession().getId(),
				authentication.getPrincipal());
	}
}


/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * 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
 *
 *      https://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.springframework.security.access.intercept.aopalliance;

import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.access.method.MethodSecurityMetadataSource;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * Provides security interception of AOP Alliance based method invocations.
 *

 * The SecurityMetadataSource required by this security interceptor is of
 * type {@link MethodSecurityMetadataSource}. This is shared with the AspectJ based
 * security interceptor (AspectJSecurityInterceptor), since both work with
 * Java Methods.
 *

 * Refer to {@link AbstractSecurityInterceptor} for details on the workflow.
 *
 * @author Ben Alex
 * @author Rob Winch
 */
public class MethodSecurityInterceptor extends AbstractSecurityInterceptor implements
		MethodInterceptor {
	// ~ Instance fields
	// ================================================================================================

	private MethodSecurityMetadataSource securityMetadataSource;

	// ~ Methods
	// ========================================================================================================

	public Class<?> getSecureObjectClass() {
		return MethodInvocation.class;
	}

	/**
	 * This method should be used to enforce security on a MethodInvocation.
	 *
	 * @param mi The method being invoked which requires a security decision
	 *
	 * @return The returned value from the method invocation (possibly modified by the
	 * {@code AfterInvocationManager}).
	 *
	 * @throws Throwable if any error occurs
	 */
	public Object invoke(MethodInvocation mi) throws Throwable {
		InterceptorStatusToken token = super.beforeInvocation(mi);

		Object result;
		try {
			result = mi.proceed();
		}
		finally {
			super.finallyInvocation(token);
		}
		return super.afterInvocation(token, result);
	}

	public MethodSecurityMetadataSource getSecurityMetadataSource() {
		return this.securityMetadataSource;
	}

	public SecurityMetadataSource obtainSecurityMetadataSource() {
		return this.securityMetadataSource;
	}

	public void setSecurityMetadataSource(MethodSecurityMetadataSource newSource) {
		this.securityMetadataSource = newSource;
	}
}


/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * 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
 *
 *      https://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 sample.contact;

import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import org.springframework.transaction.annotation.Transactional;

import org.springframework.beans.factory.InitializingBean;

import org.springframework.context.support.ApplicationObjectSupport;

import org.springframework.util.Assert;

import java.util.List;
import java.util.Random;

/**
 * Concrete implementation of {@link ContactManager}.
 *
 * @author Ben Alex
 */
@Transactional
public class ContactManagerBackend extends ApplicationObjectSupport implements
		ContactManager, InitializingBean {
	// ~ Instance fields
	// ================================================================================================

	private ContactDao contactDao;
	private MutableAclService mutableAclService;
	private int counter = 1000;

	// ~ Methods
	// ========================================================================================================

	public void afterPropertiesSet() throws Exception {
		Assert.notNull(contactDao, "contactDao required");
		Assert.notNull(mutableAclService, "mutableAclService required");
	}

	public void addPermission(Contact contact, Sid recipient, Permission permission) {
		MutableAcl acl;
		ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());

		try {
			acl = (MutableAcl) mutableAclService.readAclById(oid);
		}
		catch (NotFoundException nfe) {
			acl = mutableAclService.createAcl(oid);
		}

		acl.insertAce(acl.getEntries().size(), permission, recipient, true);
		mutableAclService.updateAcl(acl);

		logger.debug("Added permission " + permission + " for Sid " + recipient
				+ " contact " + contact);
	}

	public void create(Contact contact) {
		// Create the Contact itself
		contact.setId(Long.valueOf(counter++));
		contactDao.create(contact);

		// Grant the current principal administrative permission to the contact
		addPermission(contact, new PrincipalSid(getUsername()),
				BasePermission.ADMINISTRATION);

		if (logger.isDebugEnabled()) {
			logger.debug("Created contact " + contact
					+ " and granted admin permission to recipient " + getUsername());
		}
	}

	public void delete(Contact contact) {
		contactDao.delete(contact.getId());

		// Delete the ACL information as well
		ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
		mutableAclService.deleteAcl(oid, false);

		if (logger.isDebugEnabled()) {
			logger.debug("Deleted contact " + contact + " including ACL permissions");
		}
	}

	public void deletePermission(Contact contact, Sid recipient, Permission permission) {
		ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
		MutableAcl acl = (MutableAcl) mutableAclService.readAclById(oid);

		// Remove all permissions associated with this particular recipient (string
		// equality to KISS)
		List<AccessControlEntry> entries = acl.getEntries();

		for (int i = 0; i < entries.size(); i++) {
			if (entries.get(i).getSid().equals(recipient)
					&& entries.get(i).getPermission().equals(permission)) {
				acl.deleteAce(i);
			}
		}

		mutableAclService.updateAcl(acl);

		if (logger.isDebugEnabled()) {
			logger.debug("Deleted contact " + contact + " ACL permissions for recipient "
					+ recipient);
		}
	}

	@Transactional(readOnly = true)
	public List<Contact> getAll() {
		logger.debug("Returning all contacts");

		return contactDao.findAll();
	}

	@Transactional(readOnly = true)
	public List<String> getAllRecipients() {
		logger.debug("Returning all recipients");

		return contactDao.findAllPrincipals();
	}

	@Transactional(readOnly = true)
	public Contact getById(Long id) {
		if (logger.isDebugEnabled()) {
			logger.debug("Returning contact with id: " + id);
		}

		return contactDao.getById(id);
	}

	/**
	 * This is a public method.
	 */
	@Transactional(readOnly = true)
	public Contact getRandomContact() {
		logger.debug("Returning random contact");

		Random rnd = new Random();
		List<Contact> contacts = contactDao.findAll();
		int getNumber = rnd.nextInt(contacts.size());

		return contacts.get(getNumber);
	}

	protected String getUsername() {
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();

		if (auth.getPrincipal() instanceof UserDetails) {
			return ((UserDetails) auth.getPrincipal()).getUsername();
		}
		else {
			return auth.getPrincipal().toString();
		}
	}

	public void setContactDao(ContactDao contactDao) {
		this.contactDao = contactDao;
	}

	public void setMutableAclService(MutableAclService mutableAclService) {
		this.mutableAclService = mutableAclService;
	}

	public void update(Contact contact) {
		contactDao.update(contact);

		logger.debug("Updated contact " + contact);
	}
}


/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * 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
 *
 *      https://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.springframework.security.acls.domain;

import java.io.Serializable;

import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;

import org.springframework.security.acls.model.AclCache;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.util.FieldUtils;
import org.springframework.util.Assert;

/**
 * Simple implementation of {@link AclCache} that delegates to EH-CACHE.
 * <p>
 * Designed to handle the transient fields in {@link AclImpl}. Note that this
 * implementation assumes all {@link AclImpl} instances share the same
 * {@link PermissionGrantingStrategy} and {@link AclAuthorizationStrategy} instances.
 *
 * @author Ben Alex
 */
public class EhCacheBasedAclCache implements AclCache {
	// ~ Instance fields
	// ================================================================================================

	private final Ehcache cache;
	private PermissionGrantingStrategy permissionGrantingStrategy;
	private AclAuthorizationStrategy aclAuthorizationStrategy;

	// ~ Constructors
	// ===================================================================================================

	public EhCacheBasedAclCache(Ehcache cache,
			PermissionGrantingStrategy permissionGrantingStrategy,
			AclAuthorizationStrategy aclAuthorizationStrategy) {
		Assert.notNull(cache, "Cache required");
		Assert.notNull(permissionGrantingStrategy, "PermissionGrantingStrategy required");
		Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
		this.cache = cache;
		this.permissionGrantingStrategy = permissionGrantingStrategy;
		this.aclAuthorizationStrategy = aclAuthorizationStrategy;
	}

	// ~ Methods
	// ========================================================================================================

	public void evictFromCache(Serializable pk) {
		Assert.notNull(pk, "Primary key (identifier) required");

		MutableAcl acl = getFromCache(pk);

		if (acl != null) {
			cache.remove(acl.getId());
			cache.remove(acl.getObjectIdentity());
		}
	}

	public void evictFromCache(ObjectIdentity objectIdentity) {
		Assert.notNull(objectIdentity, "ObjectIdentity required");

		MutableAcl acl = getFromCache(objectIdentity);

		if (acl != null) {
			cache.remove(acl.getId());
			cache.remove(acl.getObjectIdentity());
		}
	}

	public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
		Assert.notNull(objectIdentity, "ObjectIdentity required");

		Element element = null;

		try {
			element = cache.get(objectIdentity);
		}
		catch (CacheException ignored) {
		}

		if (element == null) {
			return null;
		}

		return initializeTransientFields((MutableAcl) element.getValue());
	}

	public MutableAcl getFromCache(Serializable pk) {
		Assert.notNull(pk, "Primary key (identifier) required");

		Element element = null;

		try {
			element = cache.get(pk);
		}
		catch (CacheException ignored) {
		}

		if (element == null) {
			return null;
		}

		return initializeTransientFields((MutableAcl) element.getValue());
	}

	public void putInCache(MutableAcl acl) {
		Assert.notNull(acl, "Acl required");
		Assert.notNull(acl.getObjectIdentity(), "ObjectIdentity required");
		Assert.notNull(acl.getId(), "ID required");

		if (this.aclAuthorizationStrategy == null) {
			if (acl instanceof AclImpl) {
				this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils
						.getProtectedFieldValue("aclAuthorizationStrategy", acl);
				this.permissionGrantingStrategy = (PermissionGrantingStrategy) FieldUtils
						.getProtectedFieldValue("permissionGrantingStrategy", acl);
			}
		}

		if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
			putInCache((MutableAcl) acl.getParentAcl());
		}

		cache.put(new Element(acl.getObjectIdentity(), acl));
		cache.put(new Element(acl.getId(), acl));
	}

	private MutableAcl initializeTransientFields(MutableAcl value) {
		if (value instanceof AclImpl) {
			FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value,
					this.aclAuthorizationStrategy);
			FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value,
					this.permissionGrantingStrategy);
		}

		if (value.getParentAcl() != null) {
			initializeTransientFields((MutableAcl) value.getParentAcl());
		}
		return value;
	}

	public void clearCache() {
		cache.removeAll();
	}
}


/*
 * Copyright 2002-2013 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.config.annotation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.core.GenericTypeResolver;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;

/**
 * A base class for {@link SecurityConfigurer} that allows subclasses to only implement
 * the methods they are interested in. It also provides a mechanism for using the
 * {@link SecurityConfigurer} and when done gaining access to the {@link SecurityBuilder}
 * that is being configured.
 *
 * @author Rob Winch
 * @author Wallace Wadge
 *
 * @param <O> The Object being built by B
 * @param <B> The Builder that is building O and is configured by
 * {@link SecurityConfigurerAdapter}
 */
public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
		implements SecurityConfigurer<O, B> {
	private B securityBuilder;

	private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor();

	public void init(B builder) throws Exception {
	}

	public void configure(B builder) throws Exception {
	}

	/**
	 * Return the {@link SecurityBuilder} when done using the {@link SecurityConfigurer}.
	 * This is useful for method chaining.
	 *
	 * @return the {@link SecurityBuilder} for further customizations
	 */
	public B and() {
		return getBuilder();
	}

	/**
	 * Gets the {@link SecurityBuilder}. Cannot be null.
	 *
	 * @return the {@link SecurityBuilder}
	 * @throws IllegalStateException if {@link SecurityBuilder} is null
	 */
	protected final B getBuilder() {
		if (securityBuilder == null) {
			throw new IllegalStateException("securityBuilder cannot be null");
		}
		return securityBuilder;
	}

	/**
	 * Performs post processing of an object. The default is to delegate to the
	 * {@link ObjectPostProcessor}.
	 *
	 * @param object the Object to post process
	 * @return the possibly modified Object to use
	 */
	@SuppressWarnings("unchecked")
	protected <T> T postProcess(T object) {
		return (T) this.objectPostProcessor.postProcess(object);
	}

	/**
	 * Adds an {@link ObjectPostProcessor} to be used for this
	 * {@link SecurityConfigurerAdapter}. The default implementation does nothing to the
	 * object.
	 *
	 * @param objectPostProcessor the {@link ObjectPostProcessor} to use
	 */
	public void addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
		this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor);
	}

	/**
	 * Sets the {@link SecurityBuilder} to be used. This is automatically set when using
	 * {@link AbstractConfiguredSecurityBuilder#apply(SecurityConfigurerAdapter)}
	 *
	 * @param builder the {@link SecurityBuilder} to set
	 */
	public void setBuilder(B builder) {
		this.securityBuilder = builder;
	}

	/**
	 * An {@link ObjectPostProcessor} that delegates work to numerous
	 * {@link ObjectPostProcessor} implementations.
	 *
	 * @author Rob Winch
	 */
	private static final class CompositeObjectPostProcessor implements
			ObjectPostProcessor<Object> {
		private List<ObjectPostProcessor<? extends Object>> postProcessors = new ArrayList<ObjectPostProcessor<?>>();

		@SuppressWarnings({ "rawtypes", "unchecked" })
		public Object postProcess(Object object) {
			for (ObjectPostProcessor opp : postProcessors) {
				Class<?> oppClass = opp.getClass();
				Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass,
						ObjectPostProcessor.class);
				if (oppType == null || oppType.isAssignableFrom(object.getClass())) {
					object = opp.postProcess(object);
				}
			}
			return object;
		}

		/**
		 * Adds an {@link ObjectPostProcessor} to use
		 * @param objectPostProcessor the {@link ObjectPostProcessor} to add
		 * @return true if the {@link ObjectPostProcessor} was added, else false
		 */
		private boolean addObjectPostProcessor(
				ObjectPostProcessor<? extends Object> objectPostProcessor) {
			boolean result = this.postProcessors.add(objectPostProcessor);
			Collections.sort(postProcessors, AnnotationAwareOrderComparator.INSTANCE);
			return result;
		}
	}
}


/*
 * Copyright 2002-2016 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.web.authentication;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.WebAttributes;

/**
 * <tt>AuthenticationSuccessHandler</tt> which can be configured with a default URL which
 * users should be sent to upon successful authentication.
 * <p>
 * The logic used is that of the {@link AbstractAuthenticationTargetUrlRequestHandler
 * parent class}.
 *
 * @author Luke Taylor
 * @since 3.0
 */
public class SimpleUrlAuthenticationSuccessHandler extends
		AbstractAuthenticationTargetUrlRequestHandler implements
		AuthenticationSuccessHandler {

	public SimpleUrlAuthenticationSuccessHandler() {
	}

	/**
	 * Constructor which sets the <tt>defaultTargetUrl</tt> property of the base class.
	 * @param defaultTargetUrl the URL to which the user should be redirected on
	 * successful authentication.
	 */
	public SimpleUrlAuthenticationSuccessHandler(String defaultTargetUrl) {
		setDefaultTargetUrl(defaultTargetUrl);
	}

	/**
	 * Calls the parent class {@code handle()} method to forward or redirect to the target
	 * URL, and then calls {@code clearAuthenticationAttributes()} to remove any leftover
	 * session data.
	 */
	public void onAuthenticationSuccess(HttpServletRequest request,
			HttpServletResponse response, Authentication authentication)
			throws IOException, ServletException {

		handle(request, response, authentication);
		clearAuthenticationAttributes(request);
	}

	/**
	 * Removes temporary authentication-related data which may have been stored in the
	 * session during the authentication process.
	 */
	protected final void clearAuthenticationAttributes(HttpServletRequest request) {
		HttpSession session = request.getSession(false);

		if (session == null) {
			return;
		}

		session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
	}
}


/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * 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
 *
 *      https://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.springframework.security.util;

import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;

/**
 * Offers static methods for directly manipulating fields.
 *
 * @author Ben Alex
 */
public final class FieldUtils {

	// ~ Methods
	// ========================================================================================================
	/**
	 * Attempts to locate the specified field on the class.
	 *
	 * @param clazz the class definition containing the field
	 * @param fieldName the name of the field to locate
	 *
	 * @return the Field (never null)
	 *
	 * @throws IllegalStateException if field could not be found
	 */
	public static Field getField(Class<?> clazz, String fieldName)
			throws IllegalStateException {
		Assert.notNull(clazz, "Class required");
		Assert.hasText(fieldName, "Field name required");

		try {
			return clazz.getDeclaredField(fieldName);
		}
		catch (NoSuchFieldException nsf) {
			// Try superclass
			if (clazz.getSuperclass() != null) {
				return getField(clazz.getSuperclass(), fieldName);
			}

			throw new IllegalStateException("Could not locate field '" + fieldName
					+ "' on class " + clazz);
		}
	}

	/**
	 * Returns the value of a (nested) field on a bean. Intended for testing.
	 * @param bean the object
	 * @param fieldName the field name, with "." separating nested properties
	 * @return the value of the nested field
	 */
	public static Object getFieldValue(Object bean, String fieldName)
			throws IllegalAccessException {
		Assert.notNull(bean, "Bean cannot be null");
		Assert.hasText(fieldName, "Field name required");
		String[] nestedFields = StringUtils.tokenizeToStringArray(fieldName, ".");
		Class<?> componentClass = bean.getClass();
		Object value = bean;

		for (String nestedField : nestedFields) {
			Field field = getField(componentClass, nestedField);
			field.setAccessible(true);
			value = field.get(value);
			if (value != null) {
				componentClass = value.getClass();
			}
		}

		return value;

	}

	public static Object getProtectedFieldValue(String protectedField, Object object) {
		Field field = FieldUtils.getField(object.getClass(), protectedField);

		try {
			field.setAccessible(true);

			return field.get(object);
		}
		catch (Exception ex) {
			ReflectionUtils.handleReflectionException(ex);

			return null; // unreachable - previous line throws exception
		}
	}

	public static void setProtectedFieldValue(String protectedField, Object object,
			Object newValue) {
		Field field = FieldUtils.getField(object.getClass(), protectedField);

		try {
			field.setAccessible(true);
			field.set(object, newValue);
		}
		catch (Exception ex) {
			ReflectionUtils.handleReflectionException(ex);
		}
	}
}


/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * 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
 *
 *      https://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.springframework.security.cas.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jasig.cas.client.util.CommonUtils;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

/**
 * Used by the ExceptionTranslationFilter to commence authentication via the
 * JA-SIG Central Authentication Service (CAS).
 *

 * The user's browser will be redirected to the JA-SIG CAS enterprise-wide login page.
 * This page is specified by the loginUrl property. Once login is complete,
 * the CAS login page will redirect to the page indicated by the service
 * property. The service is a HTTP URL belonging to the current application.
 * The service URL is monitored by the {@link CasAuthenticationFilter}, which
 * will validate the CAS login was successful.
 *
 * @author Ben Alex
 * @author Scott Battaglia
 */
public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint,
		InitializingBean {
	// ~ Instance fields
	// ================================================================================================
	private ServiceProperties serviceProperties;

	private String loginUrl;

	/**
	 * Determines whether the Service URL should include the session id for the specific
	 * user. As of CAS 3.0.5, the session id will automatically be stripped. However,
	 * older versions of CAS (i.e. CAS 2), do not automatically strip the session
	 * identifier (this is a bug on the part of the older server implementations), so an
	 * option to disable the session encoding is provided for backwards compatibility.
	 *
	 * By default, encoding is enabled.
	 */
	private boolean encodeServiceUrlWithSessionId = true;

	// ~ Methods
	// ========================================================================================================

	public void afterPropertiesSet() throws Exception {
		Assert.hasLength(this.loginUrl, "loginUrl must be specified");
		Assert.notNull(this.serviceProperties, "serviceProperties must be specified");
		Assert.notNull(this.serviceProperties.getService(),
				"serviceProperties.getService() cannot be null.");
	}

	public final void commence(final HttpServletRequest servletRequest,
			final HttpServletResponse response,
			final AuthenticationException authenticationException) throws IOException,
			ServletException {

		final String urlEncodedService = createServiceUrl(servletRequest, response);
		final String redirectUrl = createRedirectUrl(urlEncodedService);

		preCommence(servletRequest, response);

		response.sendRedirect(redirectUrl);
	}

	/**
	 * Constructs a new Service Url. The default implementation relies on the CAS client
	 * to do the bulk of the work.
	 * @param request the HttpServletRequest
	 * @param response the HttpServlet Response
	 * @return the constructed service url. CANNOT be NULL.
	 */
	protected String createServiceUrl(final HttpServletRequest request,
			final HttpServletResponse response) {
		return CommonUtils.constructServiceUrl(null, response,
				this.serviceProperties.getService(), null,
				this.serviceProperties.getArtifactParameter(),
				this.encodeServiceUrlWithSessionId);
	}

	/**
	 * Constructs the Url for Redirection to the CAS server. Default implementation relies
	 * on the CAS client to do the bulk of the work.
	 *
	 * @param serviceUrl the service url that should be included.
	 * @return the redirect url. CANNOT be NULL.
	 */
	protected String createRedirectUrl(final String serviceUrl) {
		return CommonUtils.constructRedirectUrl(this.loginUrl,
				this.serviceProperties.getServiceParameter(), serviceUrl,
				this.serviceProperties.isSendRenew(), false);
	}

	/**
	 * Template method for you to do your own pre-processing before the redirect occurs.
	 *
	 * @param request the HttpServletRequest
	 * @param response the HttpServletResponse
	 */
	protected void preCommence(final HttpServletRequest request,
			final HttpServletResponse response) {

	}

	/**
	 * The enterprise-wide CAS login URL. Usually something like
	 * https://www.mycompany.com/cas/login.
	 *
	 * @return the enterprise-wide CAS login URL
	 */
	public final String getLoginUrl() {
		return this.loginUrl;
	}

	public final ServiceProperties getServiceProperties() {
		return this.serviceProperties;
	}

	public final void setLoginUrl(final String loginUrl) {
		this.loginUrl = loginUrl;
	}

	public final void setServiceProperties(final ServiceProperties serviceProperties) {
		this.serviceProperties = serviceProperties;
	}

	/**
	 * Sets whether to encode the service url with the session id or not.
	 *
	 * @param encodeServiceUrlWithSessionId whether to encode the service url with the
	 * session id or not.
	 */
	public final void setEncodeServiceUrlWithSessionId(
			final boolean encodeServiceUrlWithSessionId) {
		this.encodeServiceUrlWithSessionId = encodeServiceUrlWithSessionId;
	}

	/**
	 * Sets whether to encode the service url with the session id or not.
	 * @return whether to encode the service url with the session id or not.
	 *
	 */
	protected boolean getEncodeServiceUrlWithSessionId() {
		return this.encodeServiceUrlWithSessionId;
	}
}


/*
 * Copyright 2002-2016 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.access.hierarchicalroles;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

/**
 *

 * This class defines a role hierarchy for use with the UserDetailsServiceWrapper.
 *
 *

 * Here is an example configuration of a role hierarchy (hint: read the ">" sign as
 * "includes"):
 *
 *

 *         <property name="hierarchy">
 *             <value>
 *                 ROLE_A > ROLE_B
 *                 ROLE_B > ROLE_AUTHENTICATED
 *                 ROLE_AUTHENTICATED > ROLE_UNAUTHENTICATED
 *             </value>
 *         </property>
 *

 *
 *

 * Explanation of the above:

 * In effect every user with ROLE_A also has ROLE_B, ROLE_AUTHENTICATED and
 * ROLE_UNAUTHENTICATED;

 * every user with ROLE_B also has ROLE_AUTHENTICATED and ROLE_UNAUTHENTICATED;

 * every user with ROLE_AUTHENTICATED also has ROLE_UNAUTHENTICATED.
 *
 *

 * Hierarchical Roles will dramatically shorten your access rules (and also make the
 * access rules much more elegant).
 *
 *

 * Consider this access rule for Spring Security's RoleVoter (background: every user that
 * is authenticated should be able to log out):

 * /logout.html=ROLE_A,ROLE_B,ROLE_AUTHENTICATED

 * With hierarchical roles this can now be shortened to:

 * /logout.html=ROLE_AUTHENTICATED

 * In addition to shorter rules this will also make your access rules more readable and
 * your intentions clearer.
 *
 * @author Michael Mayr
 */
public class RoleHierarchyImpl implements RoleHierarchy {

	private static final Log logger = LogFactory.getLog(RoleHierarchyImpl.class);

	private String roleHierarchyStringRepresentation = null;

	/**
	 * rolesReachableInOneStepMap is a Map that under the key of a specific role name
	 * contains a set of all roles reachable from this role in 1 step
	 */
	private Map<GrantedAuthority, Set<GrantedAuthority>> rolesReachableInOneStepMap = null;

	/**
	 * rolesReachableInOneOrMoreStepsMap is a Map that under the key of a specific role
	 * name contains a set of all roles reachable from this role in 1 or more steps
	 */
	private Map<GrantedAuthority, Set<GrantedAuthority>> rolesReachableInOneOrMoreStepsMap = null;

	/**
	 * Set the role hierarchy and pre-calculate for every role the set of all reachable
	 * roles, i.e. all roles lower in the hierarchy of every given role. Pre-calculation
	 * is done for performance reasons (reachable roles can then be calculated in O(1)
	 * time). During pre-calculation, cycles in role hierarchy are detected and will cause
	 * a <tt>CycleInRoleHierarchyException</tt> to be thrown.
	 *
	 * @param roleHierarchyStringRepresentation - String definition of the role hierarchy.
	 */
	public void setHierarchy(String roleHierarchyStringRepresentation) {
		this.roleHierarchyStringRepresentation = roleHierarchyStringRepresentation;

		logger.debug("setHierarchy() - The following role hierarchy was set: "
				+ roleHierarchyStringRepresentation);

		buildRolesReachableInOneStepMap();
		buildRolesReachableInOneOrMoreStepsMap();
	}

	public Collection<GrantedAuthority> getReachableGrantedAuthorities(
			Collection<? extends GrantedAuthority> authorities) {
		if (authorities == null || authorities.isEmpty()) {
			return AuthorityUtils.NO_AUTHORITIES;
		}

		Set<GrantedAuthority> reachableRoles = new HashSet<>();

		for (GrantedAuthority authority : authorities) {
			addReachableRoles(reachableRoles, authority);
			Set<GrantedAuthority> additionalReachableRoles = getRolesReachableInOneOrMoreSteps(
					authority);
			if (additionalReachableRoles != null) {
				reachableRoles.addAll(additionalReachableRoles);
			}
		}

		if (logger.isDebugEnabled()) {
			logger.debug("getReachableGrantedAuthorities() - From the roles "
					+ authorities + " one can reach " + reachableRoles
					+ " in zero or more steps.");
		}

		List<GrantedAuthority> reachableRoleList = new ArrayList<>(
				reachableRoles.size());
		reachableRoleList.addAll(reachableRoles);

		return reachableRoleList;
	}

	// SEC-863
	private void addReachableRoles(Set<GrantedAuthority> reachableRoles,
			GrantedAuthority authority) {

		for (GrantedAuthority testAuthority : reachableRoles) {
			String testKey = testAuthority.getAuthority();
			if ((testKey != null) && (testKey.equals(authority.getAuthority()))) {
				return;
			}
		}
		reachableRoles.add(authority);
	}

	// SEC-863
	private Set<GrantedAuthority> getRolesReachableInOneOrMoreSteps(
			GrantedAuthority authority) {

		if (authority.getAuthority() == null) {
			return null;
		}

		for (GrantedAuthority testAuthority : this.rolesReachableInOneOrMoreStepsMap
				.keySet()) {
			String testKey = testAuthority.getAuthority();
			if ((testKey != null) && (testKey.equals(authority.getAuthority()))) {
				return this.rolesReachableInOneOrMoreStepsMap.get(testAuthority);
			}
		}

		return null;
	}

	/**
	 * Parse input and build the map for the roles reachable in one step: the higher role
	 * will become a key that references a set of the reachable lower roles.
	 */
	private void buildRolesReachableInOneStepMap() {
		this.rolesReachableInOneStepMap = new HashMap<GrantedAuthority, Set<GrantedAuthority>>();
		try (BufferedReader bufferedReader = new BufferedReader(
				new StringReader(this.roleHierarchyStringRepresentation))) {
			for (String readLine; (readLine = bufferedReader.readLine()) != null;) {
				String[] roles = readLine.split(" > ");
				for (int i = 1; i < roles.length; i++) {
					GrantedAuthority higherRole = new SimpleGrantedAuthority(
							roles[i - 1].replaceAll("^\\s+|\\s+$", ""));
					GrantedAuthority lowerRole = new SimpleGrantedAuthority(roles[i].replaceAll("^\\s+|\\s+$", ""));
					Set<GrantedAuthority> rolesReachableInOneStepSet;
					if (!this.rolesReachableInOneStepMap.containsKey(higherRole)) {
						rolesReachableInOneStepSet = new HashSet<GrantedAuthority>();
						this.rolesReachableInOneStepMap.put(higherRole, rolesReachableInOneStepSet);
					} else {
						rolesReachableInOneStepSet = this.rolesReachableInOneStepMap.get(higherRole);
					}
					addReachableRoles(rolesReachableInOneStepSet, lowerRole);
					if (logger.isDebugEnabled()) {
						logger.debug("buildRolesReachableInOneStepMap() - From role " + higherRole
								+ " one can reach role " + lowerRole + " in one step.");
					}
				}
			}
		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
	}

	/**
	 * For every higher role from rolesReachableInOneStepMap store all roles that are
	 * reachable from it in the map of roles reachable in one or more steps. (Or throw a
	 * CycleInRoleHierarchyException if a cycle in the role hierarchy definition is
	 * detected)
	 */
	private void buildRolesReachableInOneOrMoreStepsMap() {
		this.rolesReachableInOneOrMoreStepsMap = new HashMap<>();
		// iterate over all higher roles from rolesReachableInOneStepMap

		for (GrantedAuthority role : this.rolesReachableInOneStepMap.keySet()) {
			Set<GrantedAuthority> rolesToVisitSet = new HashSet<>();

			if (this.rolesReachableInOneStepMap.containsKey(role)) {
				rolesToVisitSet.addAll(this.rolesReachableInOneStepMap.get(role));
			}

			Set<GrantedAuthority> visitedRolesSet = new HashSet<>();

			while (!rolesToVisitSet.isEmpty()) {
				// take a role from the rolesToVisit set
				GrantedAuthority aRole = rolesToVisitSet.iterator().next();
				rolesToVisitSet.remove(aRole);
				addReachableRoles(visitedRolesSet, aRole);
				if (this.rolesReachableInOneStepMap.containsKey(aRole)) {
					Set<GrantedAuthority> newReachableRoles = this.rolesReachableInOneStepMap
							.get(aRole);

					// definition of a cycle: you can reach the role you are starting from
					if (rolesToVisitSet.contains(role)
							|| visitedRolesSet.contains(role)) {
						throw new CycleInRoleHierarchyException();
					}
					else {
						// no cycle
						rolesToVisitSet.addAll(newReachableRoles);
					}
				}
			}
			this.rolesReachableInOneOrMoreStepsMap.put(role, visitedRolesSet);

			logger.debug("buildRolesReachableInOneOrMoreStepsMap() - From role " + role
					+ " one can reach " + visitedRolesSet + " in one or more steps.");
		}

	}

}


/*
 * Copyright 2011-2016 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.crypto.encrypt;

import static org.springframework.security.crypto.encrypt.CipherUtils.doFinal;
import static org.springframework.security.crypto.encrypt.CipherUtils.initCipher;
import static org.springframework.security.crypto.encrypt.CipherUtils.newCipher;
import static org.springframework.security.crypto.encrypt.CipherUtils.newSecretKey;
import static org.springframework.security.crypto.util.EncodingUtils.concatenate;
import static org.springframework.security.crypto.util.EncodingUtils.subArray;

import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.springframework.security.crypto.codec.Hex;
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
import org.springframework.security.crypto.keygen.KeyGenerators;

/**
 * Encryptor that uses 256-bit AES encryption.
 *
 * @author Keith Donald
 * @author Dave Syer
 */
public final class AesBytesEncryptor implements BytesEncryptor {

	private final SecretKey secretKey;

	private final Cipher encryptor;

	private final Cipher decryptor;

	private final BytesKeyGenerator ivGenerator;

	private CipherAlgorithm alg;

	private static final String AES_CBC_ALGORITHM = "AES/CBC/PKCS5Padding";

	private static final String AES_GCM_ALGORITHM = "AES/GCM/NoPadding";

	public enum CipherAlgorithm {

		CBC(AES_CBC_ALGORITHM, NULL_IV_GENERATOR), GCM(AES_GCM_ALGORITHM, KeyGenerators
				.secureRandom(16));

		private BytesKeyGenerator ivGenerator;
		private String name;

		private CipherAlgorithm(String name, BytesKeyGenerator ivGenerator) {
			this.name = name;
			this.ivGenerator = ivGenerator;
		}

		@Override
		public String toString() {
			return this.name;
		}

		public AlgorithmParameterSpec getParameterSpec(byte[] iv) {
			return this == CBC ? new IvParameterSpec(iv) : new GCMParameterSpec(128, iv);
		}

		public Cipher createCipher() {
			return newCipher(this.toString());
		}

		public BytesKeyGenerator defaultIvGenerator() {
			return this.ivGenerator;
		}
	}

	public AesBytesEncryptor(String password, CharSequence salt) {
		this(password, salt, null);
	}

	public AesBytesEncryptor(String password, CharSequence salt,
			BytesKeyGenerator ivGenerator) {
		this(password, salt, ivGenerator, CipherAlgorithm.CBC);
	}

	public AesBytesEncryptor(String password, CharSequence salt,
			BytesKeyGenerator ivGenerator, CipherAlgorithm alg) {
		PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(salt),
				1024, 256);
		SecretKey secretKey = newSecretKey("PBKDF2WithHmacSHA1", keySpec);
		this.secretKey = new SecretKeySpec(secretKey.getEncoded(), "AES");
		this.alg = alg;
		this.encryptor = alg.createCipher();
		this.decryptor = alg.createCipher();
		this.ivGenerator = ivGenerator != null ? ivGenerator : alg.defaultIvGenerator();
	}

	public byte[] encrypt(byte[] bytes) {
		synchronized (this.encryptor) {
			byte[] iv = this.ivGenerator.generateKey();
			initCipher(this.encryptor, Cipher.ENCRYPT_MODE, this.secretKey,
					this.alg.getParameterSpec(iv));
			byte[] encrypted = doFinal(this.encryptor, bytes);
			return this.ivGenerator != NULL_IV_GENERATOR ? concatenate(iv, encrypted)
					: encrypted;
		}
	}

	public byte[] decrypt(byte[] encryptedBytes) {
		synchronized (this.decryptor) {
			byte[] iv = iv(encryptedBytes);
			initCipher(this.decryptor, Cipher.DECRYPT_MODE, this.secretKey,
					this.alg.getParameterSpec(iv));
			return doFinal(
					this.decryptor,
					this.ivGenerator != NULL_IV_GENERATOR ? encrypted(encryptedBytes,
							iv.length) : encryptedBytes);
		}
	}

	// internal helpers

	private byte[] iv(byte[] encrypted) {
		return this.ivGenerator != NULL_IV_GENERATOR ? subArray(encrypted, 0,
				this.ivGenerator.getKeyLength()) : NULL_IV_GENERATOR.generateKey();
	}

	private byte[] encrypted(byte[] encryptedBytes, int ivLength) {
		return subArray(encryptedBytes, ivLength, encryptedBytes.length);
	}

	private static final BytesKeyGenerator NULL_IV_GENERATOR = new BytesKeyGenerator() {

		private final byte[] VALUE = new byte[16];

		public int getKeyLength() {
			return this.VALUE.length;
		}

		public byte[] generateKey() {
			return this.VALUE;
		}

	};
}