GithubHelp home page GithubHelp logo

kerby's Introduction

Kerby - Go wrapper for Kerberos GSSAPI

Godoc

This is a port of the PyKerberos library in Go. The main motivation for this library was to provide HTTP client authentication using Kerberos. The khttp package provides a transport that authenticates all outgoing requests using SPNEGO (negotiate authentication) http://tools.ietf.org/html/rfc4559.

The C code is adapted from PyKerberos http://calendarserver.org/wiki/PyKerberos.

Usage

Note: You need the have the krb5-libs/GSSAPI packages installed for your OS.

Install using go tools:

$ go get github.com/ubccr/kerby

To run the unit tests you must have a valid Kerberos setup on the test machine and you should ensure that you have valid Kerberos tickets (run 'klist' on the command line). If you're authentication using a client keytab file you can optionally export the env variable KRB5_CLIENT_KTNAME:

$ export KRB5_CLIENT_KTNAME=/path/to/client.keytab
$ export KERBY_TEST_SERVICE="service@REALM"
$ export KERBY_TEST_PRINC="princ@REALM"
$ go test

Example HTTP Kerberos client authentication using a client keytab file:

package main

import (
    "fmt"
    "io/ioutil"
    "bytes"
    "net/http"

    "github.com/ubccr/kerby/khttp"
)

func main() {
    payload := []byte(`{"method":"hello_world"}`)
    req, err := http.NewRequest(
        "POST",
        "https://server.example.com/json",
        bytes.NewBuffer(payload))

    req.Header.Set("Content-Type", "application/json")

    t := &khttp.Transport{
        KeyTab: "/path/to/client.keytab",
        Principal: "principal@REALM"}

    client := &http.Client{Transport: t}

    res, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()

    data, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }

    fmt.Printf("%d\n", res.StatusCode)
    fmt.Printf("%s", data)
}

Example HTTP handler supporting Kerberose authentication:

func handler(w http.ResponseWriter, req *http.Request) {
    authReq := strings.Split(req.Header.Get(authorizationHeader), " ")
    if len(authReq) != 2 || authReq[0] != negotiateHeader {
        w.Header().Set(wwwAuthenticateHeader, negotiateHeader)
        http.Error(w, "Invalid authorization header", http.StatusUnauthorized)
        return
    }

    ks := new(kerby.KerbServer)
    err := ks.Init("")
    if err != nil {
        log.Printf("KerbServer Init Error: %s", err.Error())
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    defer ks.Clean()


    err = ks.Step(authReq[1])
    w.Header().Set(wwwAuthenticateHeader, negotiateHeader+" "+ks.Response())

    if err != nil {
        log.Printf("KerbServer Step Error: %s", err.Error())
        http.Error(w, err.Error(), http.StatusUnauthorized)
        return
    }

    user := ks.UserName()
    fmt.Fprintf(w, "Hello, %s", user)
}

Example adding Kerberos authentication to an http.FileServer using khttp.Handler:

package main

import (
    "github.com/ubccr/kerby/khttp"
    "log"
    "net/http"
)

func main() {
    http.Handle("/", khttp.Handler(http.FileServer(http.Dir("/tmp"))))
    log.Fatal(http.ListenAndServe(":8000", nil))
}

License

Kerby is released under the Apache 2.0 License. See the LICENSE file.

kerby's People

Contributors

aebruno avatar satyenr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

kerby's Issues

Any way to troubleshoot this not working when the keytab has been verified working

I have verified the keytab works using these troubleshooting steps:

kdestroy
kinit -kt file.keytab USER@REALM
klist

But when I pass the keytab and principal, same as above, it fails to authenticate.
The keytab path is the absolute path including the filename.
The principal is exactly the same.
No error message that I can tell.
Both running as root.

Anyway I can troubleshoot?
Is there a debug option?
Any ideas come to mind?
Thanks

Checking status after KerbServer.Step

Taking KerbServer.UserName as an example, the comments say:

// Get the user name of the principal trying to authenticate to the server.
// This method must only be called after KerbServer.Step returns a complete or
// continue response code.

What is the proper way to check the response code from KerbServer.Step?

This is also needed in general to check whether the gssapi context has been established properly. It seems that perhaps the Step function should be returning the result of C.authenticate_gss_server_step().

Does not compile in OSX - El Capitan v10.11.6

/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' has been explicitly marked deprecated here

I'm not sure what I need to do to get this to compile.
Searching around looks like this repo would need to be updated somehow, but I dunno how to fix it.

Delegation confusion

authenticate_gss_client_init() seems to have this idea that one must have a separate credential handle for credentials to delegate. Credential delegation is just a flag.

Make negotiateHeader match case insensitive

From khttp/http.go:

var (
	negotiateHeader       = "Negotiate"
	wwwAuthenticateHeader = "WWW-Authenticate"
	authorizationHeader   = "Authorization"
)
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
        ......
	authReply := strings.Split(resp.Header.Get(wwwAuthenticateHeader), " ")
	if len(authReply) != 2 || authReply[0] != negotiateHeader {
		return nil, errors.New("khttp: server replied with invalid www-authenticate header")
	}
        ......
}

I have seen services that return "negotiate" instead of "Negotiate" - causing Transport.RoundTrip() to return an error. The following patch fixes the problem:

diff --git a/khttp/http.go b/khttp/http.go
index de9ee986..db195d39 100644
--- a/khttp/http.go
+++ b/khttp/http.go
@@ -28,7 +28,7 @@ import (
 )
 
 var (
-       negotiateHeader       = "Negotiate"
+       negotiateHeader       = "negotiate"
        wwwAuthenticateHeader = "WWW-Authenticate"
        authorizationHeader   = "Authorization"
 )
@@ -83,7 +83,7 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
        }
 
        authReply := strings.Split(resp.Header.Get(wwwAuthenticateHeader), " ")
-       if len(authReply) != 2 || authReply[0] != negotiateHeader {
+       if len(authReply) != 2 || strings.ToLower(authReply[0]) != negotiateHeader {
                return nil, errors.New("khttp: server replied with invalid www-authenticate header")
        }

GSS names are not user names

Calling the client principal name a "username" is problematic. When I started looking at this I immediately feared there might be post-processing of the name to truncate any @REALM portions.

The API should provide access to the displayed and exported name forms for the initiator and acceptor names, and possibly a wrapper for the gss_name_t values themselves so that name attributes can be accessed.

No need to use the krb5 API

You shouldn't need to use the krb5 API, as is done in kerby.go, in ServerPrincipalDetails(), which is unused and undocumented anyways. Just remove it.

go test ERROR

I ran the klist and got the correct output.But when I do go test,the error msg is printed as below:
./kerby.go:154: entry.principal undefined (type C.struct_krb5_keytab_entry_st has no field or method principal)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.