Skip to content

Oauth2login xmlconfig implementation #7821

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
Expand Down Expand Up @@ -72,4 +72,7 @@ public abstract class Elements {

public static final String WEBSOCKET_MESSAGE_BROKER = "websocket-message-broker";
public static final String INTERCEPT_MESSAGE = "intercept-message";

public static final String OAUTH2_LOGIN = "oauth2-login";
public static final String CLIENT_REGISTRATIONS = "client-registrations";
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2013 the original author or authors.
* Copyright 2009-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.
Expand Down Expand Up @@ -41,6 +41,7 @@
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
import org.springframework.security.config.method.MethodSecurityMetadataSourceBeanDefinitionParser;
import org.springframework.security.config.oauth2.client.ClientRegistrationsBeanDefinitionParser;
import org.springframework.security.config.websocket.WebSocketMessageBrokerSecurityBeanDefinitionParser;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.util.ClassUtils;
Expand Down Expand Up @@ -86,7 +87,7 @@ public BeanDefinition parse(Element element, ParserContext pc) {
if (!namespaceMatchesVersion(element)) {
pc.getReaderContext()
.fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or spring-security-3.1.xsd schema or spring-security-3.2.xsd schema or spring-security-4.0.xsd schema "
+ "with Spring Security 5.2. Please update your schema declarations to the 5.2 schema.",
+ "with Spring Security 5.3. Please update your schema declarations to the 5.3 schema.",
element);
}
String name = pc.getDelegate().getLocalName(element);
Expand Down Expand Up @@ -192,6 +193,7 @@ private void loadParsers() {
new FilterInvocationSecurityMetadataSourceParser());
parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
parsers.put(Elements.CLIENT_REGISTRATIONS, new ClientRegistrationsBeanDefinitionParser());
}

