spring security OAuth2ResourceServerBeanDefinitionParser 源码

  • 2022-08-13
  • 浏览 (450)

spring security OAuth2ResourceServerBeanDefinitionParser 代码

文件路径:/config/src/main/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParser.java

/*
 * Copyright 2002-2020 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.http;

import java.util.List;
import java.util.Map;

import jakarta.servlet.http.HttpServletRequest;
import org.w3c.dom.Element;

import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationManagerResolver;
import org.springframework.security.config.Elements;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;

/**
 * A {@link BeanDefinitionParser} for <http>'s <oauth2-resource-server>
 * element.
 *
 * @author Josh Cummings
 * @since 5.3
 */
final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionParser {

	static final String AUTHENTICATION_MANAGER_RESOLVER_REF = "authentication-manager-resolver-ref";

	static final String BEARER_TOKEN_RESOLVER_REF = "bearer-token-resolver-ref";

	static final String ENTRY_POINT_REF = "entry-point-ref";

	static final String BEARER_TOKEN_RESOLVER = "bearerTokenResolver";

	static final String AUTHENTICATION_ENTRY_POINT = "authenticationEntryPoint";

	private final BeanReference authenticationManager;

	private final List<BeanReference> authenticationProviders;

	private final Map<BeanDefinition, BeanMetadataElement> entryPoints;

	private final Map<BeanDefinition, BeanMetadataElement> deniedHandlers;

	private final List<BeanDefinition> ignoreCsrfRequestMatchers;

	private final BeanDefinition authenticationEntryPoint = new RootBeanDefinition(
			BearerTokenAuthenticationEntryPoint.class);

	private final BeanDefinition accessDeniedHandler = new RootBeanDefinition(BearerTokenAccessDeniedHandler.class);

	OAuth2ResourceServerBeanDefinitionParser(BeanReference authenticationManager,
			List<BeanReference> authenticationProviders, Map<BeanDefinition, BeanMetadataElement> entryPoints,
			Map<BeanDefinition, BeanMetadataElement> deniedHandlers, List<BeanDefinition> ignoreCsrfRequestMatchers) {
		this.authenticationManager = authenticationManager;
		this.authenticationProviders = authenticationProviders;
		this.entryPoints = entryPoints;
		this.deniedHandlers = deniedHandlers;
		this.ignoreCsrfRequestMatchers = ignoreCsrfRequestMatchers;
	}

	/**
	 * Parse a &lt;oauth2-resource-server&gt; element and return the corresponding
	 * {@link BearerTokenAuthenticationFilter}
	 * @param oauth2ResourceServer the &lt;oauth2-resource-server&gt; element.
	 * @param pc the {@link ParserContext}
	 * @return a {@link BeanDefinition} representing a
	 * {@link BearerTokenAuthenticationFilter} definition
	 */
	@Override
	public BeanDefinition parse(Element oauth2ResourceServer, ParserContext pc) {
		Element jwt = DomUtils.getChildElementByTagName(oauth2ResourceServer, Elements.JWT);
		Element opaqueToken = DomUtils.getChildElementByTagName(oauth2ResourceServer, Elements.OPAQUE_TOKEN);
		validateConfiguration(oauth2ResourceServer, jwt, opaqueToken, pc);
		if (jwt != null) {
			BeanDefinition jwtAuthenticationProvider = new JwtBeanDefinitionParser().parse(jwt, pc);
			this.authenticationProviders.add(new RuntimeBeanReference(
					pc.getReaderContext().registerWithGeneratedName(jwtAuthenticationProvider)));
		}
		if (opaqueToken != null) {
			BeanDefinition opaqueTokenAuthenticationProvider = new OpaqueTokenBeanDefinitionParser().parse(opaqueToken,
					pc);
			this.authenticationProviders.add(new RuntimeBeanReference(
					pc.getReaderContext().registerWithGeneratedName(opaqueTokenAuthenticationProvider)));
		}
		BeanMetadataElement bearerTokenResolver = getBearerTokenResolver(oauth2ResourceServer);
		BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
				.rootBeanDefinition(BearerTokenRequestMatcher.class);
		requestMatcherBuilder.addConstructorArgValue(bearerTokenResolver);
		BeanDefinition requestMatcher = requestMatcherBuilder.getBeanDefinition();
		BeanMetadataElement authenticationEntryPoint = getEntryPoint(oauth2ResourceServer);
		this.entryPoints.put(requestMatcher, authenticationEntryPoint);
		this.deniedHandlers.put(requestMatcher, this.accessDeniedHandler);
		this.ignoreCsrfRequestMatchers.add(requestMatcher);
		BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder
				.rootBeanDefinition(BearerTokenAuthenticationFilter.class);
		BeanMetadataElement authenticationManagerResolver = getAuthenticationManagerResolver(oauth2ResourceServer);
		filterBuilder.addConstructorArgValue(authenticationManagerResolver);
		filterBuilder.addPropertyValue(BEARER_TOKEN_RESOLVER, bearerTokenResolver);
		filterBuilder.addPropertyValue(AUTHENTICATION_ENTRY_POINT, authenticationEntryPoint);
		return filterBuilder.getBeanDefinition();
	}

	void validateConfiguration(Element oauth2ResourceServer, Element jwt, Element opaqueToken, ParserContext pc) {
		if (!oauth2ResourceServer.hasAttribute(AUTHENTICATION_MANAGER_RESOLVER_REF)) {
			if (jwt == null && opaqueToken == null) {
				pc.getReaderContext().error("Didn't find authentication-manager-resolver-ref, "
						+ "<jwt>, or <opaque-token>. " + "Please select one.", oauth2ResourceServer);
			}
			return;
		}
		if (jwt != null) {
			pc.getReaderContext().error(
					"Found <jwt> as well as authentication-manager-resolver-ref. Please select just one.",
					oauth2ResourceServer);
		}
		if (opaqueToken != null) {
			pc.getReaderContext().error(
					"Found <opaque-token> as well as authentication-manager-resolver-ref. Please select just one.",
					oauth2ResourceServer);
		}
	}

	BeanMetadataElement getAuthenticationManagerResolver(Element element) {
		String authenticationManagerResolverRef = element.getAttribute(AUTHENTICATION_MANAGER_RESOLVER_REF);
		if (!StringUtils.isEmpty(authenticationManagerResolverRef)) {
			return new RuntimeBeanReference(authenticationManagerResolverRef);
		}
		BeanDefinitionBuilder authenticationManagerResolver = BeanDefinitionBuilder
				.rootBeanDefinition(StaticAuthenticationManagerResolver.class);
		authenticationManagerResolver.addConstructorArgValue(this.authenticationManager);
		return authenticationManagerResolver.getBeanDefinition();
	}

	BeanMetadataElement getBearerTokenResolver(Element element) {
		String bearerTokenResolverRef = element.getAttribute(BEARER_TOKEN_RESOLVER_REF);
		if (StringUtils.isEmpty(bearerTokenResolverRef)) {
			return new RootBeanDefinition(DefaultBearerTokenResolver.class);
		}
		return new RuntimeBeanReference(bearerTokenResolverRef);
	}

	BeanMetadataElement getEntryPoint(Element element) {
		String entryPointRef = element.getAttribute(ENTRY_POINT_REF);
		if (StringUtils.isEmpty(entryPointRef)) {
			return this.authenticationEntryPoint;
		}
		return new RuntimeBeanReference(entryPointRef);
	}

	static final class JwtBeanDefinitionParser implements BeanDefinitionParser {

		static final String DECODER_REF = "decoder-ref";

		static final String JWK_SET_URI = "jwk-set-uri";

		static final String JWT_AUTHENTICATION_CONVERTER_REF = "jwt-authentication-converter-ref";

		static final String JWT_AUTHENTICATION_CONVERTER = "jwtAuthenticationConverter";

		JwtBeanDefinitionParser() {
		}

		@Override
		public BeanDefinition parse(Element element, ParserContext pc) {
			validateConfiguration(element, pc);
			BeanDefinitionBuilder jwtProviderBuilder = BeanDefinitionBuilder
					.rootBeanDefinition(JwtAuthenticationProvider.class);
			jwtProviderBuilder.addConstructorArgValue(getDecoder(element));
			jwtProviderBuilder.addPropertyValue(JWT_AUTHENTICATION_CONVERTER, getJwtAuthenticationConverter(element));
			return jwtProviderBuilder.getBeanDefinition();
		}

		void validateConfiguration(Element element, ParserContext pc) {
			boolean usesDecoder = element.hasAttribute(DECODER_REF);
			boolean usesJwkSetUri = element.hasAttribute(JWK_SET_URI);
			if (usesDecoder == usesJwkSetUri) {
				pc.getReaderContext().error("Please specify either decoder-ref or jwk-set-uri.", element);
			}
		}

		Object getDecoder(Element element) {
			String decoderRef = element.getAttribute(DECODER_REF);
			if (!StringUtils.isEmpty(decoderRef)) {
				return new RuntimeBeanReference(decoderRef);
			}
			BeanDefinitionBuilder builder = BeanDefinitionBuilder
					.rootBeanDefinition(NimbusJwtDecoderJwkSetUriFactoryBean.class);
			builder.addConstructorArgValue(element.getAttribute(JWK_SET_URI));
			return builder.getBeanDefinition();
		}

		Object getJwtAuthenticationConverter(Element element) {
			String jwtDecoderRef = element.getAttribute(JWT_AUTHENTICATION_CONVERTER_REF);
			return (!StringUtils.isEmpty(jwtDecoderRef)) ? new RuntimeBeanReference(jwtDecoderRef)
					: new JwtAuthenticationConverter();
		}

	}

	static final class OpaqueTokenBeanDefinitionParser implements BeanDefinitionParser {

		static final String INTROSPECTOR_REF = "introspector-ref";

		static final String INTROSPECTION_URI = "introspection-uri";

		static final String CLIENT_ID = "client-id";

		static final String CLIENT_SECRET = "client-secret";

		OpaqueTokenBeanDefinitionParser() {
		}

		@Override
		public BeanDefinition parse(Element element, ParserContext pc) {
			validateConfiguration(element, pc);
			BeanMetadataElement introspector = getIntrospector(element);
			BeanDefinitionBuilder opaqueTokenProviderBuilder = BeanDefinitionBuilder
					.rootBeanDefinition(OpaqueTokenAuthenticationProvider.class);
			opaqueTokenProviderBuilder.addConstructorArgValue(introspector);
			return opaqueTokenProviderBuilder.getBeanDefinition();
		}

		void validateConfiguration(Element element, ParserContext pc) {
			boolean usesIntrospector = element.hasAttribute(INTROSPECTOR_REF);
			boolean usesEndpoint = element.hasAttribute(INTROSPECTION_URI) || element.hasAttribute(CLIENT_ID)
					|| element.hasAttribute(CLIENT_SECRET);
			if (usesIntrospector == usesEndpoint) {
				pc.getReaderContext().error("Please specify either introspector-ref or all of "
						+ "introspection-uri, client-id, and client-secret.", element);
				return;
			}
			if (usesEndpoint) {
				if (!(element.hasAttribute(INTROSPECTION_URI) && element.hasAttribute(CLIENT_ID)
						&& element.hasAttribute(CLIENT_SECRET))) {
					pc.getReaderContext()
							.error("Please specify introspection-uri, client-id, and client-secret together", element);
				}
			}
		}

		BeanMetadataElement getIntrospector(Element element) {
			String introspectorRef = element.getAttribute(INTROSPECTOR_REF);
			if (!StringUtils.isEmpty(introspectorRef)) {
				return new RuntimeBeanReference(introspectorRef);
			}
			String introspectionUri = element.getAttribute(INTROSPECTION_URI);
			String clientId = element.getAttribute(CLIENT_ID);
			String clientSecret = element.getAttribute(CLIENT_SECRET);
			BeanDefinitionBuilder introspectorBuilder = BeanDefinitionBuilder
					.rootBeanDefinition(NimbusOpaqueTokenIntrospector.class);
			introspectorBuilder.addConstructorArgValue(introspectionUri);
			introspectorBuilder.addConstructorArgValue(clientId);
			introspectorBuilder.addConstructorArgValue(clientSecret);
			return introspectorBuilder.getBeanDefinition();
		}

	}

	static final class StaticAuthenticationManagerResolver
			implements AuthenticationManagerResolver<HttpServletRequest> {

		private final AuthenticationManager authenticationManager;

		StaticAuthenticationManagerResolver(AuthenticationManager authenticationManager) {
			this.authenticationManager = authenticationManager;
		}

		@Override
		public AuthenticationManager resolve(HttpServletRequest context) {
			return this.authenticationManager;
		}

	}

	static final class NimbusJwtDecoderJwkSetUriFactoryBean implements FactoryBean<JwtDecoder> {

		private final String jwkSetUri;

		NimbusJwtDecoderJwkSetUriFactoryBean(String jwkSetUri) {
			this.jwkSetUri = jwkSetUri;
		}

		@Override
		public JwtDecoder getObject() {
			return NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri).build();
		}

		@Override
		public Class<?> getObjectType() {
			return JwtDecoder.class;
		}

	}

	static final class BearerTokenRequestMatcher implements RequestMatcher {

		private final BearerTokenResolver bearerTokenResolver;

		BearerTokenRequestMatcher(BearerTokenResolver bearerTokenResolver) {
			Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
			this.bearerTokenResolver = bearerTokenResolver;
		}

		@Override
		public boolean matches(HttpServletRequest request) {
			try {
				return this.bearerTokenResolver.resolve(request) != null;
			}
			catch (OAuth2AuthenticationException ex) {
				return false;
			}
		}

	}

}

相关信息

spring security 源码目录

相关文章

spring security AuthenticationConfigBuilder 源码

spring security AuthorizationFilterParser 源码

spring security ChannelAttributeFactory 源码

spring security CorsBeanDefinitionParser 源码

spring security CsrfBeanDefinitionParser 源码

spring security DefaultFilterChainValidator 源码

spring security FilterChainBeanDefinitionParser 源码

spring security FilterChainMapBeanDefinitionDecorator 源码

spring security FilterInvocationSecurityMetadataSourceParser 源码

spring security FormLoginBeanDefinitionParser 源码

0  赞