package com.networknt.oauth.code;

import com.networknt.config.Config;
import com.networknt.health.HealthGetHandler;
import com.networknt.info.ServerInfoGetHandler;
import com.networknt.oauth.code.handler.Oauth2CodeGetHandler;
import com.networknt.oauth.code.handler.Oauth2CodePostHandler;
import com.networknt.oauth.security.LightBasicAuthenticationMechanism;
import com.networknt.oauth.security.LightGSSAPIAuthenticationMechanism;
import com.networknt.oauth.security.LightIdentityManager;
import com.networknt.handler.HandlerProvider;
import io.undertow.Handlers;
import io.undertow.security.api.AuthenticationMechanism;
import io.undertow.security.api.AuthenticationMode;
import io.undertow.security.api.GSSAPIServerSubjectFactory;
import io.undertow.security.handlers.AuthenticationCallHandler;
import io.undertow.security.handlers.AuthenticationConstraintHandler;
import io.undertow.security.handlers.AuthenticationMechanismsHandler;
import io.undertow.security.handlers.SecurityInitialHandler;
import io.undertow.security.idm.IdentityManager;
import io.undertow.security.impl.CachedAuthenticatedSessionMechanism;
import io.undertow.security.impl.FormAuthenticationMechanism;
import io.undertow.server.HttpHandler;
import io.undertow.server.session.InMemorySessionManager;
import io.undertow.server.session.SessionAttachmentHandler;
import io.undertow.server.session.SessionCookieConfig;
import io.undertow.util.Methods;

import javax.security.auth.Subject;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.networknt.oauth.spnego.KerberosKDCUtil.login;

public class PathHandlerProvider implements HandlerProvider {
    private static final String SPNEGO_SERVICE_PASSWORD = "spnegoServicePassword";
    private static final String SECRET_CONFIG = "secret";
    private static final Map<String, Object> secret = Config.getInstance().getJsonMapConfig(SECRET_CONFIG);
    private static final String spnegoServicePassword = (String)secret.get(SPNEGO_SERVICE_PASSWORD);

    @Override
    public HttpHandler getHandler() {
        final IdentityManager basicIdentityManager = new LightIdentityManager();

        HttpHandler handler = Handlers.routing()
            .add(Methods.GET, "/health", new HealthGetHandler())
            .add(Methods.GET, "/server/info", new ServerInfoGetHandler())
            .add(Methods.GET, "/oauth2/code", addGetSecurity(new Oauth2CodeGetHandler(), basicIdentityManager))
            .add(Methods.POST, "/oauth2/code", addFormSecurity(new Oauth2CodePostHandler(), basicIdentityManager))
        ;
        return handler;
    }

    private HttpHandler addFormSecurity(final HttpHandler toWrap, final IdentityManager identityManager) {
        HttpHandler handler = toWrap;
        handler = new AuthenticationCallHandler(handler);
        handler = new AuthenticationConstraintHandler(handler);
        final List<AuthenticationMechanism> mechanisms = new ArrayList<>();
        mechanisms.add(new CachedAuthenticatedSessionMechanism());
        mechanisms.add(new FormAuthenticationMechanism("oauth2", "/login", "/error", "/oauth2/code"));
        handler = new AuthenticationMechanismsHandler(handler, mechanisms);
        handler = new SecurityInitialHandler(AuthenticationMode.PRO_ACTIVE, identityManager, handler);
        handler = new SessionAttachmentHandler(handler, new InMemorySessionManager("oauth2"), new SessionCookieConfig());
        return handler;
    }

    private HttpHandler addGetSecurity(final HttpHandler toWrap, final IdentityManager identityManager) {
        HttpHandler handler = toWrap;
        handler = new AuthenticationCallHandler(handler);
        handler = new AuthenticationConstraintHandler(handler);
        List<AuthenticationMechanism> mechanisms = new ArrayList<>();
        // bypass the SPNEGO if service password is not even configured.
        if(spnegoServicePassword != null) {
            mechanisms.add(new LightGSSAPIAuthenticationMechanism(new SubjectFactory()));
        }
        mechanisms.add(new LightBasicAuthenticationMechanism("OAuth"));
        handler = new AuthenticationMechanismsHandler(handler, mechanisms);
        handler = new SecurityInitialHandler(AuthenticationMode.PRO_ACTIVE, identityManager, handler);
        return handler;
    }

    private class SubjectFactory implements GSSAPIServerSubjectFactory {
        @Override
        public Subject getSubjectForHost(String hostName) throws GeneralSecurityException {
            return login("HTTP/" + hostName, spnegoServicePassword.toCharArray());
        }
    }
}

@@ -39,35 +39,304 @@
 ort 
-com.networknt.config.Config
+static com.networknt.oauth.spnego.KerberosKDCUtil.login;%0A%0Aimport java.security.GeneralSecurityException;%0Aimport java.util.ArrayList;%0Aimport java.util.List;%0Aimport java.util.Map;%0A%0Aimport javax.security.auth.Subject;%0A%0Aimport com.networknt.config.Config;%0Aimport com.networknt.handler.HandlerProvider
 ;%0Aim
@@ -757,54 +757,9 @@
 er;%0A
-import com.networknt.handler.HandlerProvider;
 %0A
+
 impo
@@ -1648,230 +1648,8 @@
 s;%0A%0A
-import javax.security.auth.Subject;%0Aimport java.security.GeneralSecurityException;%0Aimport java.util.ArrayList;%0Aimport java.util.List;%0Aimport java.util.Map;%0A%0Aimport static com.networknt.oauth.spnego.KerberosKDCUtil.login;%0A%0A
 publ
@@ -1847,16 +1847,74 @@
 ecret%22;%0A
+    private static final String SERVER_CONFIG = %22server%22;%0A
     priv
@@ -2013,16 +2013,131 @@
 ONFIG);%0A
+    private static final Map%3CString, Object%3E server = Config.getInstance().getJsonMapConfigNoCache(SERVER_CONFIG);%0A
     priv
@@ -2451,17 +2451,42 @@
 %22/health
-%22
+/%22+server.get(%22serviceId%22)
 , new He
@@ -3655,24 +3655,33 @@
 eConfig());%0A
+        %0A
         retu
@@ -4392,32 +4392,32 @@
 r, mechanisms);%0A
-
         handler 
@@ -4495,32 +4495,41 @@
 ager, handler);%0A
+        %0A
         return h

fix oauth2-code health check path - #160 (#161)