Spring Security SAML Identity Metadata WITHOUT Spring Boot - spring

I keep seeing the following block of code for registering SAML identity providers:
spring:
security:
saml2:
relyingparty:
registration:
adfs:
identityprovider:
entity-id: https://idp.example.com/issuer
verification.credentials:
- certificate-location: "classpath:idp.crt"
singlesignon.url: https://idp.example.com/issuer/sso
singlesignon.sign-request: false
However, I have an older project that I need to implement multiple SAML identity providers that is NOT built on Spring Boot, and converting it is not an option (if we were starting the same project today, of course we would use Spring Boot).
How does the above code translate to doing this manually?

You can do that by exposing a bean of type RelyingPartyRegistrationRepository:
#Value("${verification.key}")
File verificationKey;
#Bean
public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception {
X509Certificate certificate = X509Support.decodeCertificate(this.verificationKey);
Saml2X509Credential credential = Saml2X509Credential.verification(certificate);
RelyingPartyRegistration registration = RelyingPartyRegistration
.withRegistrationId("example")
.assertingPartyDetails(party -> party
.entityId("https://idp.example.com/issuer")
.singleSignOnServiceLocation("https://idp.example.com/SSO.saml2")
.wantAuthnRequestsSigned(false)
.verificationX509Credentials(c -> c.add(credential))
)
.build();
return new InMemoryRelyingPartyRegistrationRepository(registration);
}
The application.yml properties that you mentioned, are just a shortcut to declare this bean from Spring Boot. There is a complete sample not using Spring Boot in the Spring Security samples repository.
Also, there is an entire section in Spring Security documentation teaching how to override Spring Boot auto-configuration (where I took the code block above).

Related

Can I have Spring Boot create a WebClient which uses OAuth2 without it trying to apply the OAuth flow to my endpoints?

I want to have a WebClient which uses a client_credentials OAuth2 flow to authorize with an API. I've followed various sets of instructions from the documentation to several tutorials.
I feel like I'm pretty close to getting Spring Boot to do what I want, but the default behaviour is doing something I don't want - I get redirected to /login when I make a request to any of my controllers. I want to be able to (at the moment) do an unauthorized request to my API, and have the service-to-service call use the configured OAuth2 flow.
spring:
main:
web-application-type: reactive
security:
oauth2:
client:
registration:
my-private-api:
client-id: <foo>
client-secret: <bar>
authorization-grant-type: client_credentials
provider:
my-private-api:
token-uri: <uri>
#Bean
WebClient webClient( final ReactiveClientRegistrationRepository clientRegistrations,
final ReactiveOAuth2AuthorizedClientService authorizedClientService )
{
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction( new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
clientRegistrations,
authorizedClientService ) );
oauth.setDefaultClientRegistrationId( "my-private-api" );
return WebClient.builder().filter( oauth ).build();
}
Do I need to do lots of manual configuration in order to avoid this default behaviour I don't want?
So turns out my OAuth configuration was fine, what I was actually asking for was "how do I disable the default behaviour of Spring Security's SecurityWebFilterChain" - which is to add a bean overriding the behaviour:
#Bean
SecurityWebFilterChain springWebFilterChain( final ServerHttpSecurity http )
{
http.httpBasic().disable().formLogin().disable().csrf().disable().logout().disable();
return http.build();
}

Access secured actuators from Spring Boot Admin with Kubernetes Service Discovery

