Waffle / waffle

Enable drop-in Windows Single Sign On for popular Java web servers.
https://waffle.github.io/waffle
MIT License
474 stars 186 forks source link

AuthorizationHeader is empty in Waffle after update to Spring Boot 3 #2598

Closed Eyvind-A closed 2 weeks ago

Eyvind-A commented 4 weeks ago

We use Waffle in our Vaadin app. I have debugged the source code for Waffle.

request.getHeader("Authorization"); is called on line 61 in the Waffle-class AuthorizationHeader. This returns null, which causes no WindowsPrincipal being created. This makes it impossible to being authenticated. How can this be solved? This is my code:

@Configuration @EnableWebSecurity @EnableMethodSecurity(securedEnabled = true) @ComponentScan public class SecurityConfiguration {

@Autowired
private NegotiateSecurityFilter negotiateSecurityFilter;

@Autowired
private NegotiateSecurityFilterEntryPoint entryPoint;

    @Bean
protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(requests -> {
        requests.requestMatchers("/**").permitAll()
                .requestMatchers("/**").authenticated();
        })
        .headers(headers -> headers
            .frameOptions(frameOptions -> frameOptions
                    .sameOrigin()
            )
        )
        .addFilterAfter(negotiateSecurityFilter, BasicAuthenticationFilter.class);
    http.csrf(AbstractHttpConfigurer::disable); 

    return http.build();

}

@Configuration public class WaffleConfig {

@Bean
public WindowsAuthProviderImpl waffleWindowsAuthProvider() {
    return new WindowsAuthProviderImpl();
}

@Bean
public NegotiateSecurityFilterProvider negotiateSecurityFilterProvider(
        WindowsAuthProviderImpl windowsAuthProvider) {
    NegotiateSecurityFilterProvider negotiateSecurityFilterProvider = new NegotiateSecurityFilterProvider(windowsAuthProvider);
    negotiateSecurityFilterProvider.setProtocols(Arrays.asList("NTLM"));
    return negotiateSecurityFilterProvider;
}

@Bean
public BasicSecurityFilterProvider basicSecurityFilterProvider(WindowsAuthProviderImpl windowsAuthProvider) {
    return new BasicSecurityFilterProvider(windowsAuthProvider);
}

@Bean
public SecurityFilterProviderCollection waffleSecurityFilterProviderCollection(
        NegotiateSecurityFilterProvider negotiateSecurityFilterProvider,
        BasicSecurityFilterProvider basicSecurityFilterProvider) {
    SecurityFilterProvider[] securityFilterProviders = {
            negotiateSecurityFilterProvider,
            basicSecurityFilterProvider };
    return new SecurityFilterProviderCollection(securityFilterProviders);
}

@Bean
public NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint(
        SecurityFilterProviderCollection securityFilterProviderCollection) {
    NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint = new NegotiateSecurityFilterEntryPoint();
    negotiateSecurityFilterEntryPoint.setProvider(securityFilterProviderCollection);
    return negotiateSecurityFilterEntryPoint;
}

@Bean
public NegotiateSecurityFilter waffleNegotiateSecurityFilter(SecurityFilterProviderCollection securityFilterProviderCollection) {
    NegotiateSecurityFilter negotiateSecurityFilter = new NegotiateSecurityFilter();
    negotiateSecurityFilter.setProvider(securityFilterProviderCollection);
    return negotiateSecurityFilter;
}

// This is required for Spring Boot so it does not register the same filter twice
@Bean
public FilterRegistrationBean waffleNegotiateSecurityFilterRegistration(NegotiateSecurityFilter waffleNegotiateSecurityFilter) {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter(waffleNegotiateSecurityFilter);
    registrationBean.setEnabled(false);
    return registrationBean;
}
pedroneil commented 4 weeks ago

This might be your zone and host names etc.

Windows is not negotiating for you use, the handler is not receiving a windows user principle.

If you run all in localhist, that might work.

When your browser calls your app, your app and browser must be intranet zone in windows. Your browser will only send windows credentials to an intranet zone site

vaadinapp.my.domain.com mystery be intranet

I used to have to ensure that vaadinapp.my.domain.com was in the hosts file of a windows workgroup server.

127.0.0.1 vaadinapp.my.domain.com vaadinapp

Make sure all of this is in your dns or hosts file in your calling machine... even Linux Herbert's can negotiate against a windows server Waffle app

On Tue, 29 Oct 2024, 13:23 Eyvind-A, @.***> wrote:

We use Waffle in our Vaadin app. I have debugged the source code for Waffle.

request.getHeader("Authorization"); is called on line 61 in the Waffle-class AuthorizationHeader. This returns null, which causes no WindowsPrincipal being created. This makes it impossible to being authenticated. How can this be solved? This is my code:

@configuration https://github.com/configuration @EnableWebSecurity @EnableMethodSecurity(securedEnabled = true) @componentscan https://github.com/componentscan public class SecurityConfiguration {

@Autowired private NegotiateSecurityFilter negotiateSecurityFilter;

@Autowired private NegotiateSecurityFilterEntryPoint entryPoint;

@Bean

protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(requests -> { requests.requestMatchers("/").permitAll() .requestMatchers("/").authenticated(); }) .headers(headers -> headers .frameOptions(frameOptions -> frameOptions .sameOrigin() ) ) .addFilterAfter(negotiateSecurityFilter, BasicAuthenticationFilter.class); http.csrf(AbstractHttpConfigurer::disable);

return http.build();

}

