Skip to content

Commit

Permalink
feat(server, ui): Fix PR
Browse files Browse the repository at this point in the history
  • Loading branch information
DelaunayAlex committed Oct 30, 2024
1 parent 127878a commit 57b2d12
Show file tree
Hide file tree
Showing 19 changed files with 181 additions and 330 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,37 @@ spring:
registration:
my-provider:
provider: my-provider
client-id: my-client
client-secret: my-client-secret
client-id: "${auth.sso.clientId}"
client-secret: "${auth.sso.clientSecret}"
authorization-grant-type: authorization_code
redirect-uri: "https://${server.http.interface}:${server.port}/login/oauth2/code/{registrationId}"
scope: openid, profile, email
client-name: My Provider
provider:
my-provider:
issuer-uri: http://localhost:3000
authorization-uri: http://localhost:3000/auth
token-uri: http://localhost:3000/token
user-info-uri: http://localhost:3000/me
authorization-uri: ${auth.sso.issuer}/auth
token-uri: ${auth.sso.issuer}/token
user-info-uri: ${auth.sso.issuer}/me
user-name-attribute: sub
jwk-set-uri: http://localhost:3000/jwks
jwk-set-uri: ${auth.sso.issuer}/jwks
resourceserver:
opaque-token:
introspection-uri: http://localhost:3000/token/introspection
client-id: 'my-client'
client-secret: 'my-client-secret'
introspection-uri: "${auth.sso.issuer}/token/introspection"
client-id: "${auth.sso.clientId}"
client-secret: "${auth.sso.clientSecret}"
authorizationserver:
issuer: http://localhost:3000
issuer: "${auth.sso.issuer}"
endpoint:
oidc:
user-info-uri: http://localhost:3000/userinfo
user-info-uri: "${auth.sso.issuer}/userinfo"