I've got a Spring Boot Admin application which uses a Kubernetes Service Discovery to get the Spring Boot client applications.
spring:
cloud:
kubernetes:
discovery:
all-namespaces: true
service-labels:
springbootadmin: true
reload:
enabled: true
period: 60s
strategy: refresh
Without secured actuator endpoints this works fine.
But as soon as the client actuator endpoints are protected by basic auth this does not work any more. The Spring Boot Admin Documentation describes how to add the authentication data to the Spring Boot Admin Server bit it does not describe how to provide this when the services are discovered via Kubernetes.
I've tried these configurations. But they don't work:
Spring Boot Admin Docs: spring.boot.admin.instance-auth.default-user-name + password
Spring Boot Admin Tutorial spring.boot.admin.client.instance.metadata.user.name + password
I also found an answer which describes how to configure the credentials in the Kubernetes annotations. This works but I would prefer to configure the credentials in the Spring Boot Admin configuration (where I can use Secrets) and not separately for each service in the Kubernetes configuration as an unsecure label.
I think I have to inject the credentials in the Service Discovery metadata. But how?
EDIT
I've examined the service discovery and found no auth configuration options which could be provided:
class KubernetesDiscoveryProperties.Metadata
class de.codecentric.boot.admin.server.cloud.discovery.DefaultServiceInstanceConverter
It might be an option to add a custom header to the requests that are sent by SBA to the clients:
#Bean
public HttpHeadersProvider customHttpHeadersProvider() {
return (instance) -> {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Authorization", "Basic bXlTcGVjaWFsVXNlcm5hbWU6bXlTcGVjaWFsUGFzc3dvcmQ=");
return httpHeaders;
};
}
The authentication can be set by these settings:
spring:
boot:
admin:
instance-auth:
default-user-name: user
default-password: pw
These settings are read by the Configuration Class AdminServerInstanceWebClientConfiguration which instantiates a bean basicAuthHttpHeadersProvider.

Spring Boot 2.0.0.M4 breaks http basic auth in application.yml

Spring Boot 1.5.6.RELEASE respected the basic-auth username and password as specified in my application.yml below.
I have upgraded to 2.0.0.M4 and now the application always starts with the default 'user' and randomly generated password. Basically the settings below are always completely ignored.
I saw some changes in the release note/doc specific to simplifying actuator security enabled/disabled. I didn't see anything specific to this.
Any ideas?
From my application.yml
security:
basic:
enabled: true
realm: some-service
user:
name: example_user
password: example_password
Update:
I've confirmed this functionality was just plainly taken out starting with Spring Boot 2.0.0.M4
In the appendices:
All the security.basic.* family of stuff is missing here from the M4 reference:
https://docs.spring.io/spring-boot/docs/2.0.0.M4/reference/html/common-application-properties.html
But appears here in the M3 reference:
https://docs.spring.io/spring-boot/docs/2.0.0.M3/reference/html/common-application-properties.html
I was able to temporarily downgrade to M3 to restore the previous functionality but would still appreciate some guidance on what replaced it. I just need a single hardcoded basic-auth user for this scenario. I'm aware I could use object configurations to do a much more complicated setup.
Edit 2018-01-31:
The ability to auto-configure a single user has been restored (via the spring.security.user configuration keys) starting with Spring Boot 2.0.0-RC1 (source).
Original answer:
The Spring Boot security.* properties have been deprecated starting with Spring Boot 2.0.0-M4. You can read about this in the Release Notes:
Security auto-configuration has been completely revisited: developers should read the companion blog post and refer to the Spring Boot 2.0 Security wiki page for more details about the change.
In order to restore the basic auth functionality you can register a custom WebSecurityConfigurerAdapter, like this:
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
return new InMemoryUserDetailsManager(
User.withDefaultPasswordEncoder().username("user").password("password")
.authorities("ROLE_USER").build(),
User.withDefaultPasswordEncoder().username("admin").password("admin")
.authorities("ROLE_ACTUATOR", "ROLE_USER").build());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR")
.requestMatchers(StaticResourceRequest.toCommonLocations()).permitAll()
.antMatchers("/**").hasRole("USER")
.and()
.cors()
.and()
.httpBasic();
}
}
(This will also configure basic auth for the Actuator endpoints)
If you additionally need to read the username and password from a .properties file, you can simply inject the values using the #Value annotation.

UserInfoRestTemplateFactory setup fails with ResourceServerConfigurerAdapter and two spring-cloud-services-starters