@configuration https://github.com/configuration public class WaffleConfig {

@Bean public WindowsAuthProviderImpl waffleWindowsAuthProvider() { return new WindowsAuthProviderImpl(); }

@Bean public NegotiateSecurityFilterProvider negotiateSecurityFilterProvider( WindowsAuthProviderImpl windowsAuthProvider) { NegotiateSecurityFilterProvider negotiateSecurityFilterProvider = new NegotiateSecurityFilterProvider(windowsAuthProvider); negotiateSecurityFilterProvider.setProtocols(Arrays.asList("NTLM")); return negotiateSecurityFilterProvider; }

@Bean public BasicSecurityFilterProvider basicSecurityFilterProvider(WindowsAuthProviderImpl windowsAuthProvider) { return new BasicSecurityFilterProvider(windowsAuthProvider); }

@Bean public SecurityFilterProviderCollection waffleSecurityFilterProviderCollection( NegotiateSecurityFilterProvider negotiateSecurityFilterProvider, BasicSecurityFilterProvider basicSecurityFilterProvider) { SecurityFilterProvider[] securityFilterProviders = { negotiateSecurityFilterProvider, basicSecurityFilterProvider }; return new SecurityFilterProviderCollection(securityFilterProviders); }

@Bean public NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint( SecurityFilterProviderCollection securityFilterProviderCollection) { NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint = new NegotiateSecurityFilterEntryPoint(); negotiateSecurityFilterEntryPoint.setProvider(securityFilterProviderCollection); return negotiateSecurityFilterEntryPoint; }

@Bean public NegotiateSecurityFilter waffleNegotiateSecurityFilter(SecurityFilterProviderCollection securityFilterProviderCollection) { NegotiateSecurityFilter negotiateSecurityFilter = new NegotiateSecurityFilter(); negotiateSecurityFilter.setProvider(securityFilterProviderCollection); return negotiateSecurityFilter; }

// This is required for Spring Boot so it does not register the same filter twice @Bean public FilterRegistrationBean waffleNegotiateSecurityFilterRegistration(NegotiateSecurityFilter waffleNegotiateSecurityFilter) { FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(waffleNegotiateSecurityFilter); registrationBean.setEnabled(false); return registrationBean; }

— Reply to this email directly, view it on GitHub https://github.com/Waffle/waffle/issues/2598, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQAQND4VSTUMPESAVJ7NO3Z56D3JAVCNFSM6AAAAABQZ26VWKVHI2DSMVQWIX3LMV43ASLTON2WKOZSGYZDCMRUHAZTMMY . You are receiving this because you are subscribed to this thread.Message ID: @.***>

Eyvind-A commented 3 weeks ago

