Waffle / waffle

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

SpringBoot Starter #360

Closed hazendaz closed 6 years ago

hazendaz commented 8 years ago

Spring boot is all the rage now. It shouldn't be too difficult to sping up a spring boot starter for waffle. I'm just getting started with spring boot so any help here would be appreciated.

unaor commented 8 years ago

After much struggle i managed to get it to work spring boot way let me know if you need code share or something for documentation porpuses

hazendaz commented 8 years ago

Definately interested. Please raise a pull request adding to our documentation.

Get Outlook for Androidhttps://aka.ms/ghei36

On Wed, Aug 17, 2016 at 11:18 AM -0400, "unaor" notifications@github.com<mailto:notifications@github.com> wrote:

After much struggle i managed to get it to work spring boot way let me know if you need code share or something for documentation porpuses

You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/dblock/waffle/issues/360#issuecomment-240445694, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AA7hoz5VSu_4ukfiosP-28UCgQDMnhiHks5qgyY_gaJpZM4IpMRD.

pataluc commented 7 years ago

definitely interested too... unaor, could you share parts of your code please?

thx

unaor commented 7 years ago

sure, two points to add since its a spring boot specific code 1.its production ready i've created two configuration classes 2.its not working properly with the embedded tomcat, the issue is mentioned on the google group

`@Configuration public class SwatWaffleConfig {

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

@Bean
public NegotiateSecurityFilterProvider negotiateSecurityFilterProvider(
        WindowsAuthProviderImpl waffleWindowsAuthProvider) {
    NegotiateSecurityFilterProvider filter = new NegotiateSecurityFilterProvider(waffleWindowsAuthProvider);
    return filter;
}

@Bean
public SecurityFilterProviderCollection waffleSecurityFilterProviderCollection(
        NegotiateSecurityFilterProvider waffleFilter) {
    SecurityFilterProvider[] providerArray = new SecurityFilterProvider[1];
    // first provider to use the waffle later we can add more
    providerArray[0] = waffleFilter;
    SecurityFilterProviderCollection filterCollection = new SecurityFilterProviderCollection(providerArray);
    return filterCollection;
}

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

@Bean
public NegotiateSecurityFilter waffleNegotiateSecurityFilter(
        SecurityFilterProviderCollection waffleSecurityFilterProviderCollection) {
    NegotiateSecurityFilter filter = new NegotiateSecurityFilter();
    filter.setProvider(waffleSecurityFilterProviderCollection);
    filter.setAllowGuestLogin(false);
    return filter;
}

}`

main security class

`@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled = true) public class SwatSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
NegotiateSecurityFilterEntryPoint entryPoint;

@Autowired
NegotiateSecurityFilter waffleFilter;

@Value("${swat.allowed-roles}")
private String [] allowedRoles;

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.exceptionHandling().authenticationEntryPoint(entryPoint).and()
            .addFilterBefore(waffleFilter, UsernamePasswordAuthenticationFilter.class);

    http.authorizeRequests().antMatchers("/dashboard").hasAnyAuthority(allowedRoles);

    http.authorizeRequests().antMatchers("/api/read/**").hasAnyAuthority(allowedRoles);

    http.authorizeRequests().antMatchers("/**").denyAll();

    http.csrf().disable().httpBasic().disable()
    .rememberMe().disable().headers().disable()
    .x509().disable().anonymous().disable();

    http.exceptionHandling().accessDeniedPage("/403");

}

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/dist/*.js", "/dist/assets/**", "/dist/favicon.ico", "/dist/index.html", "/dist/*.woff", "/dist/*.woff2", "/dist/*.ttf");
}

} `

pataluc commented 7 years ago

thanks a lot. I'm gonna dig in and try to make this work... ;)

unaor commented 7 years ago

Sure, if you need help let me know

mgoldgeier commented 7 years ago

I don't have a Spring Boot "Starter" JAR, but here is a simple demo that sets up Spring Boot, Spring Security, and Waffle: https://github.com/mgoldgeier/waffle-spring-boot-demo

mstittle commented 7 years ago

i notices a auth header being sent even after the initial authentication is successful. I tested with this setting mentioned below and the problem when away. This is not a solution that I use going forward.

https://support.microsoft.com/en-us/help/2749007/an-unexpected-401.1-status-is-returned-when-using-pre-authentication-headers-with-internet-explorer-and-internet-information-services

On Thu, Jan 19, 2017 at 12:04 PM, Mike notifications@github.com wrote:

