Skip to content

Commit

Permalink
Fix LDAP login page by using internal static resources rather than ex…
Browse files Browse the repository at this point in the history
…ternal resources (bootstrap.css...)
  • Loading branch information
fmartinou committed Mar 21, 2024
1 parent 53a6553 commit 7935485
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

import com.provectus.kafka.ui.service.rbac.AccessControlService;
import com.provectus.kafka.ui.service.rbac.extractor.RbacLdapAuthoritiesExtractor;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import com.provectus.kafka.ui.util.EmptyRedirectStrategy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
Expand All @@ -17,6 +19,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpMethod;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.ldap.core.support.LdapContextSource;
Expand All @@ -39,6 +42,9 @@
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
import org.springframework.security.web.server.authentication.logout.RedirectServerLogoutSuccessHandler;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;

@Configuration
@EnableWebFluxSecurity
Expand All @@ -51,6 +57,31 @@ public class LdapSecurityConfig {

private final LdapProperties props;

public static final String LOGIN_URL = "/login";
public static final String LOGOUT_URL = "/login?logout";

@Bean
public SecurityWebFilterChain configure(ServerHttpSecurity http) {
log.info("Configuring LDAP authentication.");
final var authHandler = new RedirectServerAuthenticationSuccessHandler();
authHandler.setRedirectStrategy(new EmptyRedirectStrategy());
final var logoutSuccessHandler = new RedirectServerLogoutSuccessHandler();
logoutSuccessHandler.setLogoutSuccessUrl(URI.create(LOGOUT_URL));

return http.authorizeExchange(spec -> spec
.pathMatchers(AUTH_WHITELIST)
.permitAll()
.anyExchange()
.authenticated()
)
.formLogin(spec -> spec.loginPage(LOGIN_URL).authenticationSuccessHandler(authHandler))
.logout(spec -> spec
.logoutSuccessHandler(logoutSuccessHandler)
.requiresLogout(ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/logout")))
.csrf(ServerHttpSecurity.CsrfSpec::disable)
.build();
}

@Bean
public ReactiveAuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource,
LdapAuthoritiesPopulator authoritiesExtractor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,25 @@
@Slf4j
public class AuthController {

@GetMapping(value = "/login", produces = {"text/html"})
public Mono<byte[]> getLogin(ServerWebExchange exchange) {
Mono<CsrfToken> token = exchange.getAttributeOrDefault(CsrfToken.class.getName(), Mono.empty());
return token
.map(AuthController::csrfToken)
.defaultIfEmpty("")
.map(csrfTokenHtmlInput -> createPage(exchange, csrfTokenHtmlInput, "login"));
}

@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)
.defaultIfEmpty("")
.map(csrfTokenHtmlInput -> createPage(exchange, csrfTokenHtmlInput));
.map(csrfTokenHtmlInput -> createPage(exchange, csrfTokenHtmlInput, "auth"));
}

private byte[] createPage(ServerWebExchange exchange, String csrfTokenHtmlInput) {
private byte[] createPage(ServerWebExchange exchange, String csrfTokenHtmlInput, String path) {
MultiValueMap<String, String> queryParams = exchange.getRequest()
.getQueryParams();
String contextPath = exchange.getRequest().getPath().contextPath().value();
Expand All @@ -44,7 +53,7 @@ private byte[] createPage(ServerWebExchange exchange, String csrfTokenHtmlInput)
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ formLogin(queryParams, contextPath, csrfTokenHtmlInput)
+ formLogin(queryParams, contextPath, csrfTokenHtmlInput, path)
+ " </div>\n"
+ " </body>\n"
+ "</html>";
Expand All @@ -54,12 +63,13 @@ private byte[] createPage(ServerWebExchange exchange, String csrfTokenHtmlInput)

private String formLogin(
MultiValueMap<String, String> queryParams,
String contextPath, String csrfTokenHtmlInput) {
String contextPath, String csrfTokenHtmlInput,
String path) {

boolean isError = queryParams.containsKey("error");
boolean isLogoutSuccess = queryParams.containsKey("logout");
return
" <form class=\"form-signin\" method=\"post\" action=\"" + contextPath + "/auth\">\n"
" <form class=\"form-signin\" method=\"post\" action=\"" + contextPath + "/" + path +"\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ createError(isError)
+ createLogoutSuccess(isLogoutSuccess)
Expand Down

0 comments on commit 7935485

Please sign in to comment.