We tried what you suggested, but it did not solve the problem. I deployed the Vaadin app on a Tomcat server with a certificate, but it is still the same problem, no authorizationheader found, so no WindowsPrincipal is created. So it seems that is not caused by the network settings or the infrastructure. It seems like it a problem with the code. So how can this be solved?

Eyvind-A commented 3 weeks ago

We have another Vaadin app where all of this works. They have the same Spring Boot and Vaadin versions, the code for WaffleConfig is the same. The code for SecurityConfiguration is almost the same, except for which URL's are permitted by requestMatchers(). How can it then be that it works in one of these apps but not in the other?

Eyvind-A commented 3 weeks ago

Our Waffle code is based on this demo: https://github.com/mgoldgeier/waffle-spring-boot-demo Are there any other demos with source code? I did not find any on github.com/Waffle/waffle.

hazendaz commented 3 weeks ago

Demos are directly in the build. See source/jna/waffle-demo for all demos code.

Sent from my Verizon, Samsung Galaxy smartphone Get Outlook for Androidhttps://aka.ms/AAb9ysg


From: Eyvind-A @.> Sent: Thursday, October 31, 2024 9:10:39 AM To: Waffle/waffle @.> Cc: Subscribed @.***> Subject: Re: [Waffle/waffle] AuthorizationHeader is empty in Waffle after update to Spring Boot 3 (Issue #2598)

Our Waffle code is based on this demo: https://github.com/mgoldgeier/waffle-spring-boot-demo Are there any other demos with source code? I did not find any on github.com/Waffle/waffle.

— Reply to this email directly, view it on GitHubhttps://github.com/Waffle/waffle/issues/2598#issuecomment-2449808220, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAHODI3M54F3EY33LEFNJ6TZ6IT47AVCNFSM6AAAAABQZ26VWKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDINBZHAYDQMRSGA. You are receiving this because you are subscribed to this thread.Message ID: @.***>

pedroneil commented 3 weeks ago

Have you tried to access the toast server from the save host using your website browser.

Have you ensured that the tomcat server, certificate is importated to your windows client keystore import the pfx and that the tomcat server is truly in the intact zone.

Use postman or open your chromium ( chrome or edge) developer tools to check that the client browser is sending the WWW-Authentication header it will not send the header if your 2 servers are not in the same intranet, use the developer tools network and check.

Your error is starting that it is not receiving the header

I had all these errors before abs it was the headers not being sent from the windows client.

The other issue you may find is on the headers where your error is in the pre flight checks

Regards Peter Neil


From: Eyvind-A @.> Sent: Thursday, October 31, 2024 12:15:51 pm To: Waffle/waffle @.> Cc: PedroWS @.>; Comment @.> Subject: Re: [Waffle/waffle] AuthorizationHeader is empty in Waffle after update to Spring Boot 3 (Issue #2598)

We tried what you suggested, but it did not solve the problem. I deployed the Vaadin app on a Tomcat server with a certificate, but it is still the same problem, no authorizationheader found, so no WindowsPrincipal is created. So it seems that is not caused by the network settings or the infrastructure. It seems like it a problem with the code. So how can this be solved?

— Reply to this email directly, view it on GitHubhttps://github.com/Waffle/waffle/issues/2598#issuecomment-2449706964, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAQAQNCSFYA6OYJCY3N4OETZ6INPPAVCNFSM6AAAAABQZ26VWKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDINBZG4YDMOJWGQ. You are receiving this because you commented.Message ID: @.***>

Eyvind-A commented 3 weeks ago

Or could it be that Authentication header is empty because we use an old implementation of Waffle (not adapted to Spring Boot 3) based on https://github.com/mgoldgeier/waffle-spring-boot-demo ? Maybe this will get solved we we implement according to the new demos in source/jna/waffle-demo?

It seems like it is not possible to see authorization headers in developer tools anymore: https://stackoverflow.com/questions/78223785/browsers-dont-display-authorization-header-in-devtools I tried Fiddle, but it was not allowed by our companys security policy.

Eyvind-A commented 3 weeks ago

I found the demos on https://github.com/Waffle/waffle/tree/master/Source/JNA/waffle-demo I assume that https://github.com/Waffle/waffle/tree/master/Source/JNA/waffle-demo/waffle-spring-boot-filter3 is the only relevant demo for Spring Boot 3? I checked the SecurityConfig class and the code here makes sense. But there is no WaffleConfig class in this demo. Is this not necessary? I mean a class like this:

@Configuration public class WaffleConfig {

@Bean
public WindowsAuthProviderImpl waffleWindowsAuthProvider() {
    return new WindowsAuthProviderImpl();
}

@Bean
public NegotiateSecurityFilterProvider negotiateSecurityFilterProvider(
        WindowsAuthProviderImpl windowsAuthProvider) {
    NegotiateSecurityFilterProvider negotiateSecurityFilterProvider = new NegotiateSecurityFilterProvider(windowsAuthProvider);
    negotiateSecurityFilterProvider.setProtocols(Arrays.asList("NTLM"));
    return negotiateSecurityFilterProvider;
}

@Bean
public BasicSecurityFilterProvider basicSecurityFilterProvider(WindowsAuthProviderImpl windowsAuthProvider) {
    return new BasicSecurityFilterProvider(windowsAuthProvider);
}

@Bean
public SecurityFilterProviderCollection waffleSecurityFilterProviderCollection(
        NegotiateSecurityFilterProvider negotiateSecurityFilterProvider,
        BasicSecurityFilterProvider basicSecurityFilterProvider) {
    SecurityFilterProvider[] securityFilterProviders = {
            negotiateSecurityFilterProvider,
            basicSecurityFilterProvider };
    return new SecurityFilterProviderCollection(securityFilterProviders);
}

@Bean
public NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint(
        SecurityFilterProviderCollection securityFilterProviderCollection) {
    NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint = new NegotiateSecurityFilterEntryPoint();
    negotiateSecurityFilterEntryPoint.setProvider(securityFilterProviderCollection);
    return negotiateSecurityFilterEntryPoint;
}

@Bean
public NegotiateSecurityFilter waffleNegotiateSecurityFilter(SecurityFilterProviderCollection securityFilterProviderCollection) {
    NegotiateSecurityFilter negotiateSecurityFilter = new NegotiateSecurityFilter();
    negotiateSecurityFilter.setProvider(securityFilterProviderCollection);
    return negotiateSecurityFilter;
}

// This is required for Spring Boot so it does not register the same filter twice
@Bean
public FilterRegistrationBean waffleNegotiateSecurityFilterRegistration(NegotiateSecurityFilter waffleNegotiateSecurityFilter) {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter(waffleNegotiateSecurityFilter);
    registrationBean.setEnabled(false);
    return registrationBean;
}
Eyvind-A commented 3 weeks ago

I changed the code according to your demo (same code for SecurityConfiguration and no WaffleConfig class): https://github.com/Waffle/waffle/tree/master/Source/JNA/waffle-demo/waffle-spring-boot-filter3 but then got this error:

Parameter 0 of constructor in com.example.application.security.SecurityConfiguration required a bean of type 'waffle.spring.NegotiateSecurityFilter' that could not be found.

Eyvind-A commented 3 weeks ago

I finally got an AuthorizationHeader! I changed the SecurityConfig according to your demo and kept my WaffleConfig class.

Eyvind-A commented 3 weeks ago

filterChain method needs to be like this for Vaadin.

@Bean SecurityFilterChain filterChain(final HttpSecurity http) throws Exception { http.authorizeHttpRequests(requests -> requests.anyRequest().authenticated()) .addFilterBefore(filter, BasicAuthenticationFilter.class) .exceptionHandling(handling -> handling.authenticationEntryPoint(entryPoint)); http.csrf(AbstractHttpConfigurer::disable);// Vaadin has built-in Cross-Site Request Forgery

    return http.build();

}

http.csrf(AbstractHttpConfigurer::disable); is important!

hazendaz commented 2 weeks ago

Is waffle now working for you with spring boot 3?

Eyvind-A commented 2 weeks ago

Yes, it is! Should I close the issue?

hazendaz commented 2 weeks ago

Yes please. Thanks.

Eyvind-A commented 2 weeks ago

Solved. See https://stackoverflow.com/questions/79137109/authorizationheader-is-empty-in-waffle-after-update-to-spring-boot-3