-1

I am trying to create a service using golang that will listen on a port for a post request containing json and would like to parse out the username and password fields of the json and save those as variables to be used outside of the function to authenticate to Active Directory. I am using the HandleFunc() fucntion, but cannot ficure out how to access the variables outside of the function. I tried creating a return, but it wouldn't build. How do I properly create the variables and then use them outside of the function?

 package main

 import (
         "gopkg.in/ldap.v2"
         "fmt"
         "net/http"
         "os"
         "encoding/json"
         "log"
         "crypto/tls"
         "html"

 )

 type Message struct {
     User string 
     Password string 
 }

 func main() {
     const SERVICE_PORT = "8080"


     var uname string
     var pwd string

     LDAP_SERVER_DOMAIN := os.Getenv("LDAP_DOM")
     if LDAP_SERVER_DOMAIN == "" {
        LDAP_SERVER_DOMAIN = "192.168.10.0" 
     }


     //Handle Http request and parse json
     http.HandleFunc("/", func(w http.ResponseWriter, request *http.Request) {
            var m Message

            if request.Body == nil {
            http.Error(w, "Please send a request body", 400)                
            return
            }

            err := json.NewDecoder(request.Body).Decode(&m)
            if err != nil {
                http.Error(w, err.Error(), 400)
                return
            }
            // Not sure what to do here
            uname = m.User
            pwd = m.Password
        })

     log.Fatal(http.ListenAndServe(":" + SERVICE_PORT, nil))

     connected := ldapConn(LDAP_SERVER_DOMAIN, uname, pwd)

     if connected == true {
        fmt.Println("Connected is", connected)
     }


 }


// Connects to the ldap server and returns true if successful
 func ldapConn(dom, user, pass string) bool {
    // For testing go insecure
    tlsConfig := &tls.Config{InsecureSkipVerify: true}

    conn, err := ldap.DialTLS("tcp", dom, tlsConfig)
    if err != nil {
        // error in connection
        log.Println("ldap.DialTLS ERROR:", err)

        //debug
        fmt.Println("Error", err)

        return false
    }
    defer conn.Close()
    err = conn.Bind(user, pass)
    if err != nil {
        // error in ldap bind
        log.Println(err)

        //debug
        log.Println("conn.Bind ERROR:", err)

        return false
    }
    return true
}
antman1p
  • 514
  • 2
  • 11
  • 25
  • 1
    This doesn't make sense for a couple reasons. The `ldapConn` function will get called before your handler, so those variables won't be set. This also doesn't try to take into account what happens with concurrent calls to the handler. Just declare the variables and call the auth function in the handler. You also don't have an http server, so nothing could call your handler, and your program just exits. – JimB Jan 25 '17 at 14:52
  • I'm just listening on Localhost. When I curl local host with a json my handler is picking it up just fine. I don't seem to be able to call any functions inside the handler. When I try a simple fmt.PrintLn I get nothing in the console. – antman1p Jan 25 '17 at 14:56
  • sorry, I missed the ListenAndServe, so you have an http server, so you never get to the `ldapConn` call because you're blocking there. function calls work exactly the same in a handler as anywhere else, you'll have to show an example of what's not working for you. – JimB Jan 25 '17 at 14:59
  • I seriously just got it to start allowing fmt.Println() inside of the handler. Grrrr.... ok. I am going to move my function calls to LDAP inside of the handler and try that now. – antman1p Jan 25 '17 at 15:08
  • Make sure you move the associated variable declarations inside the handler as well to avoid the race conditions. – JimB Jan 25 '17 at 15:10
  • It worked. Thanks for your help. Now I need to figure out how to use those variables to authenticate to AD and return the user's groups. – antman1p Jan 25 '17 at 15:17

2 Answers2

1

You can't access the variables not because Go namespaces not allow it but because ListenAndServe is blocking and ldapConn could be called only if the server is stopped.

 log.Fatal(http.ListenAndServe(":" + SERVICE_PORT, nil))
 // Blocked until the server is listening and serving.

 connected := ldapConn(LDAP_SERVER_DOMAIN, uname, pwd)

A more correct approach is to call ldapConn inside http.HandleFunc callback.

 http.HandleFunc("/", func(w http.ResponseWriter, request *http.Request) {
        var m Message

        if request.Body == nil {
            http.Error(w, "Please send a request body", 400)                
            return
        }

        err := json.NewDecoder(request.Body).Decode(&m)
        if err != nil {
            http.Error(w, err.Error(), 400)
            return
        }

        connected := ldapConn(LDAP_SERVER_DOMAIN, m.User, m.Password)
        if connected == true {
            fmt.Println("Connected is", connected)
        }
 })

 log.Fatal(http.ListenAndServe(":" + SERVICE_PORT, nil))
I159
  • 29,741
  • 31
  • 97
  • 132
0

How do I get the HandleFunc() function to parse a json into variables accesible outside of the function?

from your question I don't think you can return the json value here. Instead you could pass the struct to a function and call them inside it. for example :

//Handle Http request and parse json
     http.HandleFunc("/", func(w http.ResponseWriter, request *http.Request) {
            var m Message

            if request.Body == nil {
            http.Error(w, "Please send a request body", 400)                
            return
            }

            err := json.NewDecoder(request.Body).Decode(&m)
            if err != nil {
                http.Error(w, err.Error(), 400)
                return
            }
            // Not sure what to do here
            // pass the variable to your function
            uname = m.User
            pwd = m.Password

            // passed your struct to a function here and do your logic there.
            yourFunction(m)
        })

and you can write yourFunction(m Message) in another package or the same package as you define your handler. for example writing yourFunction() would be :

func yourFunction(m Message){
   // do your logic here
}

if function is in another package

//call your package where your struct is defined.
func yourFunction(m main.Message){
   // do your logic here
}

as JimB said. You're calling your ldapConn after ListenAndServe those lines would never be executed since it is blocked.

and if you like to print your app is started or failed. I think this code will help you :

    log.Println("App started on port = ", port)
    err := http.ListenAndServe(":"+port, nil)
    if err != nil {
        log.Panic("App Failed to start on = ", port, " Error : ", err.Error())
    }
Community
  • 1
  • 1
Gujarat Santana
  • 9,854
  • 17
  • 53
  • 75
  • All http handlers are inherently concurrent. You cannot access global variables without synchronization from within an http handler. – JimB Jan 25 '17 at 15:09
  • @JimB sorry I have edited my answer since it was really late for me so I dont have much time to edit it. yeah it was a mistake – Gujarat Santana Jan 25 '17 at 22:39