/******************************************************************************* * Copyright 2016 The MITRE Corporation * * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package org.mitre.openid.connect.binder.config; import java.util.HashMap; import java.util.List; import java.util.Map; import org.mitre.jose.keystore.JWKSetKeyStore; import org.mitre.jwt.signer.service.impl.DefaultJWTSigningAndValidationService; import org.mitre.jwt.signer.service.impl.JWKSetCacheService; import org.mitre.oauth2.model.RegisteredClient; import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod; import org.mitre.openid.connect.binder.authentication.MultipleIdentityAuthenticationConsistencyFilter; import org.mitre.openid.connect.binder.authentication.MultipleIdentityAuthenticationProvider; import org.mitre.openid.connect.client.OIDCAuthenticationFilter; import org.mitre.openid.connect.client.keypublisher.ClientKeyPublisher; import org.mitre.openid.connect.client.service.impl.DynamicRegistrationClientConfigurationService; import org.mitre.openid.connect.client.service.impl.DynamicServerConfigurationService; import org.mitre.openid.connect.client.service.impl.HybridIssuerService; import org.mitre.openid.connect.client.service.impl.JsonFileRegisteredClientService; import org.mitre.openid.connect.client.service.impl.PlainAuthRequestUrlBuilder; import org.mitre.openid.connect.client.service.impl.StaticAuthRequestOptionsService; import org.mitre.openid.connect.client.service.impl.StaticClientConfigurationService; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.annotation.Order; import org.springframework.core.io.ClassPathResource; 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.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter; import com.google.common.collect.Sets; import com.nimbusds.jose.JWSAlgorithm; @Configuration @EnableWebMvcSecurity @Order(4) // The EnableResourceServer annotation of OAuthProtectedResourceConfiguration uses a WebSecurityConfigurer with hard-coded Order of 3. public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter{ @Value( "${authentication.entryPoint}" ) private String authEntryPoint; @Value( "${issuerService.loginUrl}" ) private String issuerLoginUrl; @Value( "${staticClient.id}" ) private String staticId; @Value( "${staticClient.secret}" ) private String staticSecret; @Value( "${staticClient.name}" ) private String staticName; @Value( "#{'${staticClient.scope}'.split(',')}" ) private List<String> staticScope; @Value( "#{'${staticClient.redirectUris}'.split(',')}" ) private List<String> staticRedirects; @Value( "${staticClient.jwksUri}" ) private String staticJwks; @Value( "${staticClient.introspection}" ) private String staticInstrospection; @Value( "${client1.uri}" ) private String client1; @Value( "${client2.uri}" ) private String client2; @Value( "${dynamicClient.name}" ) private String dynamicName; @Value( "#{'${dynamicClient.scope}'.split(',')}" ) private List<String> dynamicScope; @Value( "#{'${dynamicClient.redirectUris}'.split(',')}" ) private List<String> dynamicRedirects; @Value( "${dynamicClient.jwksUri}" ) private String dynamicJwks; @Value( "${dynamicClient.introspection}" ) private String dynamicIntrospection; @Value( "${signerService.defaultId}" ) private String defaultSignerId; @Value( "${signerService.defaultAlgorithm}" ) private String defaultAlgorithm; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/", "/home", "/css/**", "/idps").permitAll() .and() .formLogin().loginPage("/login").permitAll().and().logout().permitAll() .and() .authorizeRequests().anyRequest().authenticated() .and() .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint()) .and() .addFilterBefore(openIdConnectAuthenticationFilter(), AbstractPreAuthenticatedProcessingFilter.class) .addFilterBefore(multipleIdentityAuthenticationConsistencyFilter(), OIDCAuthenticationFilter.class); } @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(openIdConnectAuthenticationProvider()); } @Bean public LoginUrlAuthenticationEntryPoint authenticationEntryPoint() { return new LoginUrlAuthenticationEntryPoint(authEntryPoint); } @Bean public MultipleIdentityAuthenticationConsistencyFilter multipleIdentityAuthenticationConsistencyFilter() { return new MultipleIdentityAuthenticationConsistencyFilter(); } @Bean public OIDCAuthenticationFilter openIdConnectAuthenticationFilter() throws Exception { OIDCAuthenticationFilter filter = new OIDCAuthenticationFilter(); filter.setAuthenticationManager(authenticationManager()); filter.setIssuerService(hybridIssuerService()); filter.setClientConfigurationService(dynamicClientConfigurationService()); filter.setServerConfigurationService(dynamicServerConfigurationService()); filter.setAuthRequestOptionsService(staticAuthRequestOptionsService()); filter.setAuthRequestUrlBuilder(plainAuthRequestUrlBuilder()); return filter; } @Bean public MultipleIdentityAuthenticationProvider openIdConnectAuthenticationProvider() { MultipleIdentityAuthenticationProvider authenticationProvider = new MultipleIdentityAuthenticationProvider(); return authenticationProvider; } @Bean public HybridIssuerService hybridIssuerService() { HybridIssuerService issuerService = new HybridIssuerService(); issuerService.setLoginPageUrl(issuerLoginUrl); return issuerService; } @Bean @Primary public DynamicServerConfigurationService dynamicServerConfigurationService() { return new DynamicServerConfigurationService(); } @Bean public StaticClientConfigurationService staticClientConfigurationService() { StaticClientConfigurationService clientConfigurationService = new StaticClientConfigurationService(); RegisteredClient client = new RegisteredClient(); client.setClientId(staticId); client.setClientSecret(staticSecret); client.setClientName(staticName); client.setScope(Sets.newHashSet(staticScope)); client.setTokenEndpointAuthMethod(AuthMethod.SECRET_BASIC); client.setRedirectUris(Sets.newHashSet(staticRedirects)); client.setRequestObjectSigningAlg(JWSAlgorithm.RS256); client.setJwksUri(staticJwks); client.setAllowIntrospection(Boolean.parseBoolean(staticInstrospection)); Map<String, RegisteredClient> clients = new HashMap<String, RegisteredClient>(); clients.put(client1, client); clients.put(client2, client); clientConfigurationService.setClients(clients); /* * Registered Client Service. Uncomment this to save dynamically registered clients out to a * file on disk (indicated by the filename property) or replace this with another implementation * of RegisteredClientService. This defaults to an in-memory implementation of RegisteredClientService * which will forget and re-register all clients on restart. */ // clientConfigurationService.setRegisteredClientService(new JsonFileRegisteredClientService("/tmp/simple-web-app-clients.json")); return clientConfigurationService; } @Bean @Primary public DynamicRegistrationClientConfigurationService dynamicClientConfigurationService() { DynamicRegistrationClientConfigurationService clientConfigurationService = new DynamicRegistrationClientConfigurationService(); RegisteredClient client = new RegisteredClient(); client.setClientName(dynamicName); client.setScope(Sets.newHashSet(dynamicScope)); client.setTokenEndpointAuthMethod(AuthMethod.SECRET_BASIC); client.setRedirectUris(Sets.newHashSet(dynamicRedirects)); client.setRequestObjectSigningAlg(JWSAlgorithm.RS256); client.setJwksUri(dynamicJwks); client.setAllowIntrospection(Boolean.parseBoolean(dynamicIntrospection)); clientConfigurationService.setTemplate(client); /* * Registered Client Service. Uncomment this to save dynamically registered clients out to a * file on disk (indicated by the filename property) or replace this with another implementation * of RegisteredClientService. This defaults to an in-memory implementation of RegisteredClientService * which will forget and re-register all clients on restart. */ // clientConfigurationService.setRegisteredClientService(new JsonFileRegisteredClientService("/tmp/simple-web-app-clients.json")); return clientConfigurationService; } @Bean public StaticAuthRequestOptionsService staticAuthRequestOptionsService() { return new StaticAuthRequestOptionsService(); } @Bean public PlainAuthRequestUrlBuilder plainAuthRequestUrlBuilder() { return new PlainAuthRequestUrlBuilder(); } @Bean public JWKSetCacheService jwkSetCacheService() { return new JWKSetCacheService(); } @Bean public DefaultJWTSigningAndValidationService defaultSignerService() throws Exception { JWKSetKeyStore defaultKeyStore = new JWKSetKeyStore(); defaultKeyStore.setLocation(new ClassPathResource("keystore.jwks")); DefaultJWTSigningAndValidationService signerService = new DefaultJWTSigningAndValidationService(defaultKeyStore); signerService.setDefaultSignerKeyId(defaultSignerId); signerService.setDefaultSigningAlgorithmName(defaultAlgorithm); return signerService; } // this bean causes an error during spring initialization: // "org.springframework.security.config.annotation.ObjectPostProcessor is a required bean. Ensure you have used @EnableWebSecurity and @Configuration" // @Bean // public ClientKeyPublisher clientKeyPublisher() throws Exception { // ClientKeyPublisher keyPublisher = new ClientKeyPublisher(); // keyPublisher.setJwkPublishUrl("jwk"); // keyPublisher.setSigningAndValidationService(defaultSignerService()); // return keyPublisher; // } }