I don't have a Spring Boot "Starter" JAR, but here is a simple demo that sets up Spring Boot, Spring Security, and Waffle: https://github.com/mgoldgeier/waffle-spring-boot-demo

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/Waffle/waffle/issues/360#issuecomment-273834953, or mute the thread https://github.com/notifications/unsubscribe-auth/AAhh8q3iR9nJVJI3HNhKpUbzirngAXyxks5rT5eQgaJpZM4IpMRD .

-- mike stittleburg

unaor commented 7 years ago

@mstittle could you please elaborate on this?

mgoldgeier commented 7 years ago

I have managed to put a Spring Boot Waffle Starter together... if I can find time to get a waffle dev environment set up, I might be able to add the code to the waffle repo. I assume nobody else has done any work on this yet?

mgoldgeier commented 7 years ago

I'm not sure if this is ready for a pull request yet, but I forked and added a Spring Boot Starter to the project. Needs documentation and tests (though not a ton to unit test here, I think).

https://github.com/mgoldgeier/waffle/tree/spring-boot

I can post a sample using this starter in a Spring Boot project. The one gotcha is a possible version conflict with JNA if using Spring Boot dependency version management.

hazendaz commented 7 years ago

@mgoldgeier Looking good. If you can build a sample out maybe under our demos packaging that would be great.

Can you elaborate on the jna issue? Are we ahead or behind springboot? I know 4.4.0 is out last I checked but not sure if I applied here yet or not or if that means we are ahead of springboot. We don't have any hard dependency on a recently released specific version so as long as we don't get conflicting versions we should be fine.

mgoldgeier commented 7 years ago

Spring Boot provides dependency versions for each release. They are currently specifying 4.2.2 for jna, while the waffle snapshot I was working off of specified 4.4.0. Using 4.2.2 was throwing an exception in waffle, but if I forced 4.4.0 in my pom (just define property jna.version), everything seemed to work ok. I'm not sure what components of Spring Boot use jna; my project was using 4.2.2 due to Spring Boot's dependency management in maven.

Current versions listed here: http://docs.spring.io/spring-boot/docs/current/reference/html/appendix-dependency-versions.html

I'll try to get a sample put together when I get a chance.

hazendaz commented 7 years ago

I recall some changes I needed to make that must have been 4.3+ around waffle-tests and a few other areas. We may have to account for this situation once we get an official supported starter here. When I get some time I'll go back and look at what I had changed and see if there are any better ways to handle it so the older version can still work.

aminmc commented 7 years ago

@mgoldgeier I've used your approach and works however I get an unauthorized exception if I try to POST to an endpoint. Is there any additional configuration that I need?

mgoldgeier commented 7 years ago

@aminmc What is it that you are using? My demo code? Your issue doesn't seem waffle-related if the GET method works ok.

It sounds suspicious of a CSRF configuration issue. You can disable CSRF protection in Spring Security by adding http.csrf().disable() under the security configuration as a quick test to see if that's your problem.

aminmc commented 7 years ago

Hi @mgoldgeier disabling csrf did the trick using your demo code. Thanks very much!

aminmc commented 7 years ago

Hi @mgoldgeier sorry to bring this up here but I'm seeing: com.sun.jna.platform.win32.Win32Exception: The token supplied to the function is invalid Have you seen this before? I'm following the demo code and it works when run the application locally but when I run the app on a remote server I start seeing the exception. The browser keeps showing me the login/password even though I've added my credentials correctly.

Thanks

unaor commented 7 years ago

I had this error and suffered greatly due to it I noticed that in my case it was happening even though the user was already identified, so it made no sense can you verify if its your case? ill share the solution i used

aminmc commented 7 years ago

yep the same. The thing that annoyed me was that locally it works and then sometimes it works on our development environment and then it stops and i'm prompted with the username/password and no matter how many times I enter my credentials it keeps showing me the prompt.

unaor commented 7 years ago

ok its not the most pretty solution i hope some member can make it better ,but it will take care of this issue

override the NegotiateSecurityFilter in the spring package and change the following:

catch (final IOException e) {
      NegotiateSecurityFilter.LOGGER.warn("error logging in user: {}", e.getMessage());
      NegotiateSecurityFilter.LOGGER.trace("", e);
      this.sendUnauthorized(response, true);
      return;
 }

to

SwatNegotiateFilter.LOGGER.warn("error logging in user: {}", e.getMessage());
SwatNegotiateFilter.LOGGER.trace("", e);
if(e.getMessage().equals(TOKEN_ERROR) && request.getUserPrincipal() != null && 
        request.getUserPrincipal().getName() != null){
                    LOGGER.debug("Ignoring token error for authenticated user: " +   
                        request.getUserPrincipal().getName());
                chain.doFilter(request, response);
                    return; 
 }
else {
        this.sendUnauthorized(response, true);
         return;
}
aminmc commented 7 years ago

Thanks @unaor Are there any side effects of doing this? Any negative impact?

unaor commented 7 years ago

basically im checking that there is an authenticated user in the request , and if there is im continuing the filter, so i don't think its a security hole. But the truth is that though i tried, i wasn't able to understand why the exception is being thrown if the user is already identified, maybe @hazendaz could shed a light

mgoldgeier commented 7 years ago

@aminmc @unaor Yes, I've had this same error and have posted about it previously. For me, it would only happen when using IE. Someone previously pointed out that in my case, I was registering the negotiate filter twice inadvertently. Spring Boot automatically registers any class that you have on the classpath that is a type Filter. In my demo project, I had added code:

    @Bean
    public FilterRegistrationBean waffleNegotiateSecurityFilterRegistration(NegotiateSecurityFilter waffleNegotiateSecurityFilter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(waffleNegotiateSecurityFilter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

This prevents the automatic registration of the filter and prevents it from being registered twice. Can you confirm that you are doing this? If you are, and still see the error, than I mistakenly thought this solved the problem.

unaor commented 7 years ago

@mgoldgeier in my case it was happening with all browsers- IE,Chrome and firefox I added the bean you suggested and it seems that it fixed the issue for me

hazendaz commented 7 years ago

Glad it all worked! We need to get all this information over into FAQ. I don't have a lot of time right now but if someone wants to contribute doing that I'll merge it in. Thanks.

kbdguy commented 7 years ago

@mgoldgeier thanks for the great simple test for spring boot... works with waffle 1.8.2. I tried using with waffle 1.8.3 and get an error on every client-connect attempt.... any clues? java.lang.NoSuchMethodError: com.sun.jna.platform.win32.Sspi$SecHandle.createFieldsOrder([Ljava/lang/String;)Ljava/util/List; at com.sun.jna.platform.win32.Sspi$SecHandle.<clinit>(Sspi.java:263) ~[jna-platform-4.3.0.jar!/:4.3.0 (b0)] at waffle.windows.auth.impl.WindowsCredentialsHandleImpl.initialize(WindowsCredentialsHandleImpl.java:82) ~[waffle-jna-1.8.3.jar!/:1.8.3] at waffle.windows.auth.impl.WindowsAuthProviderImpl.acceptSecurityToken(WindowsAuthProviderImpl.java:117) ~[waffle-jna-1.8.3.jar!/:1.8.3] at waffle.servlet.spi.NegotiateSecurityFilterProvider.doFilter(NegotiateSecurityFilterProvider.java:143) ~[waffle-jna-1.8.3.jar!/:1.8.3] at waffle.servlet.spi.SecurityFilterProviderCollection.doFilter(SecurityFilterProviderCollection.java:148) ~[waffle-jna-1.8.3.jar!/:1.8.3] at waffle.spring.NegotiateSecurityFilter.doFilter(NegotiateSecurityFilter.java:104) ~[waffle-spring-security4-1.8.3.jar!/:1.8.3]

mgoldgeier commented 7 years ago

@kbdguy It is probably a version conflict of the JNA library. Be aware that Spring Boot dependency management specifies versions of a whole bunch of external libraries, one of which is JNA. Check to see what version of JNA Spring is specifying and what version Waffle is specifying and I suspect you'll find the problem. You can try forcing the version. I'm not sure what part of Spring uses that library.

See: https://github.com/spring-projects/spring-boot/blob/master/spring-boot-dependencies/pom.xml

kbdguy commented 7 years ago

@mgoldgeier thanks, and I think you put me on the right track. I looked, and I actually don't think my (your!) spring boot dependencies are calling for jna at all. I'm somewhat inexperienced with maven and never really wandered into the weeds of it, but I think there is a problem with what maven central gives me when I ask for waffle-spring-security4. According to what IntelliJ IDEA tells me after it imports all my pom.xml dependencies, waffle-spring-security4 brings in dependency waffle-jna ver 1.8.3, and waffle-jna calls for both jna-platform ver 4.3.0 AND jna ver 4.2.2. So... that seemed fishy to me, so I edited my pom like this to get jna ver 4.3.0 instead of 4.2.2:

com.github.waffle waffle-spring-security4 ${waffle.version} net.java.dev.jna jna
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna</artifactId>
        <version>4.3.0</version>
    </dependency>

and that worked, exception gone!

So do you think this is an error in the way waffle-jna ver 1.8.3 is set up in maven central?

hazendaz commented 7 years ago

@kbdguy Spring boot was on jna 4.2.2. Due to how maven resolves things, it's quite easily mixed up depending on order that spring boot is sitting in along with waffle and if spring boot called it in dependency management which I suspect they did. There was no issue with waffle-jna 1.8.3 in this regard. Technically speaking you should be able to remove your exclusions but will still need to keep the call out on jna that you did. However, there could be some issues in springboot depending where jna is used. I believe with jna 4.3.0 there were some deprecations which I applied in waffle. So that would abviously cause those 4.2.2 issues. Probably a better thing to do here would be to go track down the spring boot module using jna and get them to upgrade. This is the second project I've seen this same issues with spring boot, jna, and project usage. The core issue is jna and what they did under the hood. I think they were restoring or fixing things in 4.4.0.

kbdguy commented 7 years ago

@hazendaz Thanks... I see now that jna 4.2.2 is coming in via the parent pom, org.springframework.boot. Frustrating... I tried explicitly including your lower-level waffle-jna as the project's dependency because at least I could have kept the version number 1.8.3 consistent... but no dice. You are correct, the exclusion in my earlier attempt was not necessary; it works fine just by explicitly including the jna v 4.3.0 dependency in my project. So I guess we have to keep an eye on the waffle jna version vs. Spring boot's and fix it up like this until Spring boot changes.

Anyway, it is great to get waffle working within Spring Boot, even if this hoop has to be jumped through.

hazendaz commented 7 years ago

Glad it is working. We will try to stick a bit closer to springboot in the future. Thanks for confirming what was necessary here for others to see.

kbdguy commented 7 years ago

Update: I had another jna-version-related problem when I added spring-boot-devtools to the project. At start-up would get error "...\net\java\dev\jna\jna-platform\4.3.0\lib\test-classes' must exist and must be a directory" When I upgraded the spring parent pom version to 1.5.4.RELEASE (latest release as of today), the problem went away.

hazendaz commented 7 years ago

Is it possible that anyone that has been working with springboot could generously provide us a demo app to add to our demo package that takes full advantage of showing how this works with springboot as well as getting content from here into our docs? I'd love to have that before I cut the first officially fullly java 8 version which I'd like to do within next month.

mgoldgeier commented 7 years ago

Sorry to say I haven't had a chance to finish up what I started on the spring boot stuff. I'm not actively using spring boot anymore either. For anyone who wants to pick it up, I did some work in a fork. If I do get a chance, I'll let you know.

unaor commented 7 years ago

Dont we already have a spring boot working example? I can provide mine if needed

hazendaz commented 7 years ago

@unaor We do but only in so much as part of this issue thread. What I'd like is for a demo to get added to the demo portion of the project. And extra points if we can get a waffle-springboot-starter. No rush or anything. I've gotten tied up in other things (moving recently) so not a lot of time to dedicate to github ;)

mgoldgeier commented 7 years ago

I had done a lot of work on a Spring Boot Starter off a fork here: https://github.com/mgoldgeier/waffle/tree/spring-boot/Source/JNA/waffle-spring-boot ... Really, it just needs to be documented, demo added, and merged. I haven't had any time to finish this up, but someone should pick it up from there if they can.

hazendaz commented 7 years ago

@mgoldgeier Awesome! Since this is just on your fork even if not fully documented, can you submit it as a pull request? I'll accept it then we can just work it from the core. Nothing wrong with bringing in work in progress ;)

hazendaz commented 7 years ago

@mgoldgeier I have cherry picked your commit, updated to springboot 1.5.7.RELEASE and I'm in process of merging to this repo. Thank you so much for the work. Anything else needed can just be added as time permits.

mgoldgeier commented 7 years ago

@hazendaz Awesome. Sorry I never got around to creating a PR.

hazendaz commented 7 years ago

No worries! Thanks for making the code available. I really appreciate it.

hazendaz commented 6 years ago

Closing as completed on master.

yeshwanthreddybeeram commented 6 years ago

can i know how you did sso login from using it