Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Infra: Add gradle p.1 #783

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
25dea60
Misc
Haarolean Oct 25, 2024
1e668f8
Impl authentication page backend
Haarolean Oct 25, 2024
7b6cf2e
Merge remote-tracking branch 'origin/main' into auth_page_be
Haarolean Oct 25, 2024
d91e8b9
Add POST auth endpoint
Haarolean Nov 17, 2024
5ec0abe
Merge branch 'main' into auth_page_be
Haarolean Dec 17, 2024
3e61608
resolves #72
Nilumilak May 20, 2024
09f2070
feat: auth page
Nilumilak Nov 17, 2024
09062ef
feat: auth page
Nilumilak Dec 17, 2024
92b7db6
Fix missing controller tag
Haarolean Dec 17, 2024
8e78c51
feat: auth page
Nilumilak Dec 17, 2024
b8161eb
feat: auth page
Nilumilak Dec 18, 2024
f65874a
Lint
Haarolean Dec 18, 2024
eae23e2
Fixed login page renderer
germanosin Dec 23, 2024
6cf3881
Initial gradle support
germanosin Jan 15, 2025
cbc96ff
Merge main
germanosin Jan 15, 2025
4a6ee2b
Plugins varion catalog
germanosin Jan 15, 2025
7c5fbd1
Plugins varion catalog
germanosin Jan 15, 2025
112ede0
Added jib and nexus publish
germanosin Jan 15, 2025
8085237
Update node version
germanosin Jan 16, 2025
4f568c5
Update default version
germanosin Jan 16, 2025
17e0624
Fixing comments
germanosin Jan 17, 2025
f828fd3
Fixing comments
germanosin Jan 17, 2025
336eb76
Version cleanup, minor refactoring
Haarolean Jan 17, 2025
ac99710
Simplify dep mngmnt, update libs
Haarolean Jan 17, 2025
f7183fa
Dedupe boot version
Haarolean Jan 23, 2025
808807e
Added e2e flags
germanosin Jan 29, 2025
436904b
Switched release flag instead of prod
germanosin Jan 29, 2025
21d2155
rm todo
Haarolean Jan 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ build/
*.tgz

/docker/*.override.yaml
out/
node_modules/
.gradle
1 change: 1 addition & 0 deletions .java-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
21
115 changes: 115 additions & 0 deletions api/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@

plugins {
id 'antlr'
id 'checkstyle'
id 'org.springframework.boot' version '3.4.1'
Haarolean marked this conversation as resolved.
Show resolved Hide resolved
id 'com.gorylenko.gradle-git-properties' version "2.4.2"
}

dependencies {
implementation project(":contract")
implementation project(":frontend")
Haarolean marked this conversation as resolved.
Show resolved Hide resolved
implementation project(":serde-api")

implementation libs.spring.starter.webflux
implementation libs.spring.starter.security
implementation libs.spring.starter.actuator
implementation libs.spring.starter.logging
implementation libs.spring.starter.oauth2.client
implementation libs.spring.boot.actuator
compileOnly libs.spring.boot.devtools

implementation libs.spring.security.ldap

implementation libs.kafka.clients

implementation libs.apache.avro
implementation libs.apache.commons
implementation libs.apache.commons.pool2
implementation libs.apache.datasketches

implementation libs.confluent.schema.registry.client
implementation libs.confluent.avro.serializer
implementation libs.confluent.protobuf.serializer
implementation libs.confluent.json.schema.serializer

implementation libs.aws.msk.auth
implementation (libs.azure.identity) {
exclude group: 'io.netty', module: 'netty-tcnative-boringssl-static'
germanosin marked this conversation as resolved.
Show resolved Hide resolved
}

implementation libs.jackson.databind.nullable
implementation libs.cel
antlr libs.antlr
implementation libs.antlr.runtime

implementation libs.opendatadiscovery.oddrn
implementation (libs.opendatadiscovery.client) {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-webflux'
exclude group: 'io.projectreactor', module: 'reactor-core'
exclude group: 'io.projectreactor.ipc', module: 'reactor-netty'
}

runtimeOnly libs.micrometer.registry.prometheus

// CVE Fixes
implementation libs.apache.commons.compress
implementation libs.okhttp3.logging.intercepter

// Annotation processors
implementation libs.lombok
implementation libs.mapstruct
annotationProcessor libs.lombok
annotationProcessor libs.mapstruct.processor
annotationProcessor libs.spring.boot.configuration.processor
testAnnotationProcessor libs.lombok
testAnnotationProcessor libs.mapstruct.processor

// Tests
testImplementation libs.spring.starter.test
testImplementation libs.reactor.test
testImplementation libs.testcontainers
testImplementation libs.testcontainers.kafka
testImplementation libs.testcontainers.jupiter
testImplementation libs.junit.jupiter.engine
testImplementation libs.mockito.core
testImplementation libs.mockito.jupiter
testImplementation libs.bytebuddy
testImplementation libs.assertj
testImplementation libs.jsonschemavalidator

testImplementation libs.okhttp3
testImplementation libs.okhttp3.mockwebserver
}

generateGrammarSource {
maxHeapSize = "64m"
arguments += ["-package", "ksql"]
}

sourceSets {
main {
antlr {
srcDirs = ["src/main/antlr4"]
}
java {
srcDirs += generateGrammarSource.outputDirectory
}
}
}

tasks.withType(Checkstyle) {
exclude '**/ksql/**'
}

checkstyle {
toolVersion '10.3.1'
germanosin marked this conversation as resolved.
Show resolved Hide resolved
configFile = rootProject.file('etc/checkstyle/checkstyle-e2e.xml')
germanosin marked this conversation as resolved.
Show resolved Hide resolved
ignoreFailures = false
maxWarnings = 0
maxErrors = 0
}

test {
useJUnitPlatform()
}
4 changes: 2 additions & 2 deletions api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -440,10 +440,10 @@
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/classes/static</outputDirectory>
<outputDirectory>${basedir}/target/classes/</outputDirectory>
<resources>
<resource>
<directory>../frontend/build</directory>
<directory>../frontend/build/vite/static</directory>
</resource>
</resources>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.kafbat.ui.config;

import io.kafbat.ui.exception.ValidationException;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ protected AbstractAuthSecurityConfig() {
"/login",
"/logout",
"/oauth2/**",
"/static/**"
"/static/**",
"/api/config/authentication",
"/index.html",
"/assets/**",
"/manifest.json",
"/favicon/**",
"/api/authorization"
};

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.kafbat.ui.config.auth.logout.OAuthLogoutSuccessHandler;
import io.kafbat.ui.service.rbac.AccessControlService;
import io.kafbat.ui.service.rbac.extractor.ProviderAuthorityExtractor;
import io.kafbat.ui.util.StaticFileWebFilter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand All @@ -16,9 +17,11 @@
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcReactiveOAuth2UserService;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
Expand Down Expand Up @@ -50,16 +53,22 @@ public class OAuthSecurityConfig extends AbstractAuthSecurityConfig {
public SecurityWebFilterChain configure(ServerHttpSecurity http, OAuthLogoutSuccessHandler logoutHandler) {
log.info("Configuring OAUTH2 authentication.");

return http.authorizeExchange(spec -> spec
ServerHttpSecurity builder = http.authorizeExchange(spec -> spec
.pathMatchers(AUTH_WHITELIST)
.permitAll()
.anyExchange()
.authenticated()
)
.oauth2Login(Customizer.withDefaults())
.logout(spec -> spec.logoutSuccessHandler(logoutHandler))
.csrf(ServerHttpSecurity.CsrfSpec::disable)
.build();
.csrf(ServerHttpSecurity.CsrfSpec::disable);


builder.addFilterAt(new StaticFileWebFilter(
"/login", new ClassPathResource("/static/index.html")
), SecurityWebFiltersOrder.LOGIN_PAGE_GENERATING);

return builder.build();
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package io.kafbat.ui.config.auth;

import io.kafbat.ui.model.rbac.Role;
import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("rbac")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.kafbat.ui.api.ApplicationConfigApi;
import io.kafbat.ui.config.ClustersProperties;
import io.kafbat.ui.model.ActionDTO;
import io.kafbat.ui.model.AppAuthenticationSettingsDTO;
import io.kafbat.ui.model.ApplicationConfigDTO;
import io.kafbat.ui.model.ApplicationConfigPropertiesDTO;
import io.kafbat.ui.model.ApplicationConfigValidationDTO;
Expand Down Expand Up @@ -66,6 +67,13 @@ public Mono<ResponseEntity<ApplicationInfoDTO>> getApplicationInfo(ServerWebExch
return Mono.just(applicationInfoService.getApplicationInfo()).map(ResponseEntity::ok);
}

@Override
public Mono<ResponseEntity<AppAuthenticationSettingsDTO>> getAuthenticationSettings(
ServerWebExchange exchange) {
return Mono.just(applicationInfoService.getAuthenticationProperties())
.map(ResponseEntity::ok);
}

@Override
public Mono<ResponseEntity<ApplicationConfigDTO>> getCurrentConfig(ServerWebExchange exchange) {
var context = AccessContext.builder()
Expand Down Expand Up @@ -109,7 +117,7 @@ public Mono<ResponseEntity<UploadedFileInfoDTO>> uploadConfigRelatedFile(Flux<Pa
.then(fileFlux.single())
.flatMap(file ->
dynamicConfigOperations.uploadConfigRelatedFile((FilePart) file)
.map(path -> new UploadedFileInfoDTO().location(path.toString()))
.map(path -> new UploadedFileInfoDTO(path.toString()))
.map(ResponseEntity::ok))
.doOnEach(sig -> audit(context, sig));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.nio.charset.Charset;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.web.server.csrf.CsrfToken;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -13,13 +14,18 @@
@RestController
@RequiredArgsConstructor
@Slf4j
public class AuthController {
public class AuthenticationController {

@GetMapping(value = "/login", produces = {"text/html"})
public Mono<ClassPathResource> getLoginPage(ServerWebExchange exchange) {
return Mono.just(new ClassPathResource("static/index.html"));
}

@GetMapping(value = "/auth", produces = {"text/html"})
public Mono<byte[]> getAuth(ServerWebExchange exchange) {
Mono<CsrfToken> token = exchange.getAttributeOrDefault(CsrfToken.class.getName(), Mono.empty());
return token
.map(AuthController::csrfToken)
.map(AuthenticationController::csrfToken)
.defaultIfEmpty("")
.map(csrfTokenHtmlInput -> createPage(exchange, csrfTokenHtmlInput));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
@RestController
@RequiredArgsConstructor
@Slf4j
public class AccessController implements AuthorizationApi {
public class AuthorizationController implements AuthorizationApi {

private final AccessControlService accessControlService;

Expand Down
46 changes: 46 additions & 0 deletions api/src/main/java/io/kafbat/ui/service/ApplicationInfoService.java
Original file line number Diff line number Diff line change
@@ -1,37 +1,51 @@
package io.kafbat.ui.service;

import static io.kafbat.ui.api.model.AuthType.DISABLED;
import static io.kafbat.ui.api.model.AuthType.OAUTH2;
import static io.kafbat.ui.model.ApplicationInfoDTO.EnabledFeaturesEnum;
import static io.kafbat.ui.util.GithubReleaseInfo.GITHUB_RELEASE_INFO_TIMEOUT;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Streams;
import io.kafbat.ui.model.AppAuthenticationSettingsDTO;
import io.kafbat.ui.model.ApplicationInfoBuildDTO;
import io.kafbat.ui.model.ApplicationInfoDTO;
import io.kafbat.ui.model.ApplicationInfoLatestReleaseDTO;
import io.kafbat.ui.model.AuthTypeDTO;
import io.kafbat.ui.model.OAuthProviderDTO;
import io.kafbat.ui.util.DynamicConfigOperations;
import io.kafbat.ui.util.GithubReleaseInfo;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.info.BuildProperties;
import org.springframework.boot.info.GitProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.stereotype.Service;

@Service
public class ApplicationInfoService {
private final GithubReleaseInfo githubReleaseInfo;
private final ApplicationContext applicationContext;
private final DynamicConfigOperations dynamicConfigOperations;
private final BuildProperties buildProperties;
private final GitProperties gitProperties;

public ApplicationInfoService(DynamicConfigOperations dynamicConfigOperations,
ApplicationContext applicationContext,
@Autowired(required = false) BuildProperties buildProperties,
@Autowired(required = false) GitProperties gitProperties,
@Value("${" + GITHUB_RELEASE_INFO_TIMEOUT + ":10}") int githubApiMaxWaitTime) {
this.applicationContext = applicationContext;
this.dynamicConfigOperations = dynamicConfigOperations;
this.buildProperties = Optional.ofNullable(buildProperties).orElse(new BuildProperties(new Properties()));
this.gitProperties = Optional.ofNullable(gitProperties).orElse(new GitProperties(new Properties()));
Expand Down Expand Up @@ -70,6 +84,38 @@ private List<EnabledFeaturesEnum> getEnabledFeatures() {
return enabledFeatures;
}

public AppAuthenticationSettingsDTO getAuthenticationProperties() {
return new AppAuthenticationSettingsDTO()
.authType(AuthTypeDTO.fromValue(getAuthType()))
.oAuthProviders(getOAuthProviders());
}

private String getAuthType() {
return Optional.ofNullable(applicationContext.getEnvironment().getProperty("auth.type"))
.orElse(DISABLED.getValue());
}

@SuppressWarnings("unchecked")
private List<OAuthProviderDTO> getOAuthProviders() {
if (!getAuthType().equalsIgnoreCase(OAUTH2.getValue())) {
return Collections.emptyList();
}
var type = ResolvableType.forClassWithGenerics(Iterable.class, ClientRegistration.class);
String[] names = this.applicationContext.getBeanNamesForType(type);
var bean = (Iterable<ClientRegistration>) (names.length == 1 ? this.applicationContext.getBean(names[0]) : null);

if (bean == null) {
return Collections.emptyList();
}

return Streams.stream(bean.iterator())
.filter(r -> AuthorizationGrantType.AUTHORIZATION_CODE.equals(r.getAuthorizationGrantType()))
.map(r -> new OAuthProviderDTO()
.clientName(r.getClientName())
.authorizationUri("/oauth2/authorization/" + r.getRegistrationId()))
.toList();
}

// updating on startup and every hour
@Scheduled(fixedRateString = "${github-release-info-update-rate:3600000}")
public void updateGithubReleaseInfo() {
Expand Down
Loading
Loading