auth:
sso:
issuer: 'http://localhost:3000'
issuer: "http://localhost:3000"
clientId: 'my-client'
clientSecret: 'my-client-secret'
responseType: 'code'
scope: 'openid profile email'
redirectBaseUrl: 'https://localhost:4200'
ssoProviderName: 'SSO OIDC'
redirectBaseUrl: "https://localhost:4200"
ssoProviderName: 'SSO OpenID Connect'
oidc: true
6 changes: 6 additions & 0 deletions chutney/packaging/local-dev/src/test/resources/sso/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CLIENT_ID=my-client
CLIENT_SECRET=my-client-secret
REDIRECT_URI='https://localhost:4200'
TOKEN_FORMAT='opaque'
PORT=3000
GRANT_TYPE=authorization_code
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"author": "",
"description": "",
"dependencies": {
"dotenv": "^16.4.5",
"express": "^4.21.0",
"oidc-provider": "^8.5.1"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@

import express from 'express';
import { Provider } from 'oidc-provider';
import * as dotenv from 'dotenv';

dotenv.config()

const oidc = new Provider('http://localhost:3000', {
clients: [{
client_id: 'my-client',
client_secret: 'my-client-secret',
grant_types: ['authorization_code'],
redirect_uris: ['https://localhost:4200/'],
post_logout_redirect_uris: ['https://localhost:4200/'],
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
grant_types: [process.env.GRANT_TYPE],
redirect_uris: [process.env.REDIRECT_URI],
post_logout_redirect_uris: [process.env.REDIRECT_URI],
}],
formats: {
AccessToken: 'opaque',
RefreshToken: 'opaque',
IdToken: 'opaque'
AccessToken: process.env.TOKEN_FORMAT,
RefreshToken: process.env.TOKEN_FORMAT,
IdToken: process.env.TOKEN_FORMAT
},
features: {
introspection: {
Expand All @@ -29,7 +32,7 @@ const oidc = new Provider('http://localhost:3000', {
userinfo: { enabled: true },
},
clientBasedCORS(ctx, origin, client) {
const allowedOrigins = ['https://localhost:4200'];
const allowedOrigins = [process.env.REDIRECT_URI];
return allowedOrigins.includes(origin);
},
async findAccount(ctx, id) {
Expand All @@ -42,6 +45,7 @@ const oidc = new Provider('http://localhost:3000', {

const app = express();
app.use(oidc.callback());
app.listen(3000, () => {
console.log('OIDC provider listening on port 3000');
const port = parseInt(process.env.PORT, 10)
app.listen(port, () => {
console.log(`OIDC provider listening on port ${port}`);
});

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,133 @@

package com.chutneytesting.security;

import com.chutneytesting.admin.api.InfoController;
import com.chutneytesting.security.api.SsoOpenIdConnectController;
import com.chutneytesting.security.api.UserController;
import com.chutneytesting.security.api.UserDto;
import com.chutneytesting.security.domain.AuthenticationService;
import com.chutneytesting.security.domain.Authorizations;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import com.chutneytesting.security.infra.handlers.Http401FailureHandler;
import com.chutneytesting.security.infra.handlers.HttpEmptyLogoutSuccessHandler;
import com.chutneytesting.security.infra.handlers.HttpLoginSuccessHandler;
import com.chutneytesting.security.infra.sso.OAuth2SsoUserService;
import com.chutneytesting.security.infra.sso.OAuth2TokenAuthenticationFilter;
import com.chutneytesting.security.infra.sso.OAuth2TokenAuthenticationProvider;
import com.chutneytesting.security.infra.sso.SsoOpenIdConnectConfigProperties;
import com.chutneytesting.server.core.domain.security.Authorization;
import com.chutneytesting.server.core.domain.security.User;
import java.util.ArrayList;
import java.util.Collections;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.oauth2.server.servlet.OAuth2AuthorizationServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.ChannelSecurityConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@Profile("!sso-auth")
public class ChutneyWebSecurityConfig extends AbstractChutneyWebSecurityConfig {
@EnableConfigurationProperties({OAuth2AuthorizationServerProperties.class, SsoOpenIdConnectConfigProperties.class})
public class ChutneyWebSecurityConfig {

protected static final String LOGIN_URL = UserController.BASE_URL + "/login";
protected static final String LOGOUT_URL = UserController.BASE_URL + "/logout";
protected static final String API_BASE_URL_PATTERN = "/api/**";

@Value("${management.endpoints.web.base-path:/actuator}")
protected String actuatorBaseUrl;

@Value("${server.ssl.enabled:true}")
private Boolean sslEnabled;

@Bean
public AuthenticationService authenticationService(Authorizations authorizations) {
return new AuthenticationService(authorizations);
}

@Bean
@Order()
@ConditionalOnMissingBean(value = SecurityFilterChain.class)
public SecurityFilterChain securityFilterChain(final HttpSecurity http) throws Exception {
return configureHttp(http).build();
public SecurityFilterChain securityFilterChain(final HttpSecurity http, AuthenticationService authenticationService, @Nullable ClientRegistrationRepository clientRegistrationRepository) throws Exception {
configureSso(http, authenticationService, clientRegistrationRepository);
configureBaseHttpSecurity(http);
UserDto anonymous = anonymous();
http.anonymous(anonymousConfigurer -> anonymousConfigurer
.principal(anonymous)
.authorities(new ArrayList<>(anonymous.getAuthorities())))
.authorizeHttpRequests(httpRequest -> {
HandlerMappingIntrospector introspector = new HandlerMappingIntrospector();
httpRequest
.requestMatchers(new MvcRequestMatcher(introspector, LOGIN_URL)).permitAll()
.requestMatchers(new MvcRequestMatcher(introspector, LOGOUT_URL)).permitAll()
.requestMatchers(new MvcRequestMatcher(introspector, InfoController.BASE_URL + "/**")).permitAll()
.requestMatchers(new MvcRequestMatcher(introspector, SsoOpenIdConnectController.BASE_URL + "/**")).permitAll()
.requestMatchers(new MvcRequestMatcher(introspector, API_BASE_URL_PATTERN)).authenticated()
.requestMatchers(new MvcRequestMatcher(introspector, actuatorBaseUrl + "/**")).hasAuthority(Authorization.ADMIN_ACCESS.name())
.anyRequest().permitAll();
})
.httpBasic(Customizer.withDefaults());
return http.build();
}

protected void configureBaseHttpSecurity(final HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> httpSecurityExceptionHandlingConfigurer.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)))
.requiresChannel(this.requireChannel(sslEnabled))
.formLogin(httpSecurityFormLoginConfigurer -> httpSecurityFormLoginConfigurer
.loginProcessingUrl(LOGIN_URL)
.successHandler(new HttpLoginSuccessHandler())
.failureHandler(new Http401FailureHandler()))
.logout(httpSecurityLogoutConfigurer -> httpSecurityLogoutConfigurer
.logoutUrl(LOGOUT_URL)
.logoutSuccessHandler(new HttpEmptyLogoutSuccessHandler()));
}

protected UserDto anonymous() {
UserDto anonymous = new UserDto();
anonymous.setId(User.ANONYMOUS.id);
anonymous.setName(User.ANONYMOUS.id);
anonymous.grantAuthority("ANONYMOUS");
return anonymous;
}

private Customizer<ChannelSecurityConfigurer<HttpSecurity>.ChannelRequestMatcherRegistry> requireChannel(Boolean sslEnabled) {
if (sslEnabled) {
return channelRequestMatcherRegistry -> channelRequestMatcherRegistry.anyRequest().requiresSecure();
} else {
return channelRequestMatcherRegistry -> channelRequestMatcherRegistry.anyRequest().requiresInsecure();
}
}

private void configureSso(final HttpSecurity http, AuthenticationService authenticationService, ClientRegistrationRepository clientRegistrationRepository) throws Exception {
if (clientRegistrationRepository != null) {
OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService = new OAuth2SsoUserService(authenticationService);
OAuth2TokenAuthenticationProvider oAuth2TokenAuthenticationProvider = new OAuth2TokenAuthenticationProvider(oAuth2UserService, clientRegistrationRepository.findByRegistrationId("my-provider"));
AuthenticationManager authenticationManager = new ProviderManager(Collections.singletonList(oAuth2TokenAuthenticationProvider));
OAuth2TokenAuthenticationFilter tokenFilter = new OAuth2TokenAuthenticationFilter(authenticationManager);
http
.authenticationProvider(oAuth2TokenAuthenticationProvider)
.addFilterBefore(tokenFilter, BasicAuthenticationFilter.class)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED));
}
}
}
Loading

0 comments on commit 57b2d12

Please sign in to comment.