I've slightly updated an Spring Cloud Services example to illustrate a problem that I'm having:
https://github.com/spring-cloud-services-samples/greeting/compare/master...timtebeek:master
After the above changes I'm using:
spring-cloud-services-starter-config-client:1.5.0.RELEASE
spring-cloud-services-starter-service-registry:1.5.0.RELEASE
spring-cloud-starter-oauth2:2.0.14.RELEASE
I've also added a minimal ResourceServerConfigurerAdapter
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
#Override
public void configure(final ResourceServerSecurityConfigurer resources) {
resources.resourceId("greeter");
}
}
And the bare minimum configuration setting:
security:
oauth2:
resource:
jwt:
key-uri: https://example.com/oauth/token_key
With these changes my application fails to deploy in PCF-DEV; I've not tried PCF proper, but expect the results to be similar. Here's the error message I get:
Method userInfoRestTemplateFactory in org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerTokenServicesConfiguration required a single bean, but 2 were found:
- eurekaOAuth2ResourceDetails: defined by method 'eurekaOAuth2ResourceDetails' in class path resource [io/pivotal/spring/cloud/service/eureka/EurekaOAuth2AutoConfiguration.class]
- configClientOAuth2ResourceDetails: defined by method 'configClientOAuth2ResourceDetails' in io.pivotal.spring.cloud.service.config.ConfigClientOAuth2BootstrapConfiguration
Action:
Consider marking one of the beans as #Primary, updating the consumer to accept multiple beans, or using #Qualifier to identify the bean that should be consumed
So it's trying to use what should be completely separate OAuth2ProtectedResourceDetails from spring-cloud-services-starters to setup my application security; Where I would want it to use the external JWT key only.
Can anyone help me with how I can have my PCF deployed application using both config and discovery services also use an external JWT token for authentication setup?
I ran into the same thing. I saw this thread a few months ago. I also upgraded to spring boot 1.5.4 and cloud Dalston.SR4 and that got me over the hump. Thanks.
I was shown that http://start.spring.io was using spring boot 1.5.9. It runs on PivotalWS, so I knew there was a solution.
Try this change:
security:
oauth2:
client:
client-id: someclient
client-secret: someclientpass
resource:
jwt:
key-uri: https://example.com/oauth/token_key
The client-id and client-secret are dummy values in my case. I assume since you are also using JWT token, that your resource doesn't need to validate the token with your JWT token provider, only the signature (key-uri).
So by adding the client-id and client-secret, I'm guessing (totally guessing) that it creates the required OAuth2ProtectedResourceDetails with a better (closer) scope.
The fact that it was looking for "userInfoRestTemplateFactory" when we don't need to lookup user info is what pointed me in this direction.
My services are successfully deploying on PivotalWS (run.pivotal.io) with this change, using spring boot 1.5.9 and Dalston.SR4 with io.pivotal.spring.cloud:spring-cloud-services-dependencies:1.5.0.RELEASE
change spring-boot-starter-parent to be 1.5.2.RELEASE ,spring-cloud-dependencies to be Dalston.RC1 , spring-cloud-services-dependencies 1.5.0.RELEASE

Implement multi-tenanted application with Keycloak and springboot

When we use 'KeycloakSpringBootConfigResolver' for reading the keycloak configuration from Spring Boot properties file instead of keycloak.json.
Now there are guidelines to implement a multi-tenant application using keycloak by overriding 'KeycloakConfigResolver' as specified in http://www.keycloak.org/docs/2.3/securing_apps_guide/topics/oidc/java/multi-tenancy.html.
The steps defined here can only be used with keycloak.json.
How can we adapt this to a Spring Boot application such that keycloak properties are read from the Spring Boot properties file and multi-tenancy is achieved.
You can access the keycloak config you secified in your application.yaml (or application.properties) if you inject org.keycloak.representations.adapters.config.AdapterConfig into your component.
#Component
public class MyKeycloakConfigResolver implements KeycloakConfigResolver {
private final AdapterConfig keycloakConfig;
public MyKeycloakConfigResolver(org.keycloak.representations.adapters.config.AdapterConfig keycloakConfig) {
this.keycloakConfig = keycloakConfig;
}
#Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
// make a defensive copy before changing the config
AdapterConfig currentConfig = new AdapterConfig();
BeanUtils.copyProperties(keycloakConfig, currentConfig);
// changes stuff here for example compute the realm
return KeycloakDeploymentBuilder.build(currentConfig);
}
}
After several trials, the only feasible option for spring boot is to have
Multiple instances of the spring boot application running with different spring 'profiles'.
Each application instance can have its own keycloak properties (as it is under different profiles) including the realm.
The challenge is to have an upgrade path for all instances for version upgrades/bug fixes, but I guess there are multiple strategies already implemented (not part of this discussion)
there is a ticket regarding this problem: https://issues.jboss.org/browse/KEYCLOAK-4139?_sscc=t
Comments for that ticket also talk about possible workarounds intervening in servlet setup of the service used (Tomcat/Undertow/Jetty), which you could try.
Note that the documentation you linked in your first comment is super outdated!

Resources