Skip to content

Commit

Permalink
Fixed login page renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
germanosin committed Dec 23, 2024
1 parent f65874a commit eae23e2
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 5 deletions.
1 change: 1 addition & 0 deletions .java-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
21
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ protected AbstractAuthSecurityConfig() {
"/logout",
"/oauth2/**",
"/static/**",
"/api/config/authentication"
"/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
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 @@ -15,6 +16,11 @@
@Slf4j
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());
Expand Down
52 changes: 52 additions & 0 deletions api/src/main/java/io/kafbat/ui/util/StaticFileWebFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.kafbat.ui.util;

import java.io.IOException;
import java.io.InputStream;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

public class StaticFileWebFilter implements WebFilter {
private ServerWebExchangeMatcher matcher;
private String contents;

public StaticFileWebFilter(String path, ClassPathResource resource) {
this.matcher = ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, path);
try (InputStream inputStream = resource.getInputStream()) {
this.contents = ResourceUtil.readAsString(resource);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return this.matcher.matches(exchange)
.filter(ServerWebExchangeMatcher.MatchResult::isMatch)
.switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
.flatMap((matchResult) -> this.render(exchange));
}

private Mono<Void> render(ServerWebExchange exchange) {
String contextPath = exchange.getRequest().getPath().contextPath().value();
String contentBody = contents
.replace("\"assets/", "\"" + contextPath + "/assets/")
.replace("PUBLIC-PATH-VARIABLE", contextPath);

ServerHttpResponse result = exchange.getResponse();
result.setStatusCode(HttpStatus.OK);
result.getHeaders().setContentType(MediaType.TEXT_HTML);
DataBufferFactory bufferFactory = exchange.getResponse().bufferFactory();
return result.writeWith(Mono.just(bufferFactory.wrap(contentBody.getBytes())));
}

}
2 changes: 1 addition & 1 deletion frontend/src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const queryClient = new QueryClient({
});
const App: React.FC = () => {
const { isDarkMode } = useContext(ThemeModeContext);
const isAuthRoute = useMatch('/auth/*');
const isAuthRoute = useMatch('/login');

return (
<QueryClientProvider client={queryClient}>
Expand Down

0 comments on commit eae23e2

Please sign in to comment.