if (ClassUtils.isPresent(MESSAGE_CLASSNAME, getClass().getClassLoader())) {
Expand Down Expand Up @@ -221,7 +223,7 @@ private boolean namespaceMatchesVersion(Element element) {
private boolean matchesVersionInternal(Element element) {
String schemaLocation = element.getAttributeNS(
"http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
return schemaLocation.matches("(?m).*spring-security-5\\.2.*.xsd.*")
return schemaLocation.matches("(?m).*spring-security-5\\.3.*.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* 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.
Expand Down Expand Up @@ -138,6 +138,15 @@ final class AuthenticationConfigBuilder {

private String openIDLoginPage;

private String oauth2LoginFilterId;
private String oauth2AuthorizationRequestRedirectFilterId;
private BeanDefinition oauth2AuthorizationRequestRedirectFilter;
private BeanDefinition oauth2LoginEntryPoint;
private BeanReference oauth2LoginAuthenticationProviderRef;
private BeanReference oauth2LoginOidcAuthenticationProviderRef;

private BeanDefinition oauth2LoginLinks;

AuthenticationConfigBuilder(Element element, boolean forceAutoConfig,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to add similar logic as OAuth2LoginConfigurer.initDefaultLoginFilter() in AuthenticationConfigBuilder.createLoginPageFilterIfNeeded(). Please add a test as well to ensure the "login links" are rendered in the default login page.

ParserContext pc, SessionCreationPolicy sessionPolicy,
BeanReference requestCache, BeanReference authenticationManager,
Expand All @@ -158,6 +167,7 @@ final class AuthenticationConfigBuilder {
createRememberMeFilter(authenticationManager);
createBasicFilter(authenticationManager);
createFormLoginFilter(sessionStrategy, authenticationManager);
createOAuth2LoginFilter(sessionStrategy, authenticationManager);
createOpenIDLoginFilter(sessionStrategy, authenticationManager);
createX509Filter(authenticationManager);
createJeeFilter(authenticationManager);
Expand Down Expand Up @@ -235,6 +245,47 @@ void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authMana
}
}

void createOAuth2LoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element oauth2LoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OAUTH2_LOGIN);
if (oauth2LoginElt != null) {
OAuth2LoginBeanDefinitionParser parser = new OAuth2LoginBeanDefinitionParser(requestCache, portMapper,
portResolver, sessionStrategy, allowSessionCreation);
BeanDefinition oauth2LoginFilterBean = parser.parse(oauth2LoginElt, this.pc);
oauth2LoginFilterBean.getPropertyValues().addPropertyValue("authenticationManager", authManager);

// retrieve the other bean result
BeanDefinition oauth2LoginAuthProvider = parser.getOAuth2LoginAuthenticationProvider();
oauth2AuthorizationRequestRedirectFilter = parser.getOAuth2AuthorizationRequestRedirectFilter();
oauth2LoginEntryPoint = parser.getOAuth2LoginAuthenticationEntryPoint();

// generate bean name to be registered
String oauth2LoginAuthenticationProviderId = pc.getReaderContext()
.generateBeanName(oauth2LoginAuthProvider);
oauth2LoginFilterId = pc.getReaderContext().generateBeanName(oauth2LoginFilterBean);
oauth2AuthorizationRequestRedirectFilterId = pc.getReaderContext()
.generateBeanName(oauth2AuthorizationRequestRedirectFilter);
oauth2LoginLinks = parser.getOAuth2LoginLinks();

// register the component
pc.registerBeanComponent(new BeanComponentDefinition(oauth2AuthorizationRequestRedirectFilter,
oauth2AuthorizationRequestRedirectFilterId));
pc.registerBeanComponent(new BeanComponentDefinition(oauth2LoginFilterBean, oauth2LoginFilterId));
pc.registerBeanComponent(
new BeanComponentDefinition(oauth2LoginAuthProvider, oauth2LoginAuthenticationProviderId));

oauth2LoginAuthenticationProviderRef = new RuntimeBeanReference(oauth2LoginAuthenticationProviderId);

// oidc provider
BeanDefinition oauth2LoginOidcAuthProvider = parser.getOAuth2LoginOidcAuthenticationProvider();
String oauth2LoginOidcAuthenticationProviderId = pc.getReaderContext()
.generateBeanName(oauth2LoginOidcAuthProvider);
pc.registerBeanComponent(
new BeanComponentDefinition(oauth2LoginOidcAuthProvider, oauth2LoginOidcAuthenticationProviderId));
oauth2LoginOidcAuthenticationProviderRef = new RuntimeBeanReference(
oauth2LoginOidcAuthenticationProviderId);
}
}

void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt,
Elements.OPENID_LOGIN);
Expand Down Expand Up @@ -535,7 +586,7 @@ private void createJeeProvider() {
}

void createLoginPageFilterIfNeeded() {
boolean needLoginPage = formFilterId != null || openIDFilterId != null;
boolean needLoginPage = formFilterId != null || openIDFilterId != null || oauth2LoginFilterId != null;

// If no login page has been defined, add in the default page generator.
if (needLoginPage && formLoginPage == null && openIDLoginPage == null) {
Expand All @@ -561,6 +612,12 @@ void createLoginPageFilterIfNeeded() {
openidLoginProcessingUrl);
}

if (oauth2LoginFilterId != null) {
loginPageFilter.addConstructorArgReference(oauth2LoginFilterId);
loginPageFilter.addPropertyValue("Oauth2LoginEnabled", true);
loginPageFilter.addPropertyValue("Oauth2AuthenticationUrlToClientName", oauth2LoginLinks);
}

loginPageGenerationFilter = loginPageFilter.getBeanDefinition();
this.logoutPageGenerationFilter = logoutPageFilter.getBeanDefinition();
}
Expand Down Expand Up @@ -722,7 +779,7 @@ private BeanMetadataElement selectEntryPoint() {
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt,
Elements.OPENID_LOGIN);
// Basic takes precedence if explicit element is used and no others are configured
if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) {
if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null && oauth2LoginEntryPoint == null) {
return basicEntryPoint;
}

Expand All @@ -737,7 +794,15 @@ private BeanMetadataElement selectEntryPoint() {
}

if (formFilterId != null && openIDLoginPage == null) {
return formEntryPoint;
// gh-6802
// If form login was enabled through element and Oauth2 login was enabled from element then use form login
if (formLoginElt != null && oauth2LoginEntryPoint != null) {
return formEntryPoint;
}
// If form login was enabled through auto-config, and Oauth2 login was not enabled then use form login
if (oauth2LoginEntryPoint == null) {
return formEntryPoint;
}
}

// Otherwise use OpenID if enabled
Expand All @@ -750,6 +815,11 @@ private BeanMetadataElement selectEntryPoint() {
return preAuthEntryPoint;
}

// OAuth2 entry point will not be null if only 1 client registration
if (oauth2LoginEntryPoint != null) {
return oauth2LoginEntryPoint;
}

pc.getReaderContext()
.error("No AuthenticationEntryPoint could be established. Please "
+ "make sure you have a login mechanism configured through the namespace (such as form-login) or "
Expand Down Expand Up @@ -798,6 +868,11 @@ List<OrderDecorator> getFilters() {
FORM_LOGIN_FILTER));
}

if (oauth2LoginFilterId != null) {
filters.add(new OrderDecorator(new RuntimeBeanReference(oauth2LoginFilterId), OAUTH2_LOGIN_FILTER));
filters.add(new OrderDecorator(oauth2AuthorizationRequestRedirectFilter, OAUTH2_REDIRECT_FILTER));
}

if (openIDFilterId != null) {
filters.add(new OrderDecorator(new RuntimeBeanReference(openIDFilterId),
OPENID_FILTER));
Expand Down Expand Up @@ -840,6 +915,14 @@ List<BeanReference> getProviders() {
providers.add(jeeProviderRef);
}

if (oauth2LoginAuthenticationProviderRef != null) {
providers.add(oauth2LoginAuthenticationProviderRef);
}

if (oauth2LoginOidcAuthenticationProviderRef != null) {
providers.add(oauth2LoginOidcAuthenticationProviderRef);
}

return providers;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* 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.
Expand Down Expand Up @@ -33,6 +33,7 @@
import org.springframework.core.OrderComparator;
import org.springframework.core.Ordered;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.Elements;
Expand Down Expand Up @@ -294,6 +295,8 @@ private BeanReference createAuthenticationManager(Element element, ParserContext
clearCredentials);
}

// gh-6009
authManager.addPropertyValue("authenticationEventPublisher", new RootBeanDefinition(DefaultAuthenticationEventPublisher.class));
authManager.getRawBeanDefinition().setSource(pc.extractSource(element));
BeanDefinition authMgrBean = authManager.getBeanDefinition();
String id = pc.getReaderContext().generateBeanName(authMgrBean);
Expand Down
Loading