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

NTLM Negotiation with Zuul Reverse Proxy #543

Open
aminmc opened this issue Jul 17, 2017 · 1 comment
Open

NTLM Negotiation with Zuul Reverse Proxy #543

aminmc opened this issue Jul 17, 2017 · 1 comment

Comments

@aminmc
Copy link

aminmc commented Jul 17, 2017

Hello there

I have a backend service that is secured and I have a client app that uses Zuul to do reverse proxy look up. I'm using Waffle to identify who the currently logged in user is on the client and I would like to pass the client token to the back end service. Is there any programmatic way to enable the negotiation between the client code and the server? I've tried using the token from WindowsSecurityContextImpl but this is obviously not enough.

Spring Zuul comes with a filter than allows you to intercept the request before forwarding it to the target.

Any help would be appreciated.

Thanks

@ljluestc
Copy link

Step 2: Add Dependencies
Ensure you have the necessary dependencies in your pom.xml for Spring Cloud Zuul and Waffle (for NTLM support):

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
    <groupId>com.github.waffle</groupId>
    <artifactId>waffle-jna</artifactId>
    <version>3.0.0</version>
</dependency>

Run HTML
Step 3: Configure Zuul Proxy
Configure Zuul in your application.yml or application.properties:

zuul:
  routes:
    backend:
      path: /backend/**
      url: http://backend-service-url

Step 4: Implement a Zuul Filter for NTLM Negotiation
Create a custom Zuul filter to handle the NTLM authentication flow. This filter will intercept requests and responses to manage the NTLM handshake.

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import waffle.windows.auth.IWindowsAuthProvider;
import waffle.windows.auth.IWindowsIdentity;
import waffle.windows.auth.IWindowsSecurityContext;
import waffle.windows.auth.impl.WindowsAuthProviderImpl;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class NtlmAuthFilter extends ZuulFilter {

    private final IWindowsAuthProvider authProvider = new WindowsAuthProviderImpl();

    @Override
    public String filterType() {
        return "pre"; // Intercept requests before routing
    }

    @Override
    public int filterOrder() {
        return 1; // Set the order of the filter
    }

    @Override
    public boolean shouldFilter() {
        return true; // Apply this filter to all requests
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        HttpServletResponse response = ctx.getResponse();

        try {
            // Extract NTLM token from the request
            String authHeader = request.getHeader("Authorization");
            if (authHeader != null && authHeader.startsWith("NTLM")) {
                // Handle NTLM authentication
                byte[] token = java.util.Base64.getDecoder().decode(authHeader.substring(5));
                IWindowsSecurityContext securityContext = authProvider.acceptSecurityToken(token, "HTTP/" + request.getServerName());

                if (securityContext.isContinue()) {
                    // Send the challenge back to the client
                    response.setHeader("WWW-Authenticate", "NTLM " + java.util.Base64.getEncoder().encodeToString(securityContext.getToken()));
                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                    ctx.setSendZuulResponse(false); // Stop forwarding the request
                } else {
                    // Authentication successful
                    IWindowsIdentity identity = securityContext.getIdentity();
                    ctx.addZuulRequestHeader("X-Windows-User", identity.getFqn());
                    identity.dispose();
                }
            } else {
                // Request NTLM authentication
                response.setHeader("WWW-Authenticate", "NTLM");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                ctx.setSendZuulResponse(false); // Stop forwarding the request
            }
        } catch (Exception e) {
            ctx.setSendZuulResponse(false);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            e.printStackTrace();
        }

        return null;
    }
}

Step 5: Register the Filter
Register the custom filter in your Spring Boot application:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableZuulProxy
public class ZuulNtlmApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZuulNtlmApplication.class, args);
    }

    @Bean
    public NtlmAuthFilter ntlmAuthFilter() {
        return new NtlmAuthFilter();
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants