gogatekeeper / gatekeeper

An OpenID / Proxy service
https://gogatekeeper.github.io/gatekeeper/
Apache License 2.0
253 stars 43 forks source link

I want gatekeeper to be able to logon to a ASPX page #435

Closed dsputnikk closed 3 months ago

dsputnikk commented 3 months ago

Title

I want gatekeeper to be able to logon to a ASPX page

Summary

I am using gogatekeeper in front of a old aspx.cs site. I want it to hit login.aspx on behalf of client, login, produce a sessionId and feed it back to client. This is mostly working (I have modified code in this repo to fetch the existing sessionId for every relevant request), except I can't figure out how to make the initial upstream request to "/" or "/login.aspx" to go ahead and redirect to "/pageafterauth.aspx". If I try to repoint it in the middleware.go func entrypointMiddleware with something like resp.WriteHeader(http.StatusFound) - I end up intercepting too early and oauth call backs stop working.

Why?

To make keycloak work w/ ancient app

How

I know this is ugly but, I have this in func entrypointMiddleware (don't yell at me)

This POST is a bit useless, bu

if req.Method == "POST" {
    // Access form data
    username := req.FormValue("ctl00$ContentPlaceHolder1$txtUsername")
    password := req.FormValue("ctl00$ContentPlaceHolder1$txtPassword")

    if len(username) > 0 {

    var admId = getAdministratorIdByName(username, cfg.ASPXIntegration_AdministratorsRoute)
    logger.Info("AdmID in table is: " + admId)

    var existingSession = getASPXSession(admId, cfg.ASPXIntegration_SessionRoute)
    logger.Info("Found existing session: " + existingSession.SessionID + " Expired?: " + strconv.FormatBool(existingSession.IsExpired))

    var sessionID string
    var sessionCookie http.Cookie

    //if there isn't an existing session!!!!!!!!!!!
    if existingSession == (SessionResponse{}) || existingSession.IsExpired == true {
        if strings.HasPrefix(req.URL.Path, "/login.aspx") || req.URL.Path == "/" {
            logger.Info("HTTP Path and Method match a POST on login page. Client is requesting login page")
            sessionID = loginASPXsite(username, password, cfg.ASPXIntegration_LoginPage)
        }
    } else {
        logger.Info("Session not expired per SQL. Use it!")
        //Appears to be an existing session. Use it!
        sessionID = existingSession.SessionID
    }

    // Set the value of sessionCookie response if sessionID is not empty
    if sessionID != "" {
        // Create a new cookie with session ID
        sessionCookie = http.Cookie{
            Name:  "ASP.NET_SessionId",
            Value: sessionID,
            Path:  "/",
        }
        http.SetCookie(resp, &sessionCookie)
    }
    }
    resp.Header().Set("Referer", "http://app.mydomain.com3000/login.aspx") 

    // I WANT TO DO SOMETHING LIKE 
   //  resp.WriteHeader(http.StatusFound)
   //  resp.Header().Set("Location", "/dashboard.aspx?a=login")       //(This is the landing page after aspx auth

    }

And a GET version (technically this is the one I care about. Once my modified gatekeeper posts the form and fetches a sessionId, the browser goes back to GET login.aspx and instead I need to redirect the browser to GET dashboard.aspx except with my sessionId cookie attached.

if req.Method == "GET" {
    //Get username from context
    user, err := getIdentity(req, "kc-access", "")

    if err != nil {
        scope.Logger.Error(err.Error())
    }
    logger.Info("User1: ", zap.Any("user", user))

    username := user.Name

    if len(username) > 0 {

        var admId = getAdministratorIdByName(username, cfg.ASPXIntegration_AdministratorsRoute)
        logger.Info("AdmID in table is: " + admId)

        var existingSession = getASPXSession(admId, cfg.ASPXIntegration_SessionRoute)
        logger.Info("Found existing session: " + existingSession.SessionID + " Expired?: " + strconv.FormatBool(existingSession.IsExpired))

        var sessionID string
        var sessionCookie http.Cookie

        if there IS
        if existingSession.SessionID != "" && existingSession.IsExpired == false {

            if strings.HasPrefix(req.URL.Path, "/login.aspx") || req.URL.Path == "/" {
                logger.Info("HTTP Path and Method match a GET on login page. Client is requesting login page and we have an existing unexpired session ID. Use it!: " + existingSession.SessionID)
                sessionID = existingSession.SessionID

                Set the value of sessionCookie response if sessionID is not empty
                if sessionID != "" {
                    Create a new cookie with session ID
                    sessionCookie = http.Cookie{
                        Name:  "ASP.NET_SessionId",
                        Value: sessionID,
                        Path:  "/",
                    }
                    http.SetCookie(resp, &sessionCookie)
                }
                resp.Header().Set("Referer", "http://app.mydomain.com:3000/login.aspx") 
                resp.WriteHeader(http.StatusFound)  //THIS GETS PICKED UP ON BROWSER WHEN I TEST BUT ITS MAKING BROWSER HANG ON CALLING /auth/ocallback
                resp.Header().Set("Location", "/dashboard.aspx?a=login")

            }

        }

    }
}

Any hints? Racking my brain

p53 commented 3 months ago

@dsputnikk maybe i would create separate service for Loggin-in and redirecting to proper /path which would be located behing same ingress, e.g. nginx --> /login --> your logging-in service --> your aspx --> response to your logging-in service -->your logging-in service redirect to /dashboard -> service same vhost nginx --> match /dashboard + other paths -->gogatekeeper --> your aspx service

dsputnikk commented 3 months ago

@dsputnikk maybe i would create separate service for Loggin-in and redirecting to proper /path which would be located behing same ingress, e.g. nginx --> /login --> your logging-in service --> your aspx --> response to your logging-in service -->your logging-in service redirect to /dashboard -> service same vhost nginx --> match /dashboard + other paths -->gogatekeeper --> your aspx service

Is there anyway to expose/work with the credential stored in keycloak (even if in encrypted form?) inside of this project?

p53 commented 3 months ago

If I understand correctly you want to get aspx page cookies before keycloak login page, then login through you can set path to which you are redirect after login with post-login-redirect parameter of gatekeeper, you don't need to do it here in middleware. If I don't understand what flow you would like to achieve please describe it step by step, thx

dsputnikk commented 3 months ago

I want to have gatekeeper perform a POST to a /createsession endpoint on behalf of the client

On Mon, Mar 18, 2024, 11:06 PM p53 @.***> wrote:

If I understand correctly you want to get aspx page cookies before keycloak login page, then login through you can set path to which you are redirect after login with post-login-redirect parameter of gatekeeper, you don't need to do it here in middleware. If I don't understand what flow you would like to achieve please describe it step by step, thx

— Reply to this email directly, view it on GitHub https://github.com/gogatekeeper/gatekeeper/issues/435#issuecomment-2005240998, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADHRFULKV475ZRBLWPD62SDYY5XQXAVCNFSM6AAAAABE3TRL62VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMBVGI2DAOJZHA . You are receiving this because you were mentioned.Message ID: @.***>