Remove spring-security-openid

Closes gh-10773
This commit is contained in:
Rob Winch 2022-01-21 16:55:19 -06:00
parent e7ce694b23
commit f94090a59b
62 changed files with 16 additions and 4691 deletions

View File

@ -23,7 +23,6 @@ dependencies {
optional project(':spring-security-oauth2-client')
optional project(':spring-security-oauth2-jose')
optional project(':spring-security-oauth2-resource-server')
optional project(':spring-security-openid')
optional project(':spring-security-rsocket')
optional project(':spring-security-web')
optional 'io.projectreactor:reactor-core'
@ -80,10 +79,6 @@ dependencies {
testImplementation 'org.hsqldb:hsqldb'
testImplementation 'org.mockito:mockito-core'
testImplementation "org.mockito:mockito-inline"
testImplementation ('org.openid4java:openid4java-nodeps') {
exclude group: 'com.google.code.guice', module: 'guice'
exclude group: 'commons-logging', module: 'commons-logging'
}
testImplementation('org.seleniumhq.selenium:htmlunit-driver') {
exclude group: 'commons-logging', module: 'commons-logging'
}

View File

@ -72,12 +72,6 @@ public abstract class Elements {
public static final String FORM_LOGIN = "form-login";
public static final String OPENID_LOGIN = "openid-login";
public static final String OPENID_ATTRIBUTE_EXCHANGE = "attribute-exchange";
public static final String OPENID_ATTRIBUTE = "openid-attribute";
public static final String BASIC_AUTH = "http-basic";
public static final String REMEMBER_ME = "remember-me";

View File

@ -23,7 +23,6 @@ import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.openid.OpenIDAuthenticationFilter;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
@ -132,7 +131,6 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
* <li><a href="
* {@docRoot}/org/springframework/security/cas/web/CasAuthenticationFilter.html">CasAuthenticationFilter</a></li>
* <li>{@link UsernamePasswordAuthenticationFilter}</li>
* <li>{@link OpenIDAuthenticationFilter}</li>
* <li>{@link org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter}</li>
* <li>{@link org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter}</li>
* <li>{@link ConcurrentSessionFilter}</li>

View File

@ -91,7 +91,6 @@ final class FilterOrderRegistration {
order.next());
put(UsernamePasswordAuthenticationFilter.class, order.next());
order.next(); // gh-8105
this.filterToOrder.put("org.springframework.security.openid.OpenIDAuthenticationFilter", order.next());
put(DefaultLoginPageGeneratingFilter.class, order.next());
put(DefaultLogoutPageGeneratingFilter.class, order.next());
put(ConcurrentSessionFilter.class, order.next());

View File

@ -70,7 +70,6 @@ import org.springframework.security.config.annotation.web.configurers.X509Config
import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2ClientConfigurer;
import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.config.annotation.web.configurers.openid.OpenIDLoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.saml2.Saml2LoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.saml2.Saml2LogoutConfigurer;
import org.springframework.security.core.Authentication;
@ -171,219 +170,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
return getSharedObject(ApplicationContext.class);
}
/**
* Allows configuring OpenID based authentication.
*
* <h2>Example Configurations</h2>
*
* A basic example accepting the defaults and not using attribute exchange:
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) {
* http.authorizeRequests().antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;).and().openidLogin()
* .permitAll();
* }
*
* &#064;Override
* protected void configure(AuthenticationManagerBuilder auth) throws Exception {
* auth.inMemoryAuthentication()
* // the username must match the OpenID of the user you are
* // logging in with
* .withUser(
* &quot;https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU&quot;)
* .password(&quot;password&quot;).roles(&quot;USER&quot;);
* }
* }
* </pre>
*
* A more advanced example demonstrating using attribute exchange and providing a
* custom AuthenticationUserDetailsService that will make any user that authenticates
* a valid user.
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) {
* http.authorizeRequests()
* .antMatchers(&quot;/**&quot;)
* .hasRole(&quot;USER&quot;)
* .and()
* .openidLogin()
* .loginPage(&quot;/login&quot;)
* .permitAll()
* .authenticationUserDetailsService(
* new AutoProvisioningUserDetailsService())
* .attributeExchange(&quot;https://www.google.com/.*&quot;).attribute(&quot;email&quot;)
* .type(&quot;https://axschema.org/contact/email&quot;).required(true).and()
* .attribute(&quot;firstname&quot;).type(&quot;https://axschema.org/namePerson/first&quot;)
* .required(true).and().attribute(&quot;lastname&quot;)
* .type(&quot;https://axschema.org/namePerson/last&quot;).required(true).and().and()
* .attributeExchange(&quot;.*yahoo.com.*&quot;).attribute(&quot;email&quot;)
* .type(&quot;https://schema.openid.net/contact/email&quot;).required(true).and()
* .attribute(&quot;fullname&quot;).type(&quot;https://axschema.org/namePerson&quot;)
* .required(true).and().and().attributeExchange(&quot;.*myopenid.com.*&quot;)
* .attribute(&quot;email&quot;).type(&quot;https://schema.openid.net/contact/email&quot;)
* .required(true).and().attribute(&quot;fullname&quot;)
* .type(&quot;https://schema.openid.net/namePerson&quot;).required(true);
* }
* }
*
* public class AutoProvisioningUserDetailsService implements
* AuthenticationUserDetailsService&lt;OpenIDAuthenticationToken&gt; {
* public UserDetails loadUserDetails(OpenIDAuthenticationToken token)
* throws UsernameNotFoundException {
* return new User(token.getName(), &quot;NOTUSED&quot;,
* AuthorityUtils.createAuthorityList(&quot;ROLE_USER&quot;));
* }
* }
* </pre>
* @return the {@link OpenIDLoginConfigurer} for further customizations.
* @throws Exception
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
* @see OpenIDLoginConfigurer
*/
@Deprecated
public OpenIDLoginConfigurer<HttpSecurity> openidLogin() throws Exception {
return getOrApply(new OpenIDLoginConfigurer<>());
}
/**
* Allows configuring OpenID based authentication.
*
* <h2>Example Configurations</h2>
*
* A basic example accepting the defaults and not using attribute exchange:
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) {
* http
* .authorizeRequests((authorizeRequests) -&gt;
* authorizeRequests
* .antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;)
* )
* .openidLogin((openidLogin) -&gt;
* openidLogin
* .permitAll()
* );
* }
*
* &#064;Override
* protected void configure(AuthenticationManagerBuilder auth) throws Exception {
* auth.inMemoryAuthentication()
* // the username must match the OpenID of the user you are
* // logging in with
* .withUser(
* &quot;https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU&quot;)
* .password(&quot;password&quot;).roles(&quot;USER&quot;);
* }
* }
* </pre>
*
* A more advanced example demonstrating using attribute exchange and providing a
* custom AuthenticationUserDetailsService that will make any user that authenticates
* a valid user.
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http.authorizeRequests((authorizeRequests) -&gt;
* authorizeRequests
* .antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;)
* )
* .openidLogin((openidLogin) -&gt;
* openidLogin
* .loginPage(&quot;/login&quot;)
* .permitAll()
* .authenticationUserDetailsService(
* new AutoProvisioningUserDetailsService())
* .attributeExchange((googleExchange) -&gt;
* googleExchange
* .identifierPattern(&quot;https://www.google.com/.*&quot;)
* .attribute((emailAttribute) -&gt;
* emailAttribute
* .name(&quot;email&quot;)
* .type(&quot;https://axschema.org/contact/email&quot;)
* .required(true)
* )
* .attribute((firstnameAttribute) -&gt;
* firstnameAttribute
* .name(&quot;firstname&quot;)
* .type(&quot;https://axschema.org/namePerson/first&quot;)
* .required(true)
* )
* .attribute((lastnameAttribute) -&gt;
* lastnameAttribute
* .name(&quot;lastname&quot;)
* .type(&quot;https://axschema.org/namePerson/last&quot;)
* .required(true)
* )
* )
* .attributeExchange((yahooExchange) -&gt;
* yahooExchange
* .identifierPattern(&quot;.*yahoo.com.*&quot;)
* .attribute((emailAttribute) -&gt;
* emailAttribute
* .name(&quot;email&quot;)
* .type(&quot;https://schema.openid.net/contact/email&quot;)
* .required(true)
* )
* .attribute((fullnameAttribute) -&gt;
* fullnameAttribute
* .name(&quot;fullname&quot;)
* .type(&quot;https://axschema.org/namePerson&quot;)
* .required(true)
* )
* )
* );
* }
* }
*
* public class AutoProvisioningUserDetailsService implements
* AuthenticationUserDetailsService&lt;OpenIDAuthenticationToken&gt; {
* public UserDetails loadUserDetails(OpenIDAuthenticationToken token)
* throws UsernameNotFoundException {
* return new User(token.getName(), &quot;NOTUSED&quot;,
* AuthorityUtils.createAuthorityList(&quot;ROLE_USER&quot;));
* }
* }
* </pre>
* @param openidLoginCustomizer the {@link Customizer} to provide more options for the
* {@link OpenIDLoginConfigurer}
* @return the {@link HttpSecurity} for further customizations
* @throws Exception
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
* @see OpenIDLoginConfigurer
*/
@Deprecated
public HttpSecurity openidLogin(Customizer<OpenIDLoginConfigurer<HttpSecurity>> openidLoginCustomizer)
throws Exception {
openidLoginCustomizer.customize(getOrApply(new OpenIDLoginConfigurer<>()));
return HttpSecurity.this;
}
/**
* Adds the Security headers to the response. This is activated by default when using
* {@link WebSecurityConfigurerAdapter}'s default constructor. Accepting the default

View File

@ -26,7 +26,6 @@ import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.openid.OpenIDLoginConfigurer;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
@ -57,7 +56,6 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
* @author Rob Winch
* @since 3.2
* @see FormLoginConfigurer
* @see OpenIDLoginConfigurer
*/
public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>, T extends AbstractAuthenticationFilterConfigurer<B, T, F>, F extends AbstractAuthenticationProcessingFilter>
extends AbstractHttpConfigurer<T, B> {

View File

@ -1,569 +0,0 @@
/*
* Copyright 2002-2019 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.openid;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import org.openid4java.consumer.ConsumerException;
import org.openid4java.consumer.ConsumerManager;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
import org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.openid.AxFetchListFactory;
import org.springframework.security.openid.OpenID4JavaConsumer;
import org.springframework.security.openid.OpenIDAttribute;
import org.springframework.security.openid.OpenIDAuthenticationFilter;
import org.springframework.security.openid.OpenIDAuthenticationProvider;
import org.springframework.security.openid.OpenIDAuthenticationToken;
import org.springframework.security.openid.OpenIDConsumer;
import org.springframework.security.openid.RegexBasedAxFetchListFactory;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* Adds support for OpenID based authentication.
*
* <h2>Example Configuration</h2>
*
* <pre>
*
* &#064;Configuration
* &#064;EnableWebSecurity
* public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) {
* http
* .authorizeRequests()
* .antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;)
* .and()
* .openidLogin()
* .permitAll();
* }
*
* &#064;Override
* protected void configure(AuthenticationManagerBuilder auth)(
* AuthenticationManagerBuilder auth) throws Exception {
* auth
* .inMemoryAuthentication()
* .withUser(&quot;https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;);
* }
* }
* </pre>
*
* <h2>Security Filters</h2>
*
* The following Filters are populated
*
* <ul>
* <li>{@link OpenIDAuthenticationFilter}</li>
* </ul>
*
* <h2>Shared Objects Created</h2>
*
* <ul>
* <li>{@link AuthenticationEntryPoint} is populated with a
* {@link LoginUrlAuthenticationEntryPoint}</li>
* <li>An {@link OpenIDAuthenticationProvider} is populated into
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
* </li>
* </ul>
*
* <h2>Shared Objects Used</h2>
*
* The following shared objects are used:
*
* <ul>
* <li>{@link AuthenticationManager}</li>
* <li>{@link RememberMeServices} - is optionally used. See {@link RememberMeConfigurer}
* </li>
* <li>{@link SessionAuthenticationStrategy} - is optionally used. See
* {@link SessionManagementConfigurer}</li>
* </ul>
*
* @author Rob Winch
* @since 3.2
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractAuthenticationFilterConfigurer<H, OpenIDLoginConfigurer<H>, OpenIDAuthenticationFilter> {
private OpenIDConsumer openIDConsumer;
private ConsumerManager consumerManager;
private AuthenticationUserDetailsService<OpenIDAuthenticationToken> authenticationUserDetailsService;
private List<AttributeExchangeConfigurer> attributeExchangeConfigurers = new ArrayList<>();
/**
* Creates a new instance
*/
public OpenIDLoginConfigurer() {
super(new OpenIDAuthenticationFilter(), "/login/openid");
}
/**
* Sets up OpenID attribute exchange for OpenID's matching the specified pattern.
* @param identifierPattern the regular expression for matching on OpenID's (i.e.
* "https://www.google.com/.*", ".*yahoo.com.*", etc)
* @return a {@link AttributeExchangeConfigurer} for further customizations of the
* attribute exchange
*/
public AttributeExchangeConfigurer attributeExchange(String identifierPattern) {
AttributeExchangeConfigurer attributeExchangeConfigurer = new AttributeExchangeConfigurer(identifierPattern);
this.attributeExchangeConfigurers.add(attributeExchangeConfigurer);
return attributeExchangeConfigurer;
}
/**
* Sets up OpenID attribute exchange for OpenIDs matching the specified pattern. The
* default pattern is &quot;.*&quot;, it can be specified using
* {@link AttributeExchangeConfigurer#identifierPattern(String)}
* @param attributeExchangeCustomizer the {@link Customizer} to provide more options
* for the {@link AttributeExchangeConfigurer}
* @return a {@link OpenIDLoginConfigurer} for further customizations
*/
public OpenIDLoginConfigurer<H> attributeExchange(
Customizer<AttributeExchangeConfigurer> attributeExchangeCustomizer) {
AttributeExchangeConfigurer attributeExchangeConfigurer = new AttributeExchangeConfigurer(".*");
attributeExchangeCustomizer.customize(attributeExchangeConfigurer);
this.attributeExchangeConfigurers.add(attributeExchangeConfigurer);
return this;
}
/**
* Allows specifying the {@link OpenIDConsumer} to be used. The default is using an
* {@link OpenID4JavaConsumer}.
* @param consumer the {@link OpenIDConsumer} to be used
* @return the {@link OpenIDLoginConfigurer} for further customizations
*/
public OpenIDLoginConfigurer<H> consumer(OpenIDConsumer consumer) {
this.openIDConsumer = consumer;
return this;
}
/**
* Allows specifying the {@link ConsumerManager} to be used. If specified, will be
* populated into an {@link OpenID4JavaConsumer}.
*
* <p>
* This is a shortcut for specifying the {@link OpenID4JavaConsumer} with a specific
* {@link ConsumerManager} on {@link #consumer(OpenIDConsumer)}.
* </p>
* @param consumerManager the {@link ConsumerManager} to use. Cannot be null.
* @return the {@link OpenIDLoginConfigurer} for further customizations
*/
public OpenIDLoginConfigurer<H> consumerManager(ConsumerManager consumerManager) {
this.consumerManager = consumerManager;
return this;
}
/**
* The {@link AuthenticationUserDetailsService} to use. By default a
* {@link UserDetailsByNameServiceWrapper} is used with the {@link UserDetailsService}
* shared object found with {@link HttpSecurity#getSharedObject(Class)}.
* @param authenticationUserDetailsService the {@link AuthenticationDetailsSource} to
* use
* @return the {@link OpenIDLoginConfigurer} for further customizations
*/
public OpenIDLoginConfigurer<H> authenticationUserDetailsService(
AuthenticationUserDetailsService<OpenIDAuthenticationToken> authenticationUserDetailsService) {
this.authenticationUserDetailsService = authenticationUserDetailsService;
return this;
}
/**
* Specifies the URL used to authenticate OpenID requests. If the
* {@link HttpServletRequest} matches this URL the {@link OpenIDAuthenticationFilter}
* will attempt to authenticate the request. The default is "/login/openid".
* @param loginProcessingUrl the URL used to perform authentication
* @return the {@link OpenIDLoginConfigurer} for additional customization
*/
@Override
public OpenIDLoginConfigurer<H> loginProcessingUrl(String loginProcessingUrl) {
return super.loginProcessingUrl(loginProcessingUrl);
}
/**
* <p>
* Specifies the URL to send users to if login is required. If used with
* {@link WebSecurityConfigurerAdapter} a default login page will be generated when
* this attribute is not specified.
* </p>
*
* <p>
* If a URL is specified or this is not being used in conjunction with
* {@link WebSecurityConfigurerAdapter}, users are required to process the specified
* URL to generate a login page.
* </p>
*
* <ul>
* <li>It must be an HTTP POST</li>
* <li>It must be submitted to {@link #loginProcessingUrl(String)}</li>
* <li>It should include the OpenID as an HTTP parameter by the name of
* {@link OpenIDAuthenticationFilter#DEFAULT_CLAIMED_IDENTITY_FIELD}</li>
* </ul>
*
*
* <h2>Impact on other defaults</h2>
*
* Updating this value, also impacts a number of other default values. For example,
* the following are the default values when only formLogin() was specified.
*
* <ul>
* <li>/login GET - the login form</li>
* <li>/login POST - process the credentials and if valid authenticate the user</li>
* <li>/login?error GET - redirect here for failed authentication attempts</li>
* <li>/login?logout GET - redirect here after successfully logging out</li>
* </ul>
*
* If "/authenticate" was passed to this method it update the defaults as shown below:
*
* <ul>
* <li>/authenticate GET - the login form</li>
* <li>/authenticate POST - process the credentials and if valid authenticate the user
* </li>
* <li>/authenticate?error GET - redirect here for failed authentication attempts</li>
* <li>/authenticate?logout GET - redirect here after successfully logging out</li>
* </ul>
* @param loginPage the login page to redirect to if authentication is required (i.e.
* "/login")
* @return the {@link FormLoginConfigurer} for additional customization
*/
@Override
public OpenIDLoginConfigurer<H> loginPage(String loginPage) {
return super.loginPage(loginPage);
}
@Override
public void init(H http) throws Exception {
super.init(http);
OpenIDAuthenticationProvider authenticationProvider = new OpenIDAuthenticationProvider();
authenticationProvider.setAuthenticationUserDetailsService(getAuthenticationUserDetailsService(http));
authenticationProvider = postProcess(authenticationProvider);
http.authenticationProvider(authenticationProvider);
initDefaultLoginFilter(http);
}
@Override
public void configure(H http) throws Exception {
getAuthenticationFilter().setConsumer(getConsumer());
super.configure(http);
}
@Override
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
return new AntPathRequestMatcher(loginProcessingUrl);
}
/**
* Gets the {@link OpenIDConsumer} that was configured or defaults to an
* {@link OpenID4JavaConsumer}.
* @return the {@link OpenIDConsumer} to use
* @throws ConsumerException
*/
private OpenIDConsumer getConsumer() throws ConsumerException {
if (this.openIDConsumer == null) {
this.openIDConsumer = new OpenID4JavaConsumer(getConsumerManager(), attributesToFetchFactory());
}
return this.openIDConsumer;
}
/**
* Gets the {@link ConsumerManager} that was configured or defaults to using a
* {@link ConsumerManager} with the default constructor.
* @return the {@link ConsumerManager} to use
*/
private ConsumerManager getConsumerManager() {
if (this.consumerManager != null) {
return this.consumerManager;
}
return new ConsumerManager();
}
/**
* Creates an {@link RegexBasedAxFetchListFactory} using the attributes populated by
* {@link AttributeExchangeConfigurer}
* @return the {@link AxFetchListFactory} to use
*/
private AxFetchListFactory attributesToFetchFactory() {
Map<String, List<OpenIDAttribute>> identityToAttrs = new HashMap<>();
for (AttributeExchangeConfigurer conf : this.attributeExchangeConfigurers) {
identityToAttrs.put(conf.identifier, conf.getAttributes());
}
return new RegexBasedAxFetchListFactory(identityToAttrs);
}
/**
* Gets the {@link AuthenticationUserDetailsService} that was configured or defaults
* to {@link UserDetailsByNameServiceWrapper} that uses a {@link UserDetailsService}
* looked up using {@link HttpSecurity#getSharedObject(Class)}
* @param http the current {@link HttpSecurity}
* @return the {@link AuthenticationUserDetailsService}.
*/
private AuthenticationUserDetailsService<OpenIDAuthenticationToken> getAuthenticationUserDetailsService(H http) {
if (this.authenticationUserDetailsService != null) {
return this.authenticationUserDetailsService;
}
return new UserDetailsByNameServiceWrapper<>(http.getSharedObject(UserDetailsService.class));
}
/**
* If available, initializes the {@link DefaultLoginPageGeneratingFilter} shared
* object.
* @param http the {@link HttpSecurityBuilder} to use
*/
private void initDefaultLoginFilter(H http) {
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http
.getSharedObject(DefaultLoginPageGeneratingFilter.class);
if (loginPageGeneratingFilter != null && !isCustomLoginPage()) {
loginPageGeneratingFilter.setOpenIdEnabled(true);
loginPageGeneratingFilter.setOpenIDauthenticationUrl(getLoginProcessingUrl());
String loginPageUrl = loginPageGeneratingFilter.getLoginPageUrl();
if (loginPageUrl == null) {
loginPageGeneratingFilter.setLoginPageUrl(getLoginPage());
loginPageGeneratingFilter.setFailureUrl(getFailureUrl());
}
loginPageGeneratingFilter
.setOpenIDusernameParameter(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD);
}
}
/**
* A class used to add OpenID attributes to look up
*
* @author Rob Winch
*/
public final class AttributeExchangeConfigurer {
private String identifier;
private List<OpenIDAttribute> attributes = new ArrayList<>();
private List<AttributeConfigurer> attributeConfigurers = new ArrayList<>();
/**
* Creates a new instance
* @param identifierPattern the pattern that attempts to match on the OpenID
* @see OpenIDLoginConfigurer#attributeExchange(String)
*/
private AttributeExchangeConfigurer(String identifierPattern) {
this.identifier = identifierPattern;
}
/**
* Get the {@link OpenIDLoginConfigurer} to customize the OpenID configuration
* further
* @return the {@link OpenIDLoginConfigurer}
*/
public OpenIDLoginConfigurer<H> and() {
return OpenIDLoginConfigurer.this;
}
/**
* Sets the regular expression for matching on OpenID's (i.e.
* "https://www.google.com/.*", ".*yahoo.com.*", etc)
* @param identifierPattern the regular expression for matching on OpenID's
* @return the {@link AttributeExchangeConfigurer} for further customization of
* attribute exchange
*/
public AttributeExchangeConfigurer identifierPattern(String identifierPattern) {
this.identifier = identifierPattern;
return this;
}
/**
* Adds an {@link OpenIDAttribute} to be obtained for the configured OpenID
* pattern.
* @param attribute the {@link OpenIDAttribute} to obtain
* @return the {@link AttributeExchangeConfigurer} for further customization of
* attribute exchange
*/
public AttributeExchangeConfigurer attribute(OpenIDAttribute attribute) {
this.attributes.add(attribute);
return this;
}
/**
* Adds an {@link OpenIDAttribute} with the given name
* @param name the name of the {@link OpenIDAttribute} to create
* @return an {@link AttributeConfigurer} to further configure the
* {@link OpenIDAttribute} that should be obtained.
*/
public AttributeConfigurer attribute(String name) {
AttributeConfigurer attributeConfigurer = new AttributeConfigurer(name);
this.attributeConfigurers.add(attributeConfigurer);
return attributeConfigurer;
}
/**
* Adds an {@link OpenIDAttribute} named &quot;default-attribute&quot;. The name
* can by updated using {@link AttributeConfigurer#name(String)}.
* @param attributeCustomizer the {@link Customizer} to provide more options for
* the {@link AttributeConfigurer}
* @return a {@link AttributeExchangeConfigurer} for further customizations
*/
public AttributeExchangeConfigurer attribute(Customizer<AttributeConfigurer> attributeCustomizer) {
AttributeConfigurer attributeConfigurer = new AttributeConfigurer();
attributeCustomizer.customize(attributeConfigurer);
this.attributeConfigurers.add(attributeConfigurer);
return this;
}
/**
* Gets the {@link OpenIDAttribute}'s for the configured OpenID pattern
* @return
*/
private List<OpenIDAttribute> getAttributes() {
for (AttributeConfigurer config : this.attributeConfigurers) {
this.attributes.add(config.build());
}
this.attributeConfigurers.clear();
return this.attributes;
}
/**
* Configures an {@link OpenIDAttribute}
*
* @author Rob Winch
* @since 3.2
*/
public final class AttributeConfigurer {
private String name;
private int count = 1;
private boolean required = false;
private String type;
/**
* Creates a new instance named "default-attribute". The name can by updated
* using {@link #name(String)}.
*
* @see AttributeExchangeConfigurer#attribute(String)
*/
private AttributeConfigurer() {
this.name = "default-attribute";
}
/**
* Creates a new instance
* @param name the name of the attribute
* @see AttributeExchangeConfigurer#attribute(String)
*/
private AttributeConfigurer(String name) {
this.name = name;
}
/**
* Specifies the number of attribute values to request. Default is 1.
* @param count the number of attributes to request.
* @return the {@link AttributeConfigurer} for further customization
*/
public AttributeConfigurer count(int count) {
this.count = count;
return this;
}
/**
* Specifies that this attribute is required. The default is
* <code>false</code>. Note that as outlined in the OpenID specification,
* required attributes are not validated by the OpenID Provider. Developers
* should perform any validation in custom code.
* @param required specifies the attribute is required
* @return the {@link AttributeConfigurer} for further customization
*/
public AttributeConfigurer required(boolean required) {
this.required = required;
return this;
}
/**
* The OpenID attribute type.
* @param type
* @return the {@link AttributeConfigurer} for further customizations
*/
public AttributeConfigurer type(String type) {
this.type = type;
return this;
}
/**
* The OpenID attribute name.
* @param name
* @return the {@link AttributeConfigurer} for further customizations
*/
public AttributeConfigurer name(String name) {
this.name = name;
return this;
}
/**
* Gets the {@link AttributeExchangeConfigurer} for further customization of
* the attributes
* @return the {@link AttributeConfigurer}
*/
public AttributeExchangeConfigurer and() {
return AttributeExchangeConfigurer.this;
}
/**
* Builds the {@link OpenIDAttribute}.
* @return
*/
private OpenIDAttribute build() {
OpenIDAttribute attribute = new OpenIDAttribute(this.name, this.type);
attribute.setCount(this.count);
attribute.setRequired(this.required);
return attribute;
}
}
}
}

View File

@ -85,16 +85,6 @@ final class AuthenticationConfigBuilder {
private static final String DEF_REALM = "Realm";
static final String OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationFilter";
static final String OPEN_ID_AUTHENTICATION_PROVIDER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationProvider";
private static final String OPEN_ID_CONSUMER_CLASS = "org.springframework.security.openid.OpenID4JavaConsumer";
static final String OPEN_ID_ATTRIBUTE_CLASS = "org.springframework.security.openid.OpenIDAttribute";
private static final String OPEN_ID_ATTRIBUTE_FACTORY_CLASS = "org.springframework.security.openid.RegexBasedAxFetchListFactory";
static final String AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter";
static final String ATT_AUTH_DETAILS_SOURCE_REF = "authentication-details-source-ref";
@ -135,14 +125,8 @@ final class AuthenticationConfigBuilder {
private BeanDefinition formEntryPoint;
private BeanDefinition openIDEntryPoint;
private BeanReference openIDProviderRef;
private String formFilterId = null;
private String openIDFilterId = null;
private BeanDefinition x509Filter;
private BeanReference x509ProviderRef;
@ -180,12 +164,8 @@ final class AuthenticationConfigBuilder {
private String loginProcessingUrl;
private String openidLoginProcessingUrl;
private String formLoginPage;
private String openIDLoginPage;
private boolean oauth2LoginEnabled;
private boolean defaultAuthorizedClientRepositoryRegistered;
@ -237,7 +217,6 @@ final class AuthenticationConfigBuilder {
createBearerTokenAuthenticationFilter(authenticationManager);
createFormLoginFilter(sessionStrategy, authenticationManager);
createOAuth2ClientFilters(sessionStrategy, requestCache, authenticationManager);
createOpenIDLoginFilter(sessionStrategy, authenticationManager);
createX509Filter(authenticationManager);
createJeeFilter(authenticationManager);
createLogoutFilter();
@ -395,106 +374,6 @@ final class AuthenticationConfigBuilder {
}
}
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element openIDLoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OPENID_LOGIN);
RootBeanDefinition openIDFilter = null;
if (openIDLoginElt != null) {
openIDFilter = parseOpenIDFilter(sessionStrategy, openIDLoginElt);
}
if (openIDFilter != null) {
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", this.allowSessionCreation);
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
// Required by login page filter
this.openIDFilterId = this.pc.getReaderContext().generateBeanName(openIDFilter);
this.pc.registerBeanComponent(new BeanComponentDefinition(openIDFilter, this.openIDFilterId));
injectRememberMeServicesRef(openIDFilter, this.rememberMeServicesId);
createOpenIDProvider();
}
}
/**
* Parses OpenID 1.0 and 2.0 - related parts of configuration xmls
* @param sessionStrategy sessionStrategy
* @param openIDLoginElt the element from the xml file
* @return the parsed filter as rootBeanDefinition
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
private RootBeanDefinition parseOpenIDFilter(BeanReference sessionStrategy, Element openIDLoginElt) {
RootBeanDefinition openIDFilter;
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/login/openid", null,
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, this.requestCache, sessionStrategy,
this.allowSessionCreation, this.portMapper, this.portResolver);
parser.parse(openIDLoginElt, this.pc);
openIDFilter = parser.getFilterBean();
this.openIDEntryPoint = parser.getEntryPointBean();
this.openidLoginProcessingUrl = parser.getLoginProcessingUrl();
this.openIDLoginPage = parser.getLoginPage();
List<Element> attrExElts = DomUtils.getChildElementsByTagName(openIDLoginElt,
Elements.OPENID_ATTRIBUTE_EXCHANGE);
if (!attrExElts.isEmpty()) {
// Set up the consumer with the required attribute list
BeanDefinitionBuilder consumerBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_CONSUMER_CLASS);
BeanDefinitionBuilder axFactory = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_FACTORY_CLASS);
ManagedMap<String, ManagedList<BeanDefinition>> axMap = new ManagedMap<>();
for (Element attrExElt : attrExElts) {
String identifierMatch = attrExElt.getAttribute("identifier-match");
if (!StringUtils.hasText(identifierMatch)) {
if (attrExElts.size() > 1) {
this.pc.getReaderContext().error("You must supply an identifier-match attribute if using more"
+ " than one " + Elements.OPENID_ATTRIBUTE_EXCHANGE + " element", attrExElt);
}
// Match anything
identifierMatch = ".*";
}
axMap.put(identifierMatch, parseOpenIDAttributes(attrExElt));
}
axFactory.addConstructorArgValue(axMap);
consumerBldr.addConstructorArgValue(axFactory.getBeanDefinition());
openIDFilter.getPropertyValues().addPropertyValue("consumer", consumerBldr.getBeanDefinition());
}
return openIDFilter;
}
private ManagedList<BeanDefinition> parseOpenIDAttributes(Element attrExElt) {
ManagedList<BeanDefinition> attributes = new ManagedList<>();
for (Element attElt : DomUtils.getChildElementsByTagName(attrExElt, Elements.OPENID_ATTRIBUTE)) {
String name = attElt.getAttribute("name");
String type = attElt.getAttribute("type");
String required = attElt.getAttribute("required");
String count = attElt.getAttribute("count");
BeanDefinitionBuilder attrBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_CLASS);
attrBldr.addConstructorArgValue(name);
attrBldr.addConstructorArgValue(type);
if (StringUtils.hasLength(required)) {
attrBldr.addPropertyValue("required", Boolean.valueOf(required));
}
if (StringUtils.hasLength(count)) {
attrBldr.addPropertyValue("count", Integer.parseInt(count));
}
attributes.add(attrBldr.getBeanDefinition());
}
return attributes;
}
private void createOpenIDProvider() {
Element openIDLoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OPENID_LOGIN);
BeanDefinitionBuilder openIDProviderBuilder = BeanDefinitionBuilder
.rootBeanDefinition(OPEN_ID_AUTHENTICATION_PROVIDER_CLASS);
RootBeanDefinition uds = new RootBeanDefinition();
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
uds.setFactoryMethodName("authenticationUserDetailsService");
uds.getConstructorArgumentValues().addGenericArgumentValue(openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF));
openIDProviderBuilder.addPropertyValue("authenticationUserDetailsService", uds);
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
this.openIDProviderRef = new RuntimeBeanReference(
this.pc.getReaderContext().registerWithGeneratedName(openIDProvider));
}
private void injectRememberMeServicesRef(RootBeanDefinition bean, String rememberMeServicesId) {
if (rememberMeServicesId != null) {
bean.getPropertyValues().addPropertyValue("rememberMeServices",
@ -640,10 +519,9 @@ final class AuthenticationConfigBuilder {
}
void createLoginPageFilterIfNeeded() {
boolean needLoginPage = this.formFilterId != null || this.openIDFilterId != null
|| this.oauth2LoginFilterId != null;
boolean needLoginPage = this.formFilterId != null || this.oauth2LoginFilterId != null;
// If no login page has been defined, add in the default page generator.
if (needLoginPage && this.formLoginPage == null && this.openIDLoginPage == null) {
if (needLoginPage && this.formLoginPage == null) {
this.logger.info("No login page configured. The default internal one will be used. Use the '"
+ FormLoginBeanDefinitionParser.ATT_LOGIN_PAGE + "' attribute to set the URL of the login page.");
BeanDefinitionBuilder loginPageFilter = BeanDefinitionBuilder
@ -657,12 +535,7 @@ final class AuthenticationConfigBuilder {
loginPageFilter.addConstructorArgReference(this.formFilterId);
loginPageFilter.addPropertyValue("authenticationUrl", this.loginProcessingUrl);
}
if (this.openIDFilterId != null) {
loginPageFilter.addConstructorArgReference(this.openIDFilterId);
loginPageFilter.addPropertyValue("openIDauthenticationUrl", this.openidLoginProcessingUrl);
}
if (this.oauth2LoginFilterId != null) {
loginPageFilter.addConstructorArgReference(this.oauth2LoginFilterId);
loginPageFilter.addPropertyValue("Oauth2LoginEnabled", true);
loginPageFilter.addPropertyValue("Oauth2AuthenticationUrlToClientName", this.oauth2LoginLinks);
}
@ -820,21 +693,11 @@ final class AuthenticationConfigBuilder {
}
Element basicAuthElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.BASIC_AUTH);
Element formLoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.FORM_LOGIN);
Element openIDLoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OPENID_LOGIN);
// Basic takes precedence if explicit element is used and no others are configured
if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null
&& this.oauth2LoginEntryPoint == null) {
if (basicAuthElt != null && formLoginElt == null && this.oauth2LoginEntryPoint == null) {
return this.basicEntryPoint;
}
// If formLogin has been enabled either through an element or auto-config, then it
// is used if no openID login page
// has been set.
if (this.formLoginPage != null && this.openIDLoginPage != null) {
this.pc.getReaderContext().error(
"Only one login-page can be defined, either for OpenID or form-login, " + "but not both.",
this.pc.extractSource(openIDLoginElt));
}
if (this.formFilterId != null && this.openIDLoginPage == null) {
if (this.formFilterId != null) {
// If form login was enabled through element and Oauth2 login was enabled from
// element then use form login (gh-6802)
if (formLoginElt != null && this.oauth2LoginEntryPoint != null) {
@ -846,10 +709,6 @@ final class AuthenticationConfigBuilder {
return this.formEntryPoint;
}
}
// Otherwise use OpenID if enabled
if (this.openIDFilterId != null) {
return this.openIDEntryPoint;
}
// If X.509 or JEE have been enabled, use the preauth entry point.
if (this.preAuthEntryPoint != null) {
return this.preAuthEntryPoint;
@ -902,10 +761,6 @@ final class AuthenticationConfigBuilder {
filters.add(new OrderDecorator(this.oauth2AuthorizationRequestRedirectFilter,
SecurityFilters.OAUTH2_AUTHORIZATION_REQUEST_FILTER));
}
if (this.openIDFilterId != null) {
filters.add(
new OrderDecorator(new RuntimeBeanReference(this.openIDFilterId), SecurityFilters.OPENID_FILTER));
}
if (this.loginPageGenerationFilter != null) {
filters.add(new OrderDecorator(this.loginPageGenerationFilter, SecurityFilters.LOGIN_PAGE_FILTER));
filters.add(new OrderDecorator(this.logoutPageGenerationFilter, SecurityFilters.LOGOUT_PAGE_FILTER));
@ -935,9 +790,6 @@ final class AuthenticationConfigBuilder {
if (this.rememberMeProviderRef != null) {
providers.add(this.rememberMeProviderRef);
}
if (this.openIDProviderRef != null) {
providers.add(this.openIDProviderRef);
}
if (this.x509ProviderRef != null) {
providers.add(this.x509ProviderRef);
}

View File

@ -57,8 +57,6 @@ enum SecurityFilters {
FORM_LOGIN_FILTER,
OPENID_FILTER,
LOGIN_PAGE_FILTER,
LOGOUT_PAGE_FILTER,

View File

@ -109,7 +109,7 @@ public class UserDetailsServiceFactoryBean implements ApplicationContextAware {
}
if (beans.size() > 1) {
throw new ApplicationContextException("More than one UserDetailsService registered. Please "
+ "use a specific Id reference in <remember-me/> <openid-login/> or <x509 /> elements.");
+ "use a specific Id reference in <remember-me/> or <x509 /> elements.");
}
return (UserDetailsService) beans.values().toArray()[0];
}

View File

@ -312,7 +312,7 @@ http-firewall =
http =
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "security" attribute to "none".
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & oauth2-login? & oauth2-client? & oauth2-resource-server? & openid-login? & x509? & jee? & http-basic? & logout? & password-management? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler? & headers? & csrf? & cors?) }
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & oauth2-login? & oauth2-client? & oauth2-resource-server? & x509? & jee? & http-basic? & logout? & password-management? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler? & headers? & csrf? & cors?) }
http.attlist &=
## The request URL pattern which will be mapped to the filter chain created by this <http> element. If omitted, the filter chain will match all requests.
attribute pattern {xsd:token}?
@ -630,36 +630,6 @@ opaque-token.attlist &=
## Reference to an OpaqueTokenIntrospector
attribute introspector-ref {xsd:token}?
openid-login =
## Sets up form login for authentication with an Open ID identity. NOTE: The OpenID 1.0 and 2.0 protocols have been deprecated and users are <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is supported by <code>spring-security-oauth2</code>.
element openid-login {form-login.attlist, user-service-ref?, attribute-exchange*}
attribute-exchange =
## Sets up an attribute exchange configuration to request specified attributes from the OpenID identity provider. When multiple elements are used, each must have an identifier-attribute attribute. Each configuration will be matched in turn against the supplied login identifier until a match is found.
element attribute-exchange {attribute-exchange.attlist, openid-attribute+}
attribute-exchange.attlist &=
## A regular expression which will be compared against the claimed identity, when deciding which attribute-exchange configuration to use during authentication.
attribute identifier-match {xsd:token}?
openid-attribute =
## Attributes used when making an OpenID AX Fetch Request. NOTE: The OpenID 1.0 and 2.0 protocols have been deprecated and users are <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is supported by <code>spring-security-oauth2</code>.
element openid-attribute {openid-attribute.attlist}
openid-attribute.attlist &=
## Specifies the name of the attribute that you wish to get back. For example, email.
attribute name {xsd:token}
openid-attribute.attlist &=
## Specifies the attribute type. For example, https://axschema.org/contact/email. See your OP's documentation for valid attribute types.
attribute type {xsd:token}
openid-attribute.attlist &=
## Specifies if this attribute is required to the OP, but does not error out if the OP does not return the attribute. Default is false.
attribute required {xsd:boolean}?
openid-attribute.attlist &=
## Specifies the number of attributes that you wish to get back. For example, return 3 emails. The default value is 1.
attribute count {xsd:int}?
filter-chain-map =
## Used to explicitly configure a FilterChainProxy instance with a FilterChainMap
element filter-chain-map {filter-chain-map.attlist, filter-chain+}
@ -1148,4 +1118,4 @@ position =
## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
attribute position {named-security-filter}
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CORS_FILTER" | "CSRF_FILTER" | "LOGOUT_FILTER" | "OAUTH2_AUTHORIZATION_REQUEST_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "OAUTH2_LOGIN_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" | "LOGIN_PAGE_FILTER" |"LOGOUT_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BEARER_TOKEN_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER" | "WELL_KNOWN_CHANGE_PASSWORD_REDIRECT_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CORS_FILTER" | "CSRF_FILTER" | "LOGOUT_FILTER" | "OAUTH2_AUTHORIZATION_REQUEST_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "OAUTH2_LOGIN_FILTER" | "FORM_LOGIN_FILTER" | "LOGIN_PAGE_FILTER" |"LOGOUT_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BEARER_TOKEN_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER" | "WELL_KNOWN_CHANGE_PASSWORD_REDIRECT_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"

View File

@ -1015,28 +1015,6 @@
<xs:element ref="security:oauth2-login"/>
<xs:element ref="security:oauth2-client"/>
<xs:element ref="security:oauth2-resource-server"/>
<xs:element name="openid-login">
<xs:annotation>
<xs:documentation>Sets up form login for authentication with an Open ID identity. NOTE: The OpenID 1.0 and
2.0 protocols have been deprecated and users are &lt;a
href="https://openid.net/specs/openid-connect-migration-1_0.html"&gt;encouraged to
migrate&lt;/a&gt; to &lt;a href="https://openid.net/connect/"&gt;OpenID Connect&lt;/a&gt;, which is
supported by &lt;code&gt;spring-security-oauth2&lt;/code&gt;.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:attribute-exchange"/>
</xs:sequence>
<xs:attributeGroup ref="security:form-login.attlist"/>
<xs:attribute name="user-service-ref" type="xs:token">
<xs:annotation>
<xs:documentation>A reference to a user-service (or UserDetailsService bean) Id
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="x509">
<xs:annotation>
<xs:documentation>Adds support for X.509 client authentication.
@ -1942,73 +1920,6 @@
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="attribute-exchange">
<xs:annotation>
<xs:documentation>Sets up an attribute exchange configuration to request specified attributes from the
OpenID identity provider. When multiple elements are used, each must have an
identifier-attribute attribute. Each configuration will be matched in turn against the
supplied login identifier until a match is found.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="security:openid-attribute"/>
</xs:sequence>
<xs:attributeGroup ref="security:attribute-exchange.attlist"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="attribute-exchange.attlist">
<xs:attribute name="identifier-match" type="xs:token">
<xs:annotation>
<xs:documentation>A regular expression which will be compared against the claimed identity, when deciding
which attribute-exchange configuration to use during authentication.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="openid-attribute">
<xs:annotation>
<xs:documentation>Attributes used when making an OpenID AX Fetch Request. NOTE: The OpenID 1.0 and 2.0
protocols have been deprecated and users are &lt;a
href="https://openid.net/specs/openid-connect-migration-1_0.html"&gt;encouraged to
migrate&lt;/a&gt; to &lt;a href="https://openid.net/connect/"&gt;OpenID Connect&lt;/a&gt;, which is
supported by &lt;code&gt;spring-security-oauth2&lt;/code&gt;.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="security:openid-attribute.attlist"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="openid-attribute.attlist">
<xs:attribute name="name" use="required" type="xs:token">
<xs:annotation>
<xs:documentation>Specifies the name of the attribute that you wish to get back. For example, email.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="type" use="required" type="xs:token">
<xs:annotation>
<xs:documentation>Specifies the attribute type. For example, https://axschema.org/contact/email. See your
OP's documentation for valid attribute types.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="required" type="xs:boolean">
<xs:annotation>
<xs:documentation>Specifies if this attribute is required to the OP, but does not error out if the OP does
not return the attribute. Default is false.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="count" type="xs:int">
<xs:annotation>
<xs:documentation>Specifies the number of attributes that you wish to get back. For example, return 3
emails. The default value is 1.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="filter-chain-map">
<xs:annotation>
<xs:documentation>Used to explicitly configure a FilterChainProxy instance with a FilterChainMap
@ -3335,7 +3246,6 @@
<xs:enumeration value="CAS_FILTER"/>
<xs:enumeration value="OAUTH2_LOGIN_FILTER"/>
<xs:enumeration value="FORM_LOGIN_FILTER"/>
<xs:enumeration value="OPENID_FILTER"/>
<xs:enumeration value="LOGIN_PAGE_FILTER"/>
<xs:enumeration value="LOGOUT_PAGE_FILTER"/>
<xs:enumeration value="DIGEST_AUTH_FILTER"/>

View File

@ -260,87 +260,6 @@ public class DefaultLoginPageConfigurerTests {
// @formatter:on
}
@Test
public void loginPageWhenOpenIdLoginConfiguredThenOpedIdLoginPage() throws Exception {
this.spring.register(DefaultLoginPageWithOpenIDConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Identity</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
public void loginPageWhenOpenIdLoginAndFormLoginAndRememberMeConfiguredThenOpedIdLoginPage() throws Exception {
this.spring.register(DefaultLoginPageWithFormLoginOpenIDRememberMeConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n" + " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n"
+ " <p>\n" + " <label for=\"username\" class=\"sr-only\">Identity</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnDefaultLoginPageGeneratingFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
@ -472,42 +391,6 @@ public class DefaultLoginPageConfigurerTests {
}
@EnableWebSecurity
static class DefaultLoginPageWithOpenIDConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.openidLogin();
// @formatter:on
}
}
@EnableWebSecurity
static class DefaultLoginPageWithFormLoginOpenIDRememberMeConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.rememberMe()
.and()
.formLogin()
.and()
.openidLogin();
// @formatter:on
}
}
@EnableWebSecurity
static class DefaultLoginWithCustomAuthenticationEntryPointConfig extends WebSecurityConfigurerAdapter {

View File

@ -1,299 +0,0 @@
/*
* Copyright 2002-2019 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.Arrays;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.yadis.YadisResolver;
import org.openid4java.message.AuthRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.openid.OpenIDAttribute;
import org.springframework.security.openid.OpenIDAuthenticationFilter;
import org.springframework.security.openid.OpenIDAuthenticationStatus;
import org.springframework.security.openid.OpenIDAuthenticationToken;
import org.springframework.security.openid.OpenIDConsumer;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests to verify that all the functionality of &lt;openid-login&gt; attributes is
* present
*
* @author Rob Winch
* @author Josh Cummings
*/
@ExtendWith(SpringTestContextExtension.class)
public class NamespaceHttpOpenIDLoginTests {
public final SpringTestContext spring = new SpringTestContext(this);
@Autowired
MockMvc mvc;
@Test
public void openidLoginWhenUsingDefaultsThenMatchesNamespace() throws Exception {
this.spring.register(OpenIDLoginConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login"));
this.mvc.perform(post("/login/openid").with(csrf())).andExpect(redirectedUrl("/login?error"));
}
@Test
public void openidLoginWhenAttributeExchangeConfiguredThenFetchAttributesMatchAttributeList() throws Exception {
OpenIDLoginAttributeExchangeConfig.CONSUMER_MANAGER = mock(ConsumerManager.class);
AuthRequest mockAuthRequest = mock(AuthRequest.class);
DiscoveryInformation mockDiscoveryInformation = mock(DiscoveryInformation.class);
given(mockAuthRequest.getDestinationUrl(anyBoolean())).willReturn("mockUrl");
given(OpenIDLoginAttributeExchangeConfig.CONSUMER_MANAGER.associate(any()))
.willReturn(mockDiscoveryInformation);
given(OpenIDLoginAttributeExchangeConfig.CONSUMER_MANAGER.authenticate(any(DiscoveryInformation.class), any(),
any())).willReturn(mockAuthRequest);
this.spring.register(OpenIDLoginAttributeExchangeConfig.class).autowire();
try (MockWebServer server = new MockWebServer()) {
String endpoint = server.url("/").toString();
server.enqueue(new MockResponse().addHeader(YadisResolver.YADIS_XRDS_LOCATION, endpoint));
server.enqueue(new MockResponse()
.setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint)));
MvcResult mvcResult = this.mvc.perform(get("/login/openid")
.param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, "https://www.google.com/1"))
.andExpect(status().isFound()).andReturn();
Object attributeObject = mvcResult.getRequest().getSession()
.getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST");
assertThat(attributeObject).isInstanceOf(List.class);
List<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) attributeObject;
assertThat(attributeList.stream().anyMatch((attribute) -> "firstname".equals(attribute.getName())
&& "https://axschema.org/namePerson/first".equals(attribute.getType()) && attribute.isRequired()))
.isTrue();
assertThat(attributeList.stream().anyMatch((attribute) -> "lastname".equals(attribute.getName())
&& "https://axschema.org/namePerson/last".equals(attribute.getType()) && attribute.isRequired()))
.isTrue();
assertThat(attributeList.stream().anyMatch((attribute) -> "email".equals(attribute.getName())
&& "https://axschema.org/contact/email".equals(attribute.getType()) && attribute.isRequired()))
.isTrue();
}
}
@Test
public void openidLoginWhenUsingCustomEndpointsThenMatchesNamespace() throws Exception {
this.spring.register(OpenIDLoginCustomConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/authentication/login"));
this.mvc.perform(post("/authentication/login/process").with(csrf()))
.andExpect(redirectedUrl("/authentication/login?failed"));
}
@Test
public void openidLoginWithCustomHandlersThenBehaviorMatchesNamespace() throws Exception {
OpenIDAuthenticationToken token = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS,
"identityUrl", "message", Arrays.asList(new OpenIDAttribute("name", "type")));
OpenIDLoginCustomRefsConfig.AUDS = mock(AuthenticationUserDetailsService.class);
User user = new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
given(OpenIDLoginCustomRefsConfig.AUDS.loadUserDetails(any(Authentication.class))).willReturn(user);
OpenIDLoginCustomRefsConfig.ADS = spy(new WebAuthenticationDetailsSource());
OpenIDLoginCustomRefsConfig.CONSUMER = mock(OpenIDConsumer.class);
this.spring.register(OpenIDLoginCustomRefsConfig.class, UserDetailsServiceConfig.class).autowire();
given(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class)))
.willThrow(new AuthenticationServiceException("boom"));
// @formatter:off
MockHttpServletRequestBuilder login = post("/login/openid")
.with(csrf())
.param("openid.identity", "identity");
// @formatter:on
this.mvc.perform(login).andExpect(redirectedUrl("/custom/failure"));
reset(OpenIDLoginCustomRefsConfig.CONSUMER);
given(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class))).willReturn(token);
this.mvc.perform(login).andExpect(redirectedUrl("/custom/targetUrl"));
verify(OpenIDLoginCustomRefsConfig.AUDS).loadUserDetails(any(Authentication.class));
verify(OpenIDLoginCustomRefsConfig.ADS).buildDetails(any(Object.class));
}
@Configuration
@EnableWebSecurity
static class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.openidLogin()
.permitAll();
// @formatter:on
}
}
@Configuration
@EnableWebSecurity
static class OpenIDLoginAttributeExchangeConfig extends WebSecurityConfigurerAdapter {
static ConsumerManager CONSUMER_MANAGER;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.openidLogin()
.consumerManager(CONSUMER_MANAGER)
.attributeExchange("https://www.google.com/.*") // attribute-exchange@identifier-match
.attribute("email") // openid-attribute@name
.type("https://axschema.org/contact/email") // openid-attribute@type
.required(true) // openid-attribute@required
.count(1) // openid-attribute@count
.and()
.attribute("firstname")
.type("https://axschema.org/namePerson/first")
.required(true)
.and()
.attribute("lastname")
.type("https://axschema.org/namePerson/last")
.required(true)
.and()
.and()
.attributeExchange(".*yahoo.com.*")
.attribute("email")
.type("https://schema.openid.net/contact/email")
.required(true)
.and()
.attribute("fullname")
.type("https://axschema.org/namePerson")
.required(true)
.and()
.and()
.permitAll();
// @formatter:on
}
}
@Configuration
@EnableWebSecurity
static class OpenIDLoginCustomConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
boolean alwaysUseDefaultSuccess = true;
// @formatter:off
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.openidLogin()
.permitAll()
.loginPage("/authentication/login") // openid-login@login-page
.failureUrl("/authentication/login?failed") // openid-login@authentication-failure-url
.loginProcessingUrl("/authentication/login/process") // openid-login@login-processing-url
.defaultSuccessUrl("/default", alwaysUseDefaultSuccess); // openid-login@default-target-url / openid-login@always-use-default-target
// @formatter:on
}
}
@Configuration
@EnableWebSecurity
static class OpenIDLoginCustomRefsConfig extends WebSecurityConfigurerAdapter {
static AuthenticationUserDetailsService AUDS;
static AuthenticationDetailsSource ADS;
static OpenIDConsumer CONSUMER;
@Override
protected void configure(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler handler = new SavedRequestAwareAuthenticationSuccessHandler();
handler.setDefaultTargetUrl("/custom/targetUrl");
// @formatter:off
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.openidLogin()
// if using UserDetailsService wrap with new UserDetailsByNameServiceWrapper<OpenIDAuthenticationToken>()
.authenticationUserDetailsService(AUDS) // openid-login@user-service-ref
.failureHandler(new SimpleUrlAuthenticationFailureHandler("/custom/failure")) // openid-login@authentication-failure-handler-ref
.successHandler(handler) // openid-login@authentication-success-handler-ref
.authenticationDetailsSource(ADS) // openid-login@authentication-details-source-ref
.withObjectPostProcessor(new ObjectPostProcessor<OpenIDAuthenticationFilter>() {
@Override
public <O extends OpenIDAuthenticationFilter> O postProcess(O filter) {
filter.setConsumer(CONSUMER);
return filter;
}
});
// @formatter:on
}
}
@Configuration
static class UserDetailsServiceConfig {
@Bean
UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(
User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());
}
}
}

View File

@ -1,312 +0,0 @@
/*
* Copyright 2002-2019 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.openid;
import java.util.List;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.yadis.YadisResolver;
import org.openid4java.message.AuthRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.openid.OpenIDAttribute;
import org.springframework.security.openid.OpenIDAuthenticationFilter;
import org.springframework.security.openid.OpenIDAuthenticationProvider;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests for {@link OpenIDLoginConfigurer}
*
* @author Rob Winch
* @author Eleftheria Stein
*/
@ExtendWith(SpringTestContextExtension.class)
public class OpenIDLoginConfigurerTests {
public final SpringTestContext spring = new SpringTestContext(this);
@Autowired
MockMvc mvc;
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnOpenIDAuthenticationFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(OpenIDAuthenticationFilter.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnOpenIDAuthenticationProvider() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(OpenIDAuthenticationProvider.class));
}
@Test
public void openidLoginWhenInvokedTwiceThenUsesOriginalLoginPage() throws Exception {
this.spring.register(InvokeTwiceDoesNotOverrideConfig.class).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login/custom"));
// @formatter:on
}
@Test
public void requestWhenOpenIdLoginPageInLambdaThenRedirectsToLoginPAge() throws Exception {
this.spring.register(OpenIdLoginPageInLambdaConfig.class).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login/custom"));
// @formatter:on
}
@Test
public void requestWhenAttributeExchangeConfiguredThenFetchAttributesMatchAttributeList() throws Exception {
OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER = mock(ConsumerManager.class);
AuthRequest mockAuthRequest = mock(AuthRequest.class);
DiscoveryInformation mockDiscoveryInformation = mock(DiscoveryInformation.class);
given(mockAuthRequest.getDestinationUrl(anyBoolean())).willReturn("mockUrl");
given(OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER.associate(any())).willReturn(mockDiscoveryInformation);
given(OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER.authenticate(any(DiscoveryInformation.class), any(),
any())).willReturn(mockAuthRequest);
this.spring.register(OpenIdAttributesInLambdaConfig.class).autowire();
try (MockWebServer server = new MockWebServer()) {
String endpoint = server.url("/").toString();
server.enqueue(new MockResponse().addHeader(YadisResolver.YADIS_XRDS_LOCATION, endpoint));
server.enqueue(new MockResponse()
.setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint)));
MvcResult mvcResult = this.mvc.perform(
get("/login/openid").param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint))
.andExpect(status().isFound()).andReturn();
Object attributeObject = mvcResult.getRequest().getSession()
.getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST");
assertThat(attributeObject).isInstanceOf(List.class);
List<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) attributeObject;
assertThat(
attributeList.stream()
.anyMatch((attribute) -> "nickname".equals(attribute.getName())
&& "https://schema.openid.net/namePerson/friendly".equals(attribute.getType())))
.isTrue();
assertThat(attributeList.stream()
.anyMatch((attribute) -> "email".equals(attribute.getName())
&& "https://schema.openid.net/contact/email".equals(attribute.getType())
&& attribute.isRequired() && attribute.getCount() == 2)).isTrue();
}
}
@Test
public void requestWhenAttributeNameNotSpecifiedThenAttributeNameDefaulted() throws Exception {
OpenIdAttributesNullNameConfig.CONSUMER_MANAGER = mock(ConsumerManager.class);
AuthRequest mockAuthRequest = mock(AuthRequest.class);
DiscoveryInformation mockDiscoveryInformation = mock(DiscoveryInformation.class);
given(mockAuthRequest.getDestinationUrl(anyBoolean())).willReturn("mockUrl");
given(OpenIdAttributesNullNameConfig.CONSUMER_MANAGER.associate(any())).willReturn(mockDiscoveryInformation);
given(OpenIdAttributesNullNameConfig.CONSUMER_MANAGER.authenticate(any(DiscoveryInformation.class), any(),
any())).willReturn(mockAuthRequest);
this.spring.register(OpenIdAttributesNullNameConfig.class).autowire();
try (MockWebServer server = new MockWebServer()) {
String endpoint = server.url("/").toString();
server.enqueue(new MockResponse().addHeader(YadisResolver.YADIS_XRDS_LOCATION, endpoint));
server.enqueue(new MockResponse()
.setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint)));
// @formatter:off
MockHttpServletRequestBuilder request = get("/login/openid")
.param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint);
MvcResult mvcResult = this.mvc.perform(request)
.andExpect(status().isFound())
.andReturn();
Object attributeObject = mvcResult.getRequest().getSession()
.getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST");
// @formatter:on
assertThat(attributeObject).isInstanceOf(List.class);
List<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) attributeObject;
assertThat(attributeList).hasSize(1);
assertThat(attributeList.get(0).getName()).isEqualTo("default-attribute");
}
}
@EnableWebSecurity
static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
static ObjectPostProcessor<Object> objectPostProcessor;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.openidLogin();
// @formatter:on
}
@Bean
static ObjectPostProcessor<Object> objectPostProcessor() {
return objectPostProcessor;
}
}
static class ReflectingObjectPostProcessor implements ObjectPostProcessor<Object> {
@Override
public <O> O postProcess(O object) {
return object;
}
}
@EnableWebSecurity
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication();
// @formatter:on
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.openidLogin()
.loginPage("/login/custom")
.and()
.openidLogin();
// @formatter:on
}
}
@EnableWebSecurity
static class OpenIdLoginPageInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().authenticated()
)
.openidLogin((openIdLogin) ->
openIdLogin
.loginPage("/login/custom")
);
// @formatter:on
}
}
@EnableWebSecurity
static class OpenIdAttributesInLambdaConfig extends WebSecurityConfigurerAdapter {
static ConsumerManager CONSUMER_MANAGER;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().permitAll()
)
.openidLogin((openIdLogin) ->
openIdLogin
.consumerManager(CONSUMER_MANAGER)
.attributeExchange((attributeExchange) ->
attributeExchange
.identifierPattern(".*")
.attribute((nicknameAttribute) ->
nicknameAttribute
.name("nickname")
.type("https://schema.openid.net/namePerson/friendly")
)
.attribute((emailAttribute) ->
emailAttribute
.name("email")
.type("https://schema.openid.net/contact/email")
.required(true)
.count(2)
)
)
);
// @formatter:on
}
}
@EnableWebSecurity
static class OpenIdAttributesNullNameConfig extends WebSecurityConfigurerAdapter {
static ConsumerManager CONSUMER_MANAGER;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().permitAll()
)
.openidLogin((openIdLogin) ->
openIdLogin
.consumerManager(CONSUMER_MANAGER)
.attributeExchange((attributeExchange) ->
attributeExchange
.identifierPattern(".*")
.attribute(withDefaults())
)
);
// @formatter:on
}
}
}

View File

@ -92,21 +92,6 @@ public class UserServiceBeanDefinitionParserTests {
Long.parseLong(joe.getPassword());
}
@Test
public void worksWithOpenIDUrlsAsNames() {
// @formatter:off
setContext("<user-service id='service'>"
+ " <user name='https://joe.myopenid.com/' authorities='ROLE_A'/>"
+ " <user name='https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9' authorities='ROLE_A'/>"
+ "</user-service>");
// @formatter:on
UserDetailsService userService = (UserDetailsService) this.appContext.getBean("service");
assertThat(userService.loadUserByUsername("https://joe.myopenid.com/").getUsername())
.isEqualTo("https://joe.myopenid.com/");
assertThat(userService.loadUserByUsername("https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9")
.getUsername()).isEqualTo("https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9");
}
@Test
public void disabledAndEmbeddedFlagsAreSupported() {
// @formatter:off

View File

@ -129,91 +129,6 @@ public class FormLoginBeanDefinitionParserTests {
// @formatter:on
}
@Test
public void getLoginWhenConfiguredForOpenIdThenLoginPageReflects() throws Exception {
this.spring.configLocations(this.xml("WithOpenId")).autowire();
// @formatter:off
String expectedContent = "<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Identity</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ "</div>\n"
+ "</body></html>";
// @formatter:on
this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
}
@Test
public void getLoginWhenConfiguredForOpenIdWithCustomAttributesThenLoginPageReflects() throws Exception {
this.spring.configLocations(this.xml("WithOpenIdCustomAttributes")).autowire();
// @formatter:off
String expectedContent = "<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/signin\">\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n" + " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Identity</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ "</div>\n"
+ "</body></html>";
// @formatter:on
this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
}
@Test
public void failedLoginWhenConfiguredWithCustomAuthenticationFailureThenForwardsAccordingly() throws Exception {
this.spring.configLocations(this.xml("WithAuthenticationFailureForwardUrl")).autowire();

View File

@ -78,7 +78,6 @@ import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.openid.OpenIDAuthenticationFilter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.access.ExceptionTranslationFilter;
@ -105,7 +104,6 @@ import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
@ -624,8 +622,6 @@ public class MiscHttpConfigTests {
this.mvc.perform(get("/details").session(session))
.andExpect(content().string(details.getClass().getName()));
// @formatter:on
assertThat(ReflectionTestUtils.getField(getFilter(OpenIDAuthenticationFilter.class),
"authenticationDetailsSource")).isEqualTo(source);
}
@Test

View File

@ -1,203 +0,0 @@
/*
* Copyright 2002-2018 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.HashSet;
import java.util.Set;
import jakarta.servlet.Filter;
import jakarta.servlet.http.HttpServletRequest;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.discovery.yadis.YadisResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.openid.OpenID4JavaConsumer;
import org.springframework.security.openid.OpenIDAuthenticationFilter;
import org.springframework.security.openid.OpenIDConsumer;
import org.springframework.security.util.FieldUtils;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hamcrest.CoreMatchers.containsString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests usage of the &lt;openid-login&gt; element
*
* @author Luke Taylor
*/
@ExtendWith(SpringTestContextExtension.class)
public class OpenIDConfigTests {
private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/http/OpenIDConfigTests";
@Autowired
MockMvc mvc;
public final SpringTestContext spring = new SpringTestContext(this);
@Test
public void requestWhenOpenIDAndFormLoginBothConfiguredThenRedirectsToGeneratedLoginPage() throws Exception {
this.spring.configLocations(this.xml("WithFormLogin")).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
assertThat(getFilter(DefaultLoginPageGeneratingFilter.class)).isNotNull();
}
@Test
public void requestWhenOpenIDAndFormLoginWithFormLoginPageConfiguredThenFormLoginPageWins() throws Exception {
this.spring.configLocations(this.xml("WithFormLoginPage")).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/form-page"));
// @formatter:on
}
@Test
public void requestWhenOpenIDAndFormLoginWithOpenIDLoginPageConfiguredThenOpenIDLoginPageWins() throws Exception {
this.spring.configLocations(this.xml("WithOpenIDLoginPageAndFormLogin")).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/openid-page"));
// @formatter:on
}
@Test
public void configureWhenOpenIDAndFormLoginBothConfigureLoginPagesThenWiringException() {
assertThatExceptionOfType(BeanDefinitionParsingException.class)
.isThrownBy(() -> this.spring.configLocations(this.xml("WithFormLoginAndOpenIDLoginPages")).autowire());
}
@Test
public void requestWhenOpenIDAndRememberMeConfiguredThenRememberMePassedToIdp() throws Exception {
this.spring.configLocations(this.xml("WithRememberMe")).autowire();
OpenIDAuthenticationFilter openIDFilter = getFilter(OpenIDAuthenticationFilter.class);
String openIdEndpointUrl = "https://testopenid.com?openid.return_to=";
Set<String> returnToUrlParameters = new HashSet<>();
returnToUrlParameters.add(AbstractRememberMeServices.DEFAULT_PARAMETER);
openIDFilter.setReturnToUrlParameters(returnToUrlParameters);
OpenIDConsumer consumer = mock(OpenIDConsumer.class);
given(consumer.beginConsumption(any(HttpServletRequest.class), anyString(), anyString(), anyString()))
.will((invocation) -> openIdEndpointUrl + invocation.getArgument(2));
openIDFilter.setConsumer(consumer);
String expectedReturnTo = new StringBuilder("http://localhost/login/openid").append("?")
.append(AbstractRememberMeServices.DEFAULT_PARAMETER).append("=").append("on").toString();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
this.mvc.perform(get("/login"))
.andExpect(status().isOk())
.andExpect(content().string(containsString(AbstractRememberMeServices.DEFAULT_PARAMETER)));
MockHttpServletRequestBuilder openidLogin = get("/login/openid")
.param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, "https://ww1.openid.com")
.param(AbstractRememberMeServices.DEFAULT_PARAMETER, "on");
this.mvc.perform(openidLogin)
.andExpect(status().isFound())
.andExpect(redirectedUrl(openIdEndpointUrl + expectedReturnTo));
// @formatter:on
}
@Test
public void requestWhenAttributeExchangeConfiguredThenFetchAttributesPassedToIdp() throws Exception {
this.spring.configLocations(this.xml("WithOpenIDAttributes")).autowire();
OpenIDAuthenticationFilter openIDFilter = getFilter(OpenIDAuthenticationFilter.class);
OpenID4JavaConsumer consumer = getFieldValue(openIDFilter, "consumer");
ConsumerManager manager = getFieldValue(consumer, "consumerManager");
manager.setMaxAssocAttempts(0);
try (MockWebServer server = new MockWebServer()) {
String endpoint = server.url("/").toString();
server.enqueue(new MockResponse().addHeader(YadisResolver.YADIS_XRDS_LOCATION, endpoint));
server.enqueue(new MockResponse()
.setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint)));
this.mvc.perform(
get("/login/openid").param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint))
.andExpect(status().isFound())
.andExpect((result) -> result.getResponse().getRedirectedUrl().endsWith(
"openid.ext1.type.nickname=http%3A%2F%2Fschema.openid.net%2FnamePerson%2Ffriendly&"
+ "openid.ext1.if_available=nickname&"
+ "openid.ext1.type.email=http%3A%2F%2Fschema.openid.net%2Fcontact%2Femail&"
+ "openid.ext1.required=email&" + "openid.ext1.count.email=2"));
}
}
/**
* SEC-2919
*/
@Test
public void requestWhenLoginPageConfiguredWithPhraseLoginThenRedirectsOnlyToUserGeneratedLoginPage()
throws Exception {
this.spring.configLocations(this.xml("Sec2919")).autowire();
assertThat(getFilter(DefaultLoginPageGeneratingFilter.class)).isNull();
// @formatter:off
this.mvc.perform(get("/login"))
.andExpect(status().isOk())
.andExpect(content().string("a custom login page"));
// @formatter:on
}
private <T extends Filter> T getFilter(Class<T> clazz) {
FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class);
return (T) filterChain.getFilters("/").stream().filter(clazz::isInstance).findFirst().orElse(null);
}
private String xml(String configName) {
return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
}
private static <T> T getFieldValue(Object bean, String fieldName) throws IllegalAccessException {
return (T) FieldUtils.getFieldValue(bean, fieldName);
}
@RestController
static class CustomLoginController {
@GetMapping("/login")
String custom() {
return "a custom login page";
}
}
}

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2018 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security
https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http auto-config="true">
<openid-login/>
<csrf disabled="true"/>
</http>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2018 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security
https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http auto-config="true">
<openid-login
login-processing-url="/signin"/>
<csrf disabled="true"/>
</http>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -28,7 +28,6 @@
<http-basic authentication-details-source-ref="authenticationDetailsSource"/>
<form-login authentication-details-source-ref="authenticationDetailsSource"/>
<x509 subject-principal-regex="OU=(.*?)(?:,|$)" authentication-details-source-ref="authenticationDetailsSource"/>
<openid-login authentication-details-source-ref="authenticationDetailsSource"/>
</http>
<b:bean name="authenticationDetailsSource" class="org.mockito.Mockito" factory-method="mock">

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2018 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<http use-expressions="true">
<intercept-url pattern="/login" access="permitAll"/>
<intercept-url pattern="/**" access="authenticated"/>
<openid-login login-page="/login"/>
</http>
<b:bean
name="customLogin"
class="org.springframework.security.config.http.OpenIDConfigTests.CustomLoginController"/>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2018 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<http use-expressions="true">
<intercept-url pattern="/**" access="authenticated"/>
<openid-login/>
<form-login/>
</http>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2018 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<http use-expressions="true">
<intercept-url pattern="/**" access="authenticated"/>
<openid-login login-page="/openid-page"/>
<form-login login-page="/form-page"/>
</http>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2018 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<http use-expressions="true">
<intercept-url pattern="/**" access="authenticated"/>
<openid-login/>
<form-login login-page="/form-page"/>
</http>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2018 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<http use-expressions="true">
<intercept-url pattern="/**" access="denyAll"/>
<openid-login>
<attribute-exchange>
<openid-attribute name="nickname" type="https://schema.openid.net/namePerson/friendly"/>
<openid-attribute name="email" type="https://schema.openid.net/contact/email" required="true" count="2"/>
</attribute-exchange>
</openid-login>
</http>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2018 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<http use-expressions="true">
<intercept-url pattern="/**" access="authenticated"/>
<openid-login login-page="/openid-page"/>
<form-login/>
</http>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2018 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<http use-expressions="true">
<intercept-url pattern="/**" access="denyAll"/>
<openid-login/>
<remember-me/>
<csrf disabled="true"/>
</http>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -29,7 +29,7 @@ package org.springframework.security.authentication;
* <p>
* This might be thrown if a backend authentication repository is unavailable, for
* example. However, it would not be thrown in the event that an error occurred when
* validating an OpenID response with an OpenID Provider.
* validating an OIDC response from an OIDC provider.
* </p>
*
* @author Rob Winch

View File

@ -58,7 +58,6 @@ dependencies {
api "org.mockito:mockito-core:3.12.4"
api "org.mockito:mockito-inline:3.12.4"
api "org.mockito:mockito-junit-jupiter:3.12.4"
api "org.openid4java:openid4java-nodeps:0.9.6"
api "org.opensaml:opensaml-core:$openSamlVersion"
api "org.opensaml:opensaml-saml-api:$openSamlVersion"
api "org.opensaml:opensaml-saml-impl:$openSamlVersion"

View File

@ -38,7 +38,6 @@
***** xref:servlet/authentication/passwords/ldap.adoc[LDAP]
*** xref:servlet/authentication/session-management.adoc[Session Management]
*** xref:servlet/authentication/rememberme.adoc[Remember Me]
*** xref:servlet/authentication/openid.adoc[OpenID]
*** xref:servlet/authentication/anonymous.adoc[Anonymous]
*** xref:servlet/authentication/preauth.adoc[Pre-Authentication]
*** xref:servlet/authentication/jaas.adoc[JAAS]

View File

@ -71,7 +71,7 @@ You can do so by adding a Maven property:
----
====
If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate xref:modules.adoc#modules[Project Modules and Dependencies].
If you use additional features (such as LDAP, OAuth 2, and others), you need to also include the appropriate xref:modules.adoc#modules[Project Modules and Dependencies].
[[getting-maven-no-boot]]
=== Maven Without Spring Boot
@ -117,7 +117,7 @@ A minimal Spring Security Maven set of dependencies typically looks like the fol
----
====
If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate xref:modules.adoc#modules[Project Modules and Dependencies].
If you use additional features (such as LDAP, OAuth 2, and others), you need to also include the appropriate xref:modules.adoc#modules[Project Modules and Dependencies].
Spring Security builds against Spring Framework {spring-core-version} but should generally work with any newer version of Spring Framework 5.x.
Many users are likely to run afoul of the fact that Spring Security's transitive dependencies resolve Spring Framework {spring-core-version}, which can cause strange classpath problems.
@ -238,7 +238,7 @@ ext['spring.version']='{spring-core-version}'
----
====
If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate xref:modules.adoc#modules[Project Modules and Dependencies].
If you use additional features (such as LDAP, OAuth 2, and others), you need to also include the appropriate xref:modules.adoc#modules[Project Modules and Dependencies].
=== Gradle Without Spring Boot
@ -276,7 +276,7 @@ dependencies {
----
====
If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate xref:modules.adoc#modules[Project Modules and Dependencies].
If you use additional features (such as LDAP, OAuth 2, and others), you need to also include the appropriate xref:modules.adoc#modules[Project Modules and Dependencies].
Spring Security builds against Spring Framework {spring-core-version} but should generally work with any newer version of Spring Framework 5.x.
Many users are likely to run afoul of the fact that Spring Security's transitive dependencies resolve Spring Framework {spring-core-version}, which can cause strange classpath problems.

View File

@ -139,10 +139,6 @@ None of the classes are intended for direct use in an application.
|
| Required if you are using the LDAP namespace options (optional).
| spring-security-openid
|
| Required if you are using OpenID authentication (optional).
| aspectjweaver
| 1.6.10
| Required if using the protect-pointcut namespace syntax (optional).
@ -275,44 +271,6 @@ This is the basis of the Spring Security integration.
| Required if you are using the Ehcache-based ticket cache (optional).
|===
[[spring-security-openid]]
== OpenID -- `spring-security-openid.jar`
[NOTE]
====
The OpenID 1.0 and 2.0 protocols have been deprecated and users are encouraged to migrate to OpenID Connect, which is supported by spring-security-oauth2.
====
This module contains OpenID web authentication support.
It is used to authenticate users against an external OpenID server.
The top-level package is `org.springframework.security.openid`.
It requires OpenID4Java.
.OpenID Dependencies
|===
| Dependency | Version | Description
| spring-security-core
|
|
| spring-security-web
|
|
| openid4java-nodeps
| 0.9.6
| Spring Security's OpenID integration uses OpenID4Java.
| httpclient
| 4.1.1
| openid4java-nodeps depends on HttpClient 4.
| guice
| 2.0
| openid4java-nodeps depends on Guice 2.
|===
[[spring-security-test]]
== Test -- `spring-security-test.jar`

View File

@ -159,7 +159,6 @@ The default value is true.
* <<nsa-oauth2-client,oauth2-client>>
* <<nsa-oauth2-login,oauth2-login>>
* <<nsa-oauth2-resource-server,oauth2-resource-server>>
* <<nsa-openid-login,openid-login>>
* <<nsa-password-management,password-management>>
* <<nsa-port-mappings,port-mappings>>
* <<nsa-remember-me,remember-me>>
@ -838,7 +837,7 @@ Used to add an `UsernamePasswordAuthenticationFilter` to the filter stack and an
This will always take precedence over other namespace-created entry points.
If no attributes are supplied, a login page will be generated automatically at the URL "/login" footnote:[
This feature is really just provided for convenience and is not intended for production (where a view technology will have been chosen and can be used to render a customized login page).
The class `DefaultLoginPageGeneratingFilter` is responsible for rendering the login page and will provide login forms for both normal form login and/or OpenID if required.
The class `DefaultLoginPageGeneratingFilter` is responsible for rendering the login page and will provide login forms for both normal form login and/or OIDC if required.
] The behaviour can be customized using the <<nsa-form-login-attributes, `<form-login>` Attributes>>.
@ -1476,182 +1475,6 @@ Defaults to "/logout".
May be used to supply an instance of `LogoutSuccessHandler` which will be invoked to control the navigation after logging out.
[[nsa-openid-login]]
== <openid-login>
Similar to `<form-login>` and has the same attributes.
The default value for `login-processing-url` is "/login/openid".
An `OpenIDAuthenticationFilter` and `OpenIDAuthenticationProvider` will be registered.
The latter requires a reference to a `UserDetailsService`.
Again, this can be specified by `id`, using the `user-service-ref` attribute, or will be located automatically in the application context.
[[nsa-openid-login-parents]]
=== Parent Elements of <openid-login>
* <<nsa-http,http>>
[[nsa-openid-login-attributes]]
=== <openid-login> Attributes
[[nsa-openid-login-always-use-default-target]]
* **always-use-default-target**
Whether the user should always be redirected to the default-target-url after login.
[[nsa-openid-login-authentication-details-source-ref]]
* **authentication-details-source-ref**
Reference to an AuthenticationDetailsSource which will be used by the authentication filter
[[nsa-openid-login-authentication-failure-handler-ref]]
* **authentication-failure-handler-ref**
Reference to an AuthenticationFailureHandler bean which should be used to handle a failed authentication request.
Should not be used in combination with authentication-failure-url as the implementation should always deal with navigation to the subsequent destination
[[nsa-openid-login-authentication-failure-url]]
* **authentication-failure-url**
The URL for the login failure page.
If no login failure URL is specified, Spring Security will automatically create a failure login URL at /login?login_error and a corresponding filter to render that login failure URL when requested.
[[nsa-openid-login-authentication-success-forward-url]]
* **authentication-success-forward-url**
Maps a `ForwardAuthenticationSuccessHandler` to `authenticationSuccessHandler` property of `UsernamePasswordAuthenticationFilter`.
[[nsa-openid-login-authentication-failure-forward-url]]
* **authentication-failure-forward-url**
Maps a `ForwardAuthenticationFailureHandler` to `authenticationFailureHandler` property of `UsernamePasswordAuthenticationFilter`.
[[nsa-openid-login-authentication-success-handler-ref]]
* **authentication-success-handler-ref**
Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful authentication request.
Should not be used in combination with <<nsa-openid-login-default-target-url,default-target-url>> (or <<nsa-openid-login-always-use-default-target, always-use-default-target>>) as the implementation should always deal with navigation to the subsequent destination
[[nsa-openid-login-default-target-url]]
* **default-target-url**
The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed.
This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication.
If unspecified, defaults to the root of the application.
[[nsa-openid-login-login-page]]
* **login-page**
The URL for the login page.
If no login URL is specified, Spring Security will automatically create a login URL at /login and a corresponding filter to render that login URL when requested.
[[nsa-openid-login-login-processing-url]]
* **login-processing-url**
The URL that the login form is posted to.
If unspecified, it defaults to /login.
[[nsa-openid-login-password-parameter]]
* **password-parameter**
The name of the request parameter which contains the password.
Defaults to "password".
[[nsa-openid-login-user-service-ref]]
* **user-service-ref**
A reference to a user-service (or UserDetailsService bean) Id
[[nsa-openid-login-username-parameter]]
* **username-parameter**
The name of the request parameter which contains the username.
Defaults to "username".
[[nsa-openid-login-children]]
=== Child Elements of <openid-login>
* <<nsa-attribute-exchange,attribute-exchange>>
[[nsa-attribute-exchange]]
== <attribute-exchange>
The `attribute-exchange` element defines the list of attributes which should be requested from the identity provider.
An example can be found in the xref:servlet/authentication/openid.adoc#servlet-openid[OpenID Support] section of the namespace configuration chapter.
More than one can be used, in which case each must have an `identifier-match` attribute, containing a regular expression which is matched against the supplied OpenID identifier.
This allows different attribute lists to be fetched from different providers (Google, Yahoo etc).
[[nsa-attribute-exchange-parents]]
=== Parent Elements of <attribute-exchange>
* <<nsa-openid-login,openid-login>>
[[nsa-attribute-exchange-attributes]]
=== <attribute-exchange> Attributes
[[nsa-attribute-exchange-identifier-match]]
* **identifier-match**
A regular expression which will be compared against the claimed identity, when deciding which attribute-exchange configuration to use during authentication.
[[nsa-attribute-exchange-children]]
=== Child Elements of <attribute-exchange>
* <<nsa-openid-attribute,openid-attribute>>
[[nsa-openid-attribute]]
== <openid-attribute>
Attributes used when making an OpenID AX https://openid.net/specs/openid-attribute-exchange-1_0.html#fetch_request[ Fetch Request]
[[nsa-openid-attribute-parents]]
=== Parent Elements of <openid-attribute>
* <<nsa-attribute-exchange,attribute-exchange>>
[[nsa-openid-attribute-attributes]]
=== <openid-attribute> Attributes
[[nsa-openid-attribute-count]]
* **count**
Specifies the number of attributes that you wish to get back.
For example, return 3 emails.
The default value is 1.
[[nsa-openid-attribute-name]]
* **name**
Specifies the name of the attribute that you wish to get back.
For example, email.
[[nsa-openid-attribute-required]]
* **required**
Specifies if this attribute is required to the OP, but does not error out if the OP does not return the attribute.
Default is false.
[[nsa-openid-attribute-type]]
* **type**
Specifies the attribute type.
For example, https://axschema.org/contact/email.
See your OP's documentation for valid attribute types.
[[nsa-password-management]]
== <password-management>
This element configures password management.

View File

@ -182,7 +182,6 @@ The following is a comprehensive list of Spring Security Filter ordering:
* `OAuth2LoginAuthenticationFilter`
* `Saml2WebSsoAuthenticationFilter`
* xref:servlet/authentication/passwords/form.adoc#servlet-authentication-usernamepasswordauthenticationfilter[`UsernamePasswordAuthenticationFilter`]
* `OpenIDAuthenticationFilter`
* `DefaultLoginPageGeneratingFilter`
* `DefaultLogoutPageGeneratingFilter`
* `ConcurrentSessionFilter`

View File

@ -18,6 +18,5 @@ These sections focus on specific ways you may want to authenticate and point bac
* xref:servlet/saml2/index.adoc#servlet-saml2[SAML 2.0 Login] - SAML 2.0 Log In
* xref:servlet/authentication/rememberme.adoc#servlet-rememberme[Remember Me] - how to remember a user past session expiration
* xref:servlet/authentication/jaas.adoc#servlet-jaas[JAAS Authentication] - authenticate with JAAS
* xref:servlet/authentication/openid.adoc#servlet-openid[OpenID] - OpenID Authentication (not to be confused with OpenID Connect)
* xref:servlet/authentication/preauth.adoc#servlet-preauth[Pre-Authentication Scenarios] - authenticate with an external mechanism such as https://www.siteminder.com/[SiteMinder] or Java EE security but still use Spring Security for authorization and protection against common exploits.
* xref:servlet/authentication/x509.adoc#servlet-x509[X509 Authentication] - X509 Authentication

View File

@ -1,70 +0,0 @@
[[servlet-openid]]
= OpenID Support
[NOTE]
====
The OpenID 1.0 and 2.0 protocols have been deprecated. You should migrate to OpenID Connect, which is supported by `spring-security-oauth2`.
====
The namespace supports https://openid.net/[OpenID] login either instead of or in addition to normal form-based login, with a simple change:
====
[source,xml]
----
<http>
<intercept-url pattern="/**" access="ROLE_USER" />
<openid-login />
</http>
----
====
You should then register yourself with an OpenID provider (such as myopenid.com), and add the user information to your in-memory `<user-service>`:
====
[source,xml]
----
<user name="https://jimi.hendrix.myopenid.com/" authorities="ROLE_USER" />
----
====
You should be able to login by using the `myopenid.com` site to authenticate.
You can also select a specific `UserDetailsService` bean for use with OpenID by setting the `user-service-ref` attribute on the `openid-login` element.
Note that we have omitted the password attribute from the above user configuration, since this set of user data is being used only to load the authorities for the user.
A random password is generated internally, preventing you from accidentally using this user data as an authentication source elsewhere in your configuration.
== Attribute Exchange
Spring Security includes support for OpenID https://openid.net/specs/openid-attribute-exchange-1_0.html[attribute exchange].
As an example, the following configuration tries to retrieve the email and full name from the OpenID provider for use by the application:
====
[source,xml]
----
<openid-login>
<attribute-exchange>
<openid-attribute name="email" type="https://axschema.org/contact/email" required="true"/>
<openid-attribute name="name" type="https://axschema.org/namePerson"/>
</attribute-exchange>
</openid-login>
----
====
The "`type`" of each OpenID attribute is a URI, determined by a particular schema -- in this case, https://axschema.org/[https://axschema.org/].
If an attribute must be retrieved for successful authentication, you can set the `required` attribute.
The exact schema and attributes supported depend on your OpenID provider.
The attribute values are returned as part of the authentication process and can be accessed afterwards by using the following code:
====
[source,java]
----
OpenIDAuthenticationToken token =
(OpenIDAuthenticationToken)SecurityContextHolder.getContext().getAuthentication();
List<OpenIDAttribute> attributes = token.getAttributes();
----
====
We can obtain the `OpenIDAuthenticationToken` from the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontextholder[SecurityContextHolder].
The `OpenIDAttribute` contains the attribute type and the retrieved value (or values in the case of multi-valued attributes).
You can supply multiple `attribute-exchange` elements by using an `identifier-matcher` attribute on each element.
This contains a regular expression that is matched against the OpenID identifier supplied by the user.
See the OpenID sample application in the codebase for an example configuration, providing different attribute lists for the Google, Yahoo and MyOpenID providers.

View File

@ -29,7 +29,6 @@
<classpathentry kind="lib" path="oauth2/oauth2-core/build/classes/java/main" module="spring-security-oauth2-core" />
<classpathentry kind="lib" path="oauth2/oauth2-jose/build/classes/java/main" module="spring-security-oauth2-jose" />
<classpathentry kind="lib" path="oauth2/oauth2-resource-server/build/classes/java/main" module="spring-security-oauth2-resource-server" />
<classpathentry kind="lib" path="openid/build/classes/java/main" module="spring-security-openid" />
<classpathentry kind="lib" path="remoting/build/classes/java/main" module="spring-security-remoting" />
<classpathentry kind="lib" path="rsocket/build/classes/java/main" module="spring-security-rsocket" />
<classpathentry kind="lib" path="saml2/saml2-service-provider/build/classes/java/main" module="spring-security-saml2-service-provider" />

View File

@ -1,43 +0,0 @@
// NOTE: The OpenID 1.0 and 2.0 protocols have been deprecated and users are
// <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to migrate</a>
// to <a href="https://openid.net/connect/">OpenID Connect</a>, which is supported by <code>spring-security-oauth2</code>.
apply plugin: 'io.spring.convention.spring-module'
dependencies {
management platform(project(":spring-security-dependencies"))
api project(':spring-security-core')
api project(':spring-security-web')
api('com.google.inject:guice') {
exclude group: 'aopalliance', module: 'aopalliance'
exclude group: 'javax.inject', module: 'javax.inject'
}
// openid4java has a compile time dep on guice with a group
// name which is different from the maven central one.
// We use the maven central version here instead.
api('org.openid4java:openid4java-nodeps') {
exclude group: 'com.google.code.guice', module: 'guice'
exclude group: 'commons-logging', module: 'commons-logging'
}
api 'org.springframework:spring-aop'
api 'org.springframework:spring-beans'
api 'org.springframework:spring-context'
api 'org.springframework:spring-core'
api 'org.springframework:spring-web'
provided 'jakarta.servlet:jakarta.servlet-api'
runtimeOnly 'net.sourceforge.nekohtml:nekohtml'
runtimeOnly('org.apache.httpcomponents:httpclient') {
exclude group: 'commons-logging', module: 'commons-logging'
}
testImplementation "jakarta.inject:jakarta.inject-api"
testImplementation "org.assertj:assertj-core"
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"
testImplementation "org.junit.jupiter:junit-jupiter-engine"
testImplementation "org.mockito:mockito-core"
testImplementation "org.mockito:mockito-junit-jupiter"
testImplementation "org.springframework:spring-test"
}

View File

@ -1,41 +0,0 @@
/*
* 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.openid;
import org.springframework.security.core.AuthenticationException;
/**
* Indicates that OpenID authentication was cancelled
*
* @author Robin Bramley, Opsera Ltd
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class AuthenticationCancelledException extends AuthenticationException {
public AuthenticationCancelledException(String msg) {
super(msg);
}
public AuthenticationCancelledException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -1,46 +0,0 @@
/*
* 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.openid;
import java.util.List;
/**
* A strategy which can be used by an OpenID consumer implementation, to dynamically
* determine the attribute exchange information based on the OpenID identifier.
* <p>
* This allows the list of attributes for a fetch request to be tailored for different
* OpenID providers, since they do not all support the same attributes.
*
* @author Luke Taylor
* @since 3.1
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public interface AxFetchListFactory {
/**
* Builds the list of attributes which should be added to the fetch request for the
* supplied OpenID identifier.
* @param identifier the claimed_identity
* @return the attributes to fetch for this identifier
*/
List<OpenIDAttribute> createAttributeList(String identifier);
}

View File

@ -1,38 +0,0 @@
/*
* 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.openid;
import java.util.Collections;
import java.util.List;
/**
* @author Luke Taylor
* @since 3.1
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class NullAxFetchListFactory implements AxFetchListFactory {
@Override
public List<OpenIDAttribute> createAttributeList(String identifier) {
return Collections.emptyList();
}
}

View File

@ -1,197 +0,0 @@
/*
* 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.openid;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openid4java.association.AssociationException;
import org.openid4java.consumer.ConsumerException;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.consumer.VerificationResult;
import org.openid4java.discovery.DiscoveryException;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.Identifier;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.Message;
import org.openid4java.message.MessageException;
import org.openid4java.message.MessageExtension;
import org.openid4java.message.ParameterList;
import org.openid4java.message.ax.AxMessage;
import org.openid4java.message.ax.FetchRequest;
import org.openid4java.message.ax.FetchResponse;
import org.springframework.util.StringUtils;
/**
* @author Ray Krueger
* @author Luke Taylor
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
@SuppressWarnings("unchecked")
public class OpenID4JavaConsumer implements OpenIDConsumer {
private static final String DISCOVERY_INFO_KEY = DiscoveryInformation.class.getName();
private static final String ATTRIBUTE_LIST_KEY = "SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST";
protected final Log logger = LogFactory.getLog(getClass());
private final ConsumerManager consumerManager;
private final AxFetchListFactory attributesToFetchFactory;
public OpenID4JavaConsumer() throws ConsumerException {
this(new ConsumerManager(), new NullAxFetchListFactory());
}
public OpenID4JavaConsumer(AxFetchListFactory attributesToFetchFactory) throws ConsumerException {
this(new ConsumerManager(), attributesToFetchFactory);
}
public OpenID4JavaConsumer(ConsumerManager consumerManager, AxFetchListFactory attributesToFetchFactory) {
this.consumerManager = consumerManager;
this.attributesToFetchFactory = attributesToFetchFactory;
}
@Override
public String beginConsumption(HttpServletRequest req, String identityUrl, String returnToUrl, String realm)
throws OpenIDConsumerException {
List<DiscoveryInformation> discoveries = getDiscoveries(identityUrl);
DiscoveryInformation information = this.consumerManager.associate(discoveries);
req.getSession().setAttribute(DISCOVERY_INFO_KEY, information);
AuthRequest authReq = getAuthRequest(req, identityUrl, returnToUrl, realm, information);
return authReq.getDestinationUrl(true);
}
private List<DiscoveryInformation> getDiscoveries(String identityUrl) throws OpenIDConsumerException {
try {
return this.consumerManager.discover(identityUrl);
}
catch (DiscoveryException ex) {
throw new OpenIDConsumerException("Error during discovery", ex);
}
}
private AuthRequest getAuthRequest(HttpServletRequest req, String identityUrl, String returnToUrl, String realm,
DiscoveryInformation information) throws OpenIDConsumerException {
try {
AuthRequest authReq = this.consumerManager.authenticate(information, returnToUrl, realm);
this.logger.debug("Looking up attribute fetch list for identifier: " + identityUrl);
List<OpenIDAttribute> attributesToFetch = this.attributesToFetchFactory.createAttributeList(identityUrl);
if (!attributesToFetch.isEmpty()) {
req.getSession().setAttribute(ATTRIBUTE_LIST_KEY, attributesToFetch);
FetchRequest fetchRequest = FetchRequest.createFetchRequest();
for (OpenIDAttribute attr : attributesToFetch) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Adding attribute " + attr.getType() + " to fetch request");
}
fetchRequest.addAttribute(attr.getName(), attr.getType(), attr.isRequired(), attr.getCount());
}
authReq.addExtension(fetchRequest);
}
return authReq;
}
catch (MessageException | ConsumerException ex) {
throw new OpenIDConsumerException("Error processing ConsumerManager authentication", ex);
}
}
@Override
public OpenIDAuthenticationToken endConsumption(HttpServletRequest request) throws OpenIDConsumerException {
// extract the parameters from the authentication response
// (which comes in as a HTTP request from the OpenID provider)
ParameterList openidResp = new ParameterList(request.getParameterMap());
// retrieve the previously stored discovery information
DiscoveryInformation discovered = (DiscoveryInformation) request.getSession().getAttribute(DISCOVERY_INFO_KEY);
if (discovered == null) {
throw new OpenIDConsumerException(
"DiscoveryInformation is not available. Possible causes are lost session or replay attack");
}
List<OpenIDAttribute> attributesToFetch = (List<OpenIDAttribute>) request.getSession()
.getAttribute(ATTRIBUTE_LIST_KEY);
request.getSession().removeAttribute(DISCOVERY_INFO_KEY);
request.getSession().removeAttribute(ATTRIBUTE_LIST_KEY);
// extract the receiving URL from the HTTP request
StringBuffer receivingURL = request.getRequestURL();
String queryString = request.getQueryString();
if (StringUtils.hasLength(queryString)) {
receivingURL.append("?").append(request.getQueryString());
}
// verify the response
VerificationResult verification;
try {
verification = this.consumerManager.verify(receivingURL.toString(), openidResp, discovered);
}
catch (MessageException | AssociationException | DiscoveryException ex) {
throw new OpenIDConsumerException("Error verifying openid response", ex);
}
// examine the verification result and extract the verified identifier
Identifier verified = verification.getVerifiedId();
if (verified == null) {
Identifier id = discovered.getClaimedIdentifier();
return new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.FAILURE,
(id != null) ? id.getIdentifier() : "Unknown",
"Verification status message: [" + verification.getStatusMsg() + "]",
Collections.<OpenIDAttribute>emptyList());
}
List<OpenIDAttribute> attributes = fetchAxAttributes(verification.getAuthResponse(), attributesToFetch);
return new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS, verified.getIdentifier(),
"some message", attributes);
}
List<OpenIDAttribute> fetchAxAttributes(Message authSuccess, List<OpenIDAttribute> attributesToFetch)
throws OpenIDConsumerException {
if (attributesToFetch == null || !authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
return Collections.emptyList();
}
this.logger.debug("Extracting attributes retrieved by attribute exchange");
List<OpenIDAttribute> attributes = Collections.emptyList();
try {
MessageExtension ext = authSuccess.getExtension(AxMessage.OPENID_NS_AX);
if (ext instanceof FetchResponse) {
FetchResponse fetchResp = (FetchResponse) ext;
attributes = new ArrayList<>(attributesToFetch.size());
for (OpenIDAttribute attr : attributesToFetch) {
List<String> values = fetchResp.getAttributeValues(attr.getName());
if (!values.isEmpty()) {
OpenIDAttribute fetched = new OpenIDAttribute(attr.getName(), attr.getType(), values);
fetched.setRequired(attr.isRequired());
attributes.add(fetched);
}
}
}
}
catch (MessageException ex) {
throw new OpenIDConsumerException("Attribute retrieval failed", ex);
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Retrieved attributes" + attributes);
}
return attributes;
}
}

View File

@ -1,122 +0,0 @@
/*
* 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.openid;
import java.io.Serializable;
import java.util.List;
import org.springframework.util.Assert;
/**
* Represents an OpenID subject identity attribute.
* <p>
* Can be used for configuring the <tt>OpenID4JavaConsumer</tt> with the attributes which
* should be requested during a fetch request, or to hold values for an attribute which
* are returned during the authentication process.
*
* @author Luke Taylor
* @since 3.0
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class OpenIDAttribute implements Serializable {
private final String name;
private final String typeIdentifier;
private boolean required = false;
private int count = 1;
private final List<String> values;
public OpenIDAttribute(String name, String type) {
this.name = name;
this.typeIdentifier = type;
this.values = null;
}
public OpenIDAttribute(String name, String type, List<String> values) {
Assert.notEmpty(values, "values cannot be empty");
this.name = name;
this.typeIdentifier = type;
this.values = values;
}
/**
* The attribute name
*/
public String getName() {
return this.name;
}
/**
* The attribute type Identifier (a URI).
*/
public String getType() {
return this.typeIdentifier;
}
/**
* The "required" flag for the attribute when used with an authentication request.
* Defaults to "false".
*/
public boolean isRequired() {
return this.required;
}
public void setRequired(boolean required) {
this.required = required;
}
/**
* The requested count for the attribute when it is used as part of an authentication
* request. Defaults to 1.
*/
public int getCount() {
return this.count;
}
public void setCount(int count) {
this.count = count;
}
/**
* The values obtained from an attribute exchange.
*/
public List<String> getValues() {
Assert.notNull(this.values, "Cannot read values from an authentication request attribute");
return this.values;
}
@Override
public String toString() {
StringBuilder result = new StringBuilder("[");
result.append(this.name);
if (this.values != null) {
result.append(":");
result.append(this.values.toString());
}
result.append("]");
return result.toString();
}
}

View File

@ -1,283 +0,0 @@
/*
* 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.openid;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.openid4java.consumer.ConsumerException;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Filter which processes OpenID authentication requests.
* <p>
* The OpenID authentication involves two stages.
*
* <h2>Submission of OpenID identity</h2>
*
* The user's OpenID identity is submitted via a login form, just as it would be for a
* normal form login. At this stage the filter will extract the identity from the
* submitted request (by default, the parameter is called <tt>openid_identifier</tt>, as
* recommended by the OpenID 2.0 Specification). It then passes the identity to the
* configured <tt>OpenIDConsumer</tt>, which returns the URL to which the request should
* be redirected for authentication. A "return_to" URL is also supplied, which matches the
* URL processed by this filter, to allow the filter to handle the request once the user
* has been successfully authenticated. The OpenID server will then authenticate the user
* and redirect back to the application.
*
* <h2>Processing the Redirect from the OpenID Server</h2>
*
* Once the user has been authenticated externally, the redirected request will be passed
* to the <tt>OpenIDConsumer</tt> again for validation. The returned
* <tt>OpenIDAuthentication</tt> will be passed to the <tt>AuthenticationManager</tt>
* where it should (normally) be processed by an <tt>OpenIDAuthenticationProvider</tt> in
* order to load the authorities for the user.
*
* @author Robin Bramley
* @author Ray Krueger
* @author Luke Taylor
* @since 2.0
* @see OpenIDAuthenticationProvider
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class OpenIDAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public static final String DEFAULT_CLAIMED_IDENTITY_FIELD = "openid_identifier";
private OpenIDConsumer consumer;
private String claimedIdentityFieldName = DEFAULT_CLAIMED_IDENTITY_FIELD;
private Map<String, String> realmMapping = Collections.emptyMap();
private Set<String> returnToUrlParameters = Collections.emptySet();
public OpenIDAuthenticationFilter() {
super("/login/openid");
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
if (this.consumer == null) {
try {
this.consumer = new OpenID4JavaConsumer();
}
catch (ConsumerException ex) {
throw new IllegalArgumentException("Failed to initialize OpenID", ex);
}
}
if (this.returnToUrlParameters.isEmpty() && getRememberMeServices() instanceof AbstractRememberMeServices) {
this.returnToUrlParameters = new HashSet<>();
this.returnToUrlParameters.add(((AbstractRememberMeServices) getRememberMeServices()).getParameter());
}
}
/**
* Authentication has two phases.
* <ol>
* <li>The initial submission of the claimed OpenID. A redirect to the URL returned
* from the consumer will be performed and null will be returned.</li>
* <li>The redirection from the OpenID server to the return_to URL, once it has
* authenticated the user</li>
* </ol>
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException {
OpenIDAuthenticationToken token;
String identity = request.getParameter("openid.identity");
if (!StringUtils.hasText(identity)) {
String claimedIdentity = obtainUsername(request);
try {
String returnToUrl = buildReturnToUrl(request);
String realm = lookupRealm(returnToUrl);
String openIdUrl = this.consumer.beginConsumption(request, claimedIdentity, returnToUrl, realm);
if (this.logger.isDebugEnabled()) {
this.logger.debug("return_to is '" + returnToUrl + "', realm is '" + realm + "'");
this.logger.debug("Redirecting to " + openIdUrl);
}
response.sendRedirect(openIdUrl);
// Indicate to parent class that authentication is continuing.
return null;
}
catch (OpenIDConsumerException ex) {
this.logger.debug("Failed to consume claimedIdentity: " + claimedIdentity, ex);
throw new AuthenticationServiceException(
"Unable to process claimed identity '" + claimedIdentity + "'");
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Supplied OpenID identity is " + identity);
}
try {
token = this.consumer.endConsumption(request);
}
catch (OpenIDConsumerException ex) {
throw new AuthenticationServiceException("Consumer error", ex);
}
token.setDetails(this.authenticationDetailsSource.buildDetails(request));
// delegate to the authentication provider
Authentication authentication = this.getAuthenticationManager().authenticate(token);
return authentication;
}
protected String lookupRealm(String returnToUrl) {
String mapping = this.realmMapping.get(returnToUrl);
if (mapping == null) {
try {
URL url = new URL(returnToUrl);
int port = url.getPort();
StringBuilder realmBuffer = new StringBuilder(returnToUrl.length()).append(url.getProtocol())
.append("://").append(url.getHost());
if (port > 0) {
realmBuffer.append(":").append(port);
}
realmBuffer.append("/");
mapping = realmBuffer.toString();
}
catch (MalformedURLException ex) {
this.logger.warn("returnToUrl was not a valid URL: [" + returnToUrl + "]", ex);
}
}
return mapping;
}
/**
* Builds the <tt>return_to</tt> URL that will be sent to the OpenID service provider.
* By default returns the URL of the current request.
* @param request the current request which is being processed by this filter
* @return The <tt>return_to</tt> URL.
*/
protected String buildReturnToUrl(HttpServletRequest request) {
StringBuffer sb = request.getRequestURL();
Iterator<String> iterator = this.returnToUrlParameters.iterator();
boolean isFirst = true;
while (iterator.hasNext()) {
String name = iterator.next();
// Assume for simplicity that there is only one value
String value = request.getParameter(name);
if (value == null) {
continue;
}
if (isFirst) {
sb.append("?");
isFirst = false;
}
sb.append(utf8UrlEncode(name)).append("=").append(utf8UrlEncode(value));
if (iterator.hasNext()) {
sb.append("&");
}
}
return sb.toString();
}
/**
* Reads the <tt>claimedIdentityFieldName</tt> from the submitted request.
*/
protected String obtainUsername(HttpServletRequest req) {
String claimedIdentity = req.getParameter(this.claimedIdentityFieldName);
if (!StringUtils.hasText(claimedIdentity)) {
this.logger.error("No claimed identity supplied in authentication request");
return "";
}
return claimedIdentity.trim();
}
/**
* Maps the <tt>return_to url</tt> to a realm, for example:
*
* <pre>
* https://www.example.com/login/openid -&gt; https://www.example.com/realm
* </pre>
*
* If no mapping is provided then the returnToUrl will be parsed to extract the
* protocol, hostname and port followed by a trailing slash. This means that
* <tt>https://foo.example.com/login/openid</tt> will automatically become
* <tt>http://foo.example.com:80/</tt>
* @param realmMapping containing returnToUrl -&gt; realm mappings
*/
public void setRealmMapping(Map<String, String> realmMapping) {
this.realmMapping = realmMapping;
}
/**
* The name of the request parameter containing the OpenID identity, as submitted from
* the initial login form.
* @param claimedIdentityFieldName defaults to "openid_identifier"
*/
public void setClaimedIdentityFieldName(String claimedIdentityFieldName) {
this.claimedIdentityFieldName = claimedIdentityFieldName;
}
public void setConsumer(OpenIDConsumer consumer) {
this.consumer = consumer;
}
/**
* Specifies any extra parameters submitted along with the identity field which should
* be appended to the {@code return_to} URL which is assembled by
* {@link #buildReturnToUrl}.
* @param returnToUrlParameters the set of parameter names. If not set, it will
* default to the parameter name used by the {@code RememberMeServices} obtained from
* the parent class (if one is set).
*/
public void setReturnToUrlParameters(Set<String> returnToUrlParameters) {
Assert.notNull(returnToUrlParameters, "returnToUrlParameters cannot be null");
this.returnToUrlParameters = returnToUrlParameters;
}
/**
* Performs URL encoding with UTF-8
* @param value the value to URL encode
* @return the encoded value
*/
private String utf8UrlEncode(String value) {
try {
return URLEncoder.encode(value, "UTF-8");
}
catch (UnsupportedEncodingException ex) {
Error err = new AssertionError(
"The Java platform guarantees UTF-8 support, but it seemingly is not present.");
err.initCause(ex);
throw err;
}
}
}

View File

@ -1,139 +0,0 @@
/*
* 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.openid;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.util.Assert;
/**
* Finalises the OpenID authentication by obtaining local authorities for the
* authenticated user.
* <p>
* The authorities are obtained by calling the configured {@code UserDetailsService}. The
* {@code UserDetails} it returns must, at minimum, contain the username and
* {@code GrantedAuthority} objects applicable to the authenticated user. Note that by
* default, Spring Security ignores the password and enabled/disabled status of the
* {@code UserDetails} because this is authentication-related and should have been
* enforced by another provider server.
* <p>
* The {@code UserDetails} returned by implementations is stored in the generated
* {@code Authentication} token, so additional properties such as email addresses,
* telephone numbers etc can easily be stored.
*
* @author Robin Bramley, Opsera Ltd.
* @author Luke Taylor
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class OpenIDAuthenticationProvider implements AuthenticationProvider, InitializingBean {
private AuthenticationUserDetailsService<OpenIDAuthenticationToken> userDetailsService;
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
@Override
public void afterPropertiesSet() {
Assert.notNull(this.userDetailsService, "The userDetailsService must be set");
}
@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
if (!supports(authentication.getClass())) {
return null;
}
if (!(authentication instanceof OpenIDAuthenticationToken)) {
return null;
}
OpenIDAuthenticationToken response = (OpenIDAuthenticationToken) authentication;
OpenIDAuthenticationStatus status = response.getStatus();
// handle the various possibilities
if (status == OpenIDAuthenticationStatus.SUCCESS) {
// Lookup user details
UserDetails userDetails = this.userDetailsService.loadUserDetails(response);
return createSuccessfulAuthentication(userDetails, response);
}
if (status == OpenIDAuthenticationStatus.CANCELLED) {
throw new AuthenticationCancelledException("Log in cancelled");
}
if (status == OpenIDAuthenticationStatus.ERROR) {
throw new AuthenticationServiceException("Error message from server: " + response.getMessage());
}
if (status == OpenIDAuthenticationStatus.FAILURE) {
throw new BadCredentialsException("Log in failed - identity could not be verified");
}
if (status == OpenIDAuthenticationStatus.SETUP_NEEDED) {
throw new AuthenticationServiceException("The server responded setup was needed, which shouldn't happen");
}
throw new AuthenticationServiceException("Unrecognized return value " + status.toString());
}
/**
* Handles the creation of the final <tt>Authentication</tt> object which will be
* returned by the provider.
* <p>
* The default implementation just creates a new OpenIDAuthenticationToken from the
* original, but with the UserDetails as the principal and including the authorities
* loaded by the UserDetailsService.
* @param userDetails the loaded UserDetails object
* @param auth the token passed to the authenticate method, containing
* @return the token which will represent the authenticated user.
*/
protected Authentication createSuccessfulAuthentication(UserDetails userDetails, OpenIDAuthenticationToken auth) {
return new OpenIDAuthenticationToken(userDetails,
this.authoritiesMapper.mapAuthorities(userDetails.getAuthorities()), auth.getIdentityUrl(),
auth.getAttributes());
}
/**
* Used to load the {@code UserDetails} for the authenticated OpenID user.
*/
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = new UserDetailsByNameServiceWrapper<>(userDetailsService);
}
/**
* Used to load the {@code UserDetails} for the authenticated OpenID user.
*/
public void setAuthenticationUserDetailsService(
AuthenticationUserDetailsService<OpenIDAuthenticationToken> userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
public boolean supports(Class<?> authentication) {
return OpenIDAuthenticationToken.class.isAssignableFrom(authentication);
}
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
this.authoritiesMapper = authoritiesMapper;
}
}

View File

@ -1,60 +0,0 @@
/*
* 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.openid;
/**
* Authentication status codes, based on JanRain status codes
* @author JanRain Inc.
* @author Robin Bramley, Opsera Ltd
* @author Luke Taylor
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
public enum OpenIDAuthenticationStatus {
/** This code indicates a successful authentication request */
SUCCESS("success"),
/** This code indicates a failed authentication request */
FAILURE("failure"),
/** This code indicates the server reported an error */
ERROR("error"),
/**
* This code indicates that the user needs to do additional work to prove their
* identity
*/
SETUP_NEEDED("setup needed"),
/** This code indicates that the user cancelled their login request */
CANCELLED("cancelled");
private final String name;
OpenIDAuthenticationStatus(String name) {
this.name = name;
}
@Override
public String toString() {
return this.name;
}
}

View File

@ -1,119 +0,0 @@
/*
* 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.openid;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
/**
* OpenID Authentication Token
*
* @author Robin Bramley
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class OpenIDAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private final OpenIDAuthenticationStatus status;
private final Object principal;
private final String identityUrl;
private final String message;
private final List<OpenIDAttribute> attributes;
public OpenIDAuthenticationToken(OpenIDAuthenticationStatus status, String identityUrl, String message,
List<OpenIDAttribute> attributes) {
super(new ArrayList<>(0));
this.principal = identityUrl;
this.status = status;
this.identityUrl = identityUrl;
this.message = message;
this.attributes = attributes;
setAuthenticated(false);
}
/**
* Created by the <tt>OpenIDAuthenticationProvider</tt> on successful authentication.
* @param principal usually the <tt>UserDetails</tt> returned by the configured
* <tt>UserDetailsService</tt> used by the <tt>OpenIDAuthenticationProvider</tt>.
*/
public OpenIDAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities,
String identityUrl, List<OpenIDAttribute> attributes) {
super(authorities);
this.principal = principal;
this.status = OpenIDAuthenticationStatus.SUCCESS;
this.identityUrl = identityUrl;
this.message = null;
this.attributes = attributes;
setAuthenticated(true);
}
/**
* Returns 'null' always, as no credentials are processed by the OpenID provider.
* @see org.springframework.security.core.Authentication#getCredentials()
*/
@Override
public Object getCredentials() {
return null;
}
public String getIdentityUrl() {
return this.identityUrl;
}
public String getMessage() {
return this.message;
}
/**
* Returns the <tt>principal</tt> value.
*
* @see org.springframework.security.core.Authentication#getPrincipal()
*/
@Override
public Object getPrincipal() {
return this.principal;
}
public OpenIDAuthenticationStatus getStatus() {
return this.status;
}
public List<OpenIDAttribute> getAttributes() {
return this.attributes;
}
@Override
public String toString() {
return "[" + super.toString() + ", attributes : " + this.attributes + "]";
}
}

View File

@ -1,49 +0,0 @@
/*
* 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.openid;
import jakarta.servlet.http.HttpServletRequest;
/**
* An interface for OpenID library implementations
*
* @author Ray Krueger
* @author Robin Bramley, Opsera Ltd
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public interface OpenIDConsumer {
/**
* Given the request, the claimedIdentity, the return to url, and a realm, lookup the
* openId authentication page the user should be redirected to.
* @param req HttpServletRequest
* @param claimedIdentity String URI the user presented during authentication
* @param returnToUrl String URI of the URL we want the user sent back to by the OP
* @param realm URI pattern matching the realm we want the user to see
* @return String URI to redirect user to for authentication
* @throws OpenIDConsumerException if anything bad happens
*/
String beginConsumption(HttpServletRequest req, String claimedIdentity, String returnToUrl, String realm)
throws OpenIDConsumerException;
OpenIDAuthenticationToken endConsumption(HttpServletRequest req) throws OpenIDConsumerException;
}

View File

@ -1,39 +0,0 @@
/*
* 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.openid;
/**
* Thrown by an OpenIDConsumer if it cannot process a request
*
* @author Robin Bramley, Opsera Ltd
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class OpenIDConsumerException extends Exception {
public OpenIDConsumerException(String message) {
super(message);
}
public OpenIDConsumerException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -1,63 +0,0 @@
/*
* 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.openid;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
* @author Luke Taylor
* @since 3.1
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class RegexBasedAxFetchListFactory implements AxFetchListFactory {
private final Map<Pattern, List<OpenIDAttribute>> idToAttributes;
/**
* @param regexMap map of regular-expressions (matching the identifier) to attributes
* which should be fetched for that pattern.
*/
public RegexBasedAxFetchListFactory(Map<String, List<OpenIDAttribute>> regexMap) {
this.idToAttributes = new LinkedHashMap<>();
for (Map.Entry<String, List<OpenIDAttribute>> entry : regexMap.entrySet()) {
this.idToAttributes.put(Pattern.compile(entry.getKey()), entry.getValue());
}
}
/**
* Iterates through the patterns stored in the map and returns the list of attributes
* defined for the first match. If no match is found, returns an empty list.
*/
@Override
public List<OpenIDAttribute> createAttributeList(String identifier) {
for (Map.Entry<Pattern, List<OpenIDAttribute>> entry : this.idToAttributes.entrySet()) {
if (entry.getKey().matcher(identifier).matches()) {
return entry.getValue();
}
}
return Collections.emptyList();
}
}

View File

@ -1,17 +0,0 @@
/*
* 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.openid;

View File

@ -1,9 +0,0 @@
<html>
<body>
<p>Authenticates standard web browser users via <a href="https://openid.net">OpenID</a>.</p>
<p>NOTE: The OpenID 1.0 and 2.0 protocols have been deprecated and users are
<a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to migrate</a>
to <a href="https://openid.net/connect/">OpenID Connect</a>, which is supported by <code>spring-security-oauth2</code>.</p>
</body>
</html>

View File

@ -1,81 +0,0 @@
/*
* 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.openid;
import jakarta.servlet.http.HttpServletRequest;
/**
* @author Robin Bramley, Opsera Ltd
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class MockOpenIDConsumer implements OpenIDConsumer {
private OpenIDAuthenticationToken token;
private String redirectUrl;
public MockOpenIDConsumer() {
}
public MockOpenIDConsumer(String redirectUrl, OpenIDAuthenticationToken token) {
this.redirectUrl = redirectUrl;
this.token = token;
}
public MockOpenIDConsumer(String redirectUrl) {
this.redirectUrl = redirectUrl;
}
public MockOpenIDConsumer(OpenIDAuthenticationToken token) {
this.token = token;
}
@Override
public String beginConsumption(HttpServletRequest req, String claimedIdentity, String returnToUrl, String realm) {
return this.redirectUrl;
}
@Override
public OpenIDAuthenticationToken endConsumption(HttpServletRequest req) {
return this.token;
}
/**
* Set the redirectUrl to be returned by beginConsumption
* @param redirectUrl
*/
public void setRedirectUrl(String redirectUrl) {
this.redirectUrl = redirectUrl;
}
public void setReturnToUrl(String returnToUrl) {
// TODO Auto-generated method stub
}
/**
* Set the token to be returned by endConsumption
* @param token
*/
public void setToken(OpenIDAuthenticationToken token) {
this.token = token;
}
}

View File

@ -1,192 +0,0 @@
/*
* 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.openid;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.openid4java.association.AssociationException;
import org.openid4java.consumer.ConsumerException;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.consumer.VerificationResult;
import org.openid4java.discovery.DiscoveryException;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.Identifier;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.Message;
import org.openid4java.message.MessageException;
import org.openid4java.message.ParameterList;
import org.openid4java.message.ax.AxMessage;
import org.openid4java.message.ax.FetchResponse;
import org.springframework.mock.web.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* @author Luke Taylor
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class OpenID4JavaConsumerTests {
List<OpenIDAttribute> attributes = Arrays.asList(new OpenIDAttribute("a", "b"),
new OpenIDAttribute("b", "b", Arrays.asList("c")));
@SuppressWarnings("deprecation")
@Test
public void beginConsumptionCreatesExpectedSessionData() throws Exception {
ConsumerManager mgr = mock(ConsumerManager.class);
AuthRequest authReq = mock(AuthRequest.class);
DiscoveryInformation di = mock(DiscoveryInformation.class);
given(mgr.authenticate(any(DiscoveryInformation.class), any(), any())).willReturn(authReq);
given(mgr.associate(any())).willReturn(di);
OpenID4JavaConsumer consumer = new OpenID4JavaConsumer(mgr, new MockAttributesFactory());
MockHttpServletRequest request = new MockHttpServletRequest();
consumer.beginConsumption(request, "", "", "");
assertThat(request.getSession().getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST"))
.isEqualTo(this.attributes);
assertThat(request.getSession().getAttribute(DiscoveryInformation.class.getName())).isEqualTo(di);
// Check with empty attribute fetch list
consumer = new OpenID4JavaConsumer(mgr, new NullAxFetchListFactory());
request = new MockHttpServletRequest();
consumer.beginConsumption(request, "", "", "");
}
@Test
public void discoveryExceptionRaisesOpenIDException() throws Exception {
ConsumerManager mgr = mock(ConsumerManager.class);
OpenID4JavaConsumer consumer = new OpenID4JavaConsumer(mgr, new NullAxFetchListFactory());
given(mgr.discover(any())).willThrow(new DiscoveryException("msg"));
assertThatExceptionOfType(OpenIDConsumerException.class)
.isThrownBy(() -> consumer.beginConsumption(new MockHttpServletRequest(), "", "", ""));
}
@Test
public void messageOrConsumerAuthenticationExceptionRaisesOpenIDException() throws Exception {
ConsumerManager mgr = mock(ConsumerManager.class);
OpenID4JavaConsumer consumer = new OpenID4JavaConsumer(mgr, new NullAxFetchListFactory());
given(mgr.authenticate(ArgumentMatchers.<DiscoveryInformation>any(), any(), any()))
.willThrow(new MessageException("msg"), new ConsumerException("msg"));
assertThatExceptionOfType(OpenIDConsumerException.class)
.isThrownBy(() -> consumer.beginConsumption(new MockHttpServletRequest(), "", "", ""));
assertThatExceptionOfType(OpenIDConsumerException.class)
.isThrownBy(() -> consumer.beginConsumption(new MockHttpServletRequest(), "", "", ""));
}
@Test
public void failedVerificationReturnsFailedAuthenticationStatus() throws Exception {
ConsumerManager mgr = mock(ConsumerManager.class);
OpenID4JavaConsumer consumer = new OpenID4JavaConsumer(mgr, new NullAxFetchListFactory());
VerificationResult vr = mock(VerificationResult.class);
DiscoveryInformation di = mock(DiscoveryInformation.class);
given(mgr.verify(any(), any(ParameterList.class), any(DiscoveryInformation.class))).willReturn(vr);
MockHttpServletRequest request = new MockHttpServletRequest();
request.getSession().setAttribute(DiscoveryInformation.class.getName(), di);
OpenIDAuthenticationToken auth = consumer.endConsumption(request);
assertThat(auth.getStatus()).isEqualTo(OpenIDAuthenticationStatus.FAILURE);
}
@Test
public void verificationExceptionsRaiseOpenIDException() throws Exception {
ConsumerManager mgr = mock(ConsumerManager.class);
OpenID4JavaConsumer consumer = new OpenID4JavaConsumer(mgr, new NullAxFetchListFactory());
given(mgr.verify(any(), any(ParameterList.class), any(DiscoveryInformation.class)))
.willThrow(new MessageException(""), new AssociationException(""), new DiscoveryException(""));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setQueryString("x=5");
assertThatExceptionOfType(OpenIDConsumerException.class).isThrownBy(() -> consumer.endConsumption(request));
assertThatExceptionOfType(OpenIDConsumerException.class).isThrownBy(() -> consumer.endConsumption(request));
assertThatExceptionOfType(OpenIDConsumerException.class).isThrownBy(() -> consumer.endConsumption(request));
}
@SuppressWarnings("serial")
@Test
public void successfulVerificationReturnsExpectedAuthentication() throws Exception {
ConsumerManager mgr = mock(ConsumerManager.class);
OpenID4JavaConsumer consumer = new OpenID4JavaConsumer(mgr, new NullAxFetchListFactory());
VerificationResult vr = mock(VerificationResult.class);
DiscoveryInformation di = mock(DiscoveryInformation.class);
Identifier id = (Identifier) () -> "id";
Message msg = mock(Message.class);
given(mgr.verify(any(), any(ParameterList.class), any(DiscoveryInformation.class))).willReturn(vr);
given(vr.getVerifiedId()).willReturn(id);
given(vr.getAuthResponse()).willReturn(msg);
MockHttpServletRequest request = new MockHttpServletRequest();
request.getSession().setAttribute(DiscoveryInformation.class.getName(), di);
request.getSession().setAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST", this.attributes);
OpenIDAuthenticationToken auth = consumer.endConsumption(request);
assertThat(auth.getStatus()).isEqualTo(OpenIDAuthenticationStatus.SUCCESS);
}
@Test
public void fetchAttributesReturnsExpectedValues() throws Exception {
OpenID4JavaConsumer consumer = new OpenID4JavaConsumer(new NullAxFetchListFactory());
Message msg = mock(Message.class);
FetchResponse fr = mock(FetchResponse.class);
given(msg.hasExtension(AxMessage.OPENID_NS_AX)).willReturn(true);
given(msg.getExtension(AxMessage.OPENID_NS_AX)).willReturn(fr);
given(fr.getAttributeValues("a")).willReturn(Arrays.asList("x", "y"));
List<OpenIDAttribute> fetched = consumer.fetchAxAttributes(msg, this.attributes);
assertThat(fetched).hasSize(1);
assertThat(fetched.get(0).getValues()).hasSize(2);
}
@Test
public void messageExceptionFetchingAttributesRaisesOpenIDException() throws Exception {
OpenID4JavaConsumer consumer = new OpenID4JavaConsumer(new NullAxFetchListFactory());
Message msg = mock(Message.class);
FetchResponse fr = mock(FetchResponse.class);
given(msg.hasExtension(AxMessage.OPENID_NS_AX)).willReturn(true);
given(msg.getExtension(AxMessage.OPENID_NS_AX)).willThrow(new MessageException(""));
given(fr.getAttributeValues("a")).willReturn(Arrays.asList("x", "y"));
assertThatExceptionOfType(OpenIDConsumerException.class)
.isThrownBy(() -> consumer.fetchAxAttributes(msg, this.attributes));
}
@Test
public void missingDiscoveryInformationThrowsException() throws Exception {
OpenID4JavaConsumer consumer = new OpenID4JavaConsumer(new NullAxFetchListFactory());
assertThatExceptionOfType(OpenIDConsumerException.class)
.isThrownBy(() -> consumer.endConsumption(new MockHttpServletRequest()));
}
@Test
public void additionalConstructorsWork() throws Exception {
new OpenID4JavaConsumer();
new OpenID4JavaConsumer(new MockAttributesFactory());
}
private class MockAttributesFactory implements AxFetchListFactory {
@Override
public List<OpenIDAttribute> createAttributeList(String identifier) {
return OpenID4JavaConsumerTests.this.attributes;
}
}
}

View File

@ -1,127 +0,0 @@
/*
* Copyright 2002-2017 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.openid;
import java.net.URI;
import java.util.Collections;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
/**
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class OpenIDAuthenticationFilterTests {
OpenIDAuthenticationFilter filter;
private static final String REDIRECT_URL = "https://www.example.com/redirect";
private static final String CLAIMED_IDENTITY_URL = "https://www.example.com/identity";
private static final String REQUEST_PATH = "/login/openid";
private static final String FILTER_PROCESS_URL = "http://localhost:8080" + REQUEST_PATH;
private static final String DEFAULT_TARGET_URL = FILTER_PROCESS_URL;
@BeforeEach
public void setUp() {
this.filter = new OpenIDAuthenticationFilter();
this.filter.setConsumer(new MockOpenIDConsumer(REDIRECT_URL));
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
this.filter.setAuthenticationSuccessHandler(new SavedRequestAwareAuthenticationSuccessHandler());
successHandler.setDefaultTargetUrl(DEFAULT_TARGET_URL);
this.filter.setAuthenticationManager((a) -> a);
this.filter.afterPropertiesSet();
}
@Test
public void testFilterOperation() throws Exception {
MockHttpServletRequest req = new MockHttpServletRequest();
req.setServletPath(REQUEST_PATH);
req.setRequestURI(REQUEST_PATH);
req.setServerPort(8080);
MockHttpServletResponse response = new MockHttpServletResponse();
req.setParameter("openid_identifier", " " + CLAIMED_IDENTITY_URL);
req.setRemoteHost("www.example.com");
this.filter.setConsumer(new MockOpenIDConsumer() {
@Override
public String beginConsumption(HttpServletRequest req, String claimedIdentity, String returnToUrl,
String realm) {
assertThat(claimedIdentity).isEqualTo(CLAIMED_IDENTITY_URL);
assertThat(returnToUrl).isEqualTo(DEFAULT_TARGET_URL);
assertThat(realm).isEqualTo("http://localhost:8080/");
return REDIRECT_URL;
}
});
FilterChain fc = mock(FilterChain.class);
this.filter.doFilter(req, response, fc);
assertThat(response.getRedirectedUrl()).isEqualTo(REDIRECT_URL);
// Filter chain shouldn't proceed
verify(fc, never()).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
}
/**
* Tests that the filter encodes any query parameters on the return_to URL.
*/
@Test
public void encodesUrlParameters() throws Exception {
// Arbitrary parameter name and value that will both need to be encoded:
String paramName = "foo&bar";
String paramValue = "https://example.com/path?a=b&c=d";
MockHttpServletRequest req = new MockHttpServletRequest("GET", REQUEST_PATH);
req.addParameter(paramName, paramValue);
this.filter.setReturnToUrlParameters(Collections.singleton(paramName));
URI returnTo = new URI(this.filter.buildReturnToUrl(req));
String query = returnTo.getRawQuery();
assertThat(count(query, '=')).isEqualTo(1);
assertThat(count(query, '&')).isZero();
}
/**
* Counts the number of occurrences of {@code c} in {@code s}.
*/
private static int count(String s, char c) {
int count = 0;
for (char ch : s.toCharArray()) {
if (c == ch) {
count += 1;
}
}
return count;
}
}

View File

@ -1,200 +0,0 @@
/*
* 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.openid;
import org.junit.jupiter.api.Test;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.core.userdetails.UserDetailsService;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests {@link OpenIDAuthenticationProvider}
*
* @author Robin Bramley, Opsera Ltd
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
* supported by <code>spring-security-oauth2</code>.
*/
@Deprecated
public class OpenIDAuthenticationProviderTests {
private static final String USERNAME = "user.acegiopenid.com";
/*
* Test method for
* 'org.springframework.security.authentication.openid.OpenIDAuthenticationProvider.
* authenticate(Authentication)'
*/
@Test
public void testAuthenticateCancel() {
OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsService());
provider.setAuthoritiesMapper(new NullAuthoritiesMapper());
Authentication preAuth = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.CANCELLED, USERNAME, "",
null);
assertThat(preAuth.isAuthenticated()).isFalse();
assertThatExceptionOfType(AuthenticationCancelledException.class)
.isThrownBy(() -> provider.authenticate(preAuth)).withMessage("Log in cancelled");
}
/*
* Test method for
* 'org.springframework.security.authentication.openid.OpenIDAuthenticationProvider.
* authenticate(Authentication)'
*/
@Test
public void testAuthenticateError() {
OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsService());
Authentication preAuth = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.ERROR, USERNAME, "", null);
assertThat(preAuth.isAuthenticated()).isFalse();
assertThatExceptionOfType(AuthenticationServiceException.class).isThrownBy(() -> provider.authenticate(preAuth))
.withMessage("Error message from server: ");
}
/*
* Test method for
* 'org.springframework.security.authentication.openid.OpenIDAuthenticationProvider.
* authenticate(Authentication)'
*/
@Test
public void testAuthenticateFailure() {
OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
provider.setAuthenticationUserDetailsService(
new UserDetailsByNameServiceWrapper<>(new MockUserDetailsService()));
Authentication preAuth = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.FAILURE, USERNAME, "", null);
assertThat(preAuth.isAuthenticated()).isFalse();
assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> provider.authenticate(preAuth))
.withMessage("Log in failed - identity could not be verified");
}
/*
* Test method for
* 'org.springframework.security.authentication.openid.OpenIDAuthenticationProvider.
* authenticate(Authentication)'
*/
@Test
public void testAuthenticateSetupNeeded() {
OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsService());
Authentication preAuth = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SETUP_NEEDED, USERNAME, "",
null);
assertThat(preAuth.isAuthenticated()).isFalse();
assertThatExceptionOfType(AuthenticationServiceException.class).isThrownBy(() -> provider.authenticate(preAuth))
.withMessage("The server responded setup was needed, which shouldn't happen");
}
/*
* Test method for
* 'org.springframework.security.authentication.openid.OpenIDAuthenticationProvider.
* authenticate(Authentication)'
*/
@Test
public void testAuthenticateSuccess() {
OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsService());
Authentication preAuth = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS, USERNAME, "", null);
assertThat(preAuth.isAuthenticated()).isFalse();
Authentication postAuth = provider.authenticate(preAuth);
assertThat(postAuth).isNotNull();
assertThat(postAuth instanceof OpenIDAuthenticationToken).isTrue();
assertThat(postAuth.isAuthenticated()).isTrue();
assertThat(postAuth.getPrincipal()).isNotNull();
assertThat(postAuth.getPrincipal() instanceof UserDetails).isTrue();
assertThat(postAuth.getAuthorities()).isNotNull();
assertThat(postAuth.getAuthorities().size() > 0).isTrue();
assertThat(((OpenIDAuthenticationToken) postAuth).getStatus() == OpenIDAuthenticationStatus.SUCCESS).isTrue();
assertThat(((OpenIDAuthenticationToken) postAuth).getMessage() == null).isTrue();
}
@Test
public void testDetectsMissingAuthoritiesPopulator() throws Exception {
OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
assertThatIllegalArgumentException().isThrownBy(provider::afterPropertiesSet);
}
/*
* Test method for
* 'org.springframework.security.authentication.openid.OpenIDAuthenticationProvider.
* supports(Class)'
*/
@Test
public void testDoesntSupport() {
OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsService());
assertThat(provider.supports(UsernamePasswordAuthenticationToken.class)).isFalse();
}
/*
* Test method for
* 'org.springframework.security.authentication.openid.OpenIDAuthenticationProvider.
* authenticate(Authentication)'
*/
@Test
public void testIgnoresUserPassAuthToken() {
OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsService());
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(USERNAME, "password");
assertThat(provider.authenticate(token)).isNull();
}
/*
* Test method for
* 'org.springframework.security.authentication.openid.OpenIDAuthenticationProvider.
* supports(Class)'
*/
@Test
public void testSupports() {
OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsService());
assertThat(provider.supports(OpenIDAuthenticationToken.class)).isTrue();
}
@Test
public void testValidation() throws Exception {
OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
assertThatIllegalArgumentException().isThrownBy(provider::afterPropertiesSet);
provider = new OpenIDAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsService());
provider.afterPropertiesSet();
}
static class MockUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String ssoUserId) throws AuthenticationException {
return new User(ssoUserId, "password", true, true, true, true,
AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_B"));
}
}
}

View File

@ -1,19 +0,0 @@
<!-- NOTE: The OpenID 1.0 and 2.0 protocols have been deprecated and users are
<a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to migrate</a>
to <a href="https://openid.net/connect/">OpenID Connect</a>, which is supported by <code>spring-security-oauth2</code>. -->
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.security" level="${sec.log.level:-WARN}"/>
<root level="${root.level:-WARN}">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -280,7 +280,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
* </ol>
* @param request from which to extract parameters and perform the authentication
* @param response the response, which may be needed if the implementation has to do a
* redirect as part of a multi-stage authentication process (such as OpenID).
* redirect as part of a multi-stage authentication process (such as OIDC).
* @return the authenticated user token, or null if authentication is incomplete.
* @throws AuthenticationException if authentication fails.
*/

View File

@ -32,7 +32,6 @@ import jakarta.servlet.http.HttpSession;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.util.Assert;
@ -63,8 +62,6 @@ public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
private boolean formLoginEnabled;
private boolean openIdEnabled;
private boolean oauth2LoginEnabled;
private boolean saml2LoginEnabled;
@ -77,12 +74,6 @@ public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
private String rememberMeParameter;
private String openIDauthenticationUrl;
private String openIDusernameParameter;
private String openIDrememberMeParameter;
private Map<String, String> oauth2AuthenticationUrlToClientName;
private Map<String, String> saml2AuthenticationUrlToProviderName;
@ -92,31 +83,13 @@ public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
public DefaultLoginPageGeneratingFilter() {
}
public DefaultLoginPageGeneratingFilter(AbstractAuthenticationProcessingFilter filter) {
if (filter instanceof UsernamePasswordAuthenticationFilter) {
init((UsernamePasswordAuthenticationFilter) filter, null);
}
else {
init(null, filter);
}
}
public DefaultLoginPageGeneratingFilter(UsernamePasswordAuthenticationFilter authFilter,
AbstractAuthenticationProcessingFilter openIDFilter) {
init(authFilter, openIDFilter);
}
private void init(UsernamePasswordAuthenticationFilter authFilter,
AbstractAuthenticationProcessingFilter openIDFilter) {
public DefaultLoginPageGeneratingFilter(UsernamePasswordAuthenticationFilter authFilter) {
this.loginPageUrl = DEFAULT_LOGIN_PAGE_URL;
this.logoutSuccessUrl = DEFAULT_LOGIN_PAGE_URL + "?logout";
this.failureUrl = DEFAULT_LOGIN_PAGE_URL + "?" + ERROR_PARAMETER_NAME;
if (authFilter != null) {
initAuthFilter(authFilter);
}
if (openIDFilter != null) {
initOpenIdFilter(openIDFilter);
}
}
private void initAuthFilter(UsernamePasswordAuthenticationFilter authFilter) {
@ -128,15 +101,6 @@ public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
}
}
private void initOpenIdFilter(AbstractAuthenticationProcessingFilter openIDFilter) {
this.openIdEnabled = true;
this.openIDusernameParameter = "openid_identifier";
if (openIDFilter.getRememberMeServices() instanceof AbstractRememberMeServices) {
this.openIDrememberMeParameter = ((AbstractRememberMeServices) openIDFilter.getRememberMeServices())
.getParameter();
}
}
/**
* Sets a Function used to resolve a Map of the hidden inputs where the key is the
* name of the input and the value is the value of the input. Typically this is used
@ -149,7 +113,7 @@ public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
}
public boolean isEnabled() {
return this.formLoginEnabled || this.openIdEnabled || this.oauth2LoginEnabled || this.saml2LoginEnabled;
return this.formLoginEnabled || this.oauth2LoginEnabled || this.saml2LoginEnabled;
}
public void setLogoutSuccessUrl(String logoutSuccessUrl) {
@ -172,10 +136,6 @@ public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
this.formLoginEnabled = formLoginEnabled;
}
public void setOpenIdEnabled(boolean openIdEnabled) {
this.openIdEnabled = openIdEnabled;
}
public void setOauth2LoginEnabled(boolean oauth2LoginEnabled) {
this.oauth2LoginEnabled = oauth2LoginEnabled;
}
@ -198,15 +158,6 @@ public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
public void setRememberMeParameter(String rememberMeParameter) {
this.rememberMeParameter = rememberMeParameter;
this.openIDrememberMeParameter = rememberMeParameter;
}
public void setOpenIDauthenticationUrl(String openIDauthenticationUrl) {
this.openIDauthenticationUrl = openIDauthenticationUrl;
}
public void setOpenIDusernameParameter(String openIDusernameParameter) {
this.openIDusernameParameter = openIDusernameParameter;
}
public void setOauth2AuthenticationUrlToClientName(Map<String, String> oauth2AuthenticationUrlToClientName) {
@ -282,19 +233,6 @@ public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
sb.append(" <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n");
sb.append(" </form>\n");
}
if (this.openIdEnabled) {
sb.append(" <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"" + contextPath
+ this.openIDauthenticationUrl + "\">\n");
sb.append(" <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n");
sb.append(createError(loginError, errorMsg) + createLogoutSuccess(logoutSuccess) + " <p>\n");
sb.append(" <label for=\"username\" class=\"sr-only\">Identity</label>\n");
sb.append(" <input type=\"text\" id=\"username\" name=\"" + this.openIDusernameParameter
+ "\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n");
sb.append(" </p>\n");
sb.append(createRememberMe(this.openIDrememberMeParameter) + renderHiddenInputs(request));
sb.append(" <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n");
sb.append(" </form>\n");
}
if (this.oauth2LoginEnabled) {
sb.append("<h2 class=\"form-signin-heading\">Login with OAuth 2.0</h2>");
sb.append(createError(loginError, errorMsg));

View File

@ -20,8 +20,6 @@ import java.util.Collections;
import java.util.Locale;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test;
@ -29,8 +27,6 @@ import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
@ -131,12 +127,6 @@ public class DefaultLoginPageGeneratingFilterTests {
assertThat(response.getContentAsString()).isEmpty();
}
@Test
public void generatingPageWithOpenIdFilterOnlyIsSuccessFul() throws Exception {
DefaultLoginPageGeneratingFilter filter = new DefaultLoginPageGeneratingFilter(new MockProcessingFilter());
filter.doFilter(new MockHttpServletRequest("GET", "/login"), new MockHttpServletResponse(), this.chain);
}
/* SEC-1111 */
@Test
public void handlesNonIso8859CharsInErrorMessage() throws Exception {
@ -178,25 +168,6 @@ public class DefaultLoginPageGeneratingFilterTests {
assertThat(response.getContentAsString()).contains("Login with SAML 2.0");
assertThat(response.getContentAsString())
.contains("<a href=\"/saml/sso/google\">Google &lt; &gt; &quot; &#39; &amp;</a>");
} // Fake OpenID filter (since it's not in this module
@SuppressWarnings("unused")
private static class MockProcessingFilter extends AbstractAuthenticationProcessingFilter {
MockProcessingFilter() {
super("/someurl");
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
return null;
}
String getClaimedIdentityFieldName() {
return "unused";
}
}
}