Нет описания

Jonathan Turner 622edd2e00 pac 9 лет назад
asn1tools 0bd461fc52 refactor app tag 9 лет назад
client 8da9b46553 tidy 9 лет назад
config f62ca44c30 comment update 9 лет назад
credentials d4558216b4 cred context 9 лет назад
crypto d4a9fae5de pac 9 лет назад
examples d4558216b4 cred context 9 лет назад
gssapi 8da9b46553 tidy 9 лет назад
iana 622edd2e00 pac 9 лет назад
keytab 05a18c7de2 http server spnego auth 9 лет назад
messages 622edd2e00 pac 9 лет назад
mstypes bf41383bad pac 9 лет назад
ndr d4a9fae5de pac 9 лет назад
pac 622edd2e00 pac 9 лет назад
service 8da9b46553 tidy 9 лет назад
testdata 5ddb09b97d mstypes definitions 9 лет назад
testenv 31db7a56a5 pre-authentication 9 лет назад
types d4a9fae5de pac 9 лет назад
.gitignore 95ab435b4c initial commit 9 лет назад
LICENSE caee2dc83a Initial commit 9 лет назад
README.md 9131d9815e tests 9 лет назад

README.md

gokrb5

GoDoc

Currently the following is working/tested:

  • Client side libraries that supports authentication to HTTP servers that implement SPNEGO using Kerberos 5.
  • Service side libraries for implementing HTTP web servers using Kerberos SPNEGO authentication.
  • Tested against MIT KDC only (please let me know if you find it works against Microsoft Active Directory). MIT KDC 1.6.3 is the oldest version tested against.
  • Tested against a KDC that supports PA-FX-FAST.
  • Tested against users that have pre-authentication required using PA-ENC-TIMESTAMP.

Implemented Encryption & Checksum Types

The currently implemented encryption types are:

Implementation Encryption ID Checksum ID
aes128-cts-hmac-sha1-96 17 15
aes256-cts-hmac-sha1-96 18 16

Usage

Configuration

The gokrb5 libraries use the same krb5.conf configuration file format as MIT Kerberos, described here. Config instances can be created by loading from a file path or by passing a string, io.Reader or bufio.Scanner to the relevant method:

import "github.com/jcmturner/gokrb5/config"
cfg, err := config.Load("/path/to/config/file")
cfg, err := config.NewConfigFromString(krb5Str) //String must have appropriate newline separations
cfg, err := config.NewConfigFromReader(reader)
cfg, err := config.NewConfigFromScanner(scanner)

Keytab files

Standard keytab files can be read from a file or from a slice of bytes:

import 	"github.com/jcmturner/gokrb5/keytab"
ktFromFile, err := keytab.Load("/path/to/file.keytab")
ktFromBytes, err := keytab.Parse(b)

Kerberos Client

Create a client instance with either a password or a keytab:

import 	"github.com/jcmturner/gokrb5/client"
cl := client.NewClientWithPassword("username", "REALM.COM", "password")
cl := client.NewClientWithKeytab("username", "REALM.COM", kt)

Provide configuration to the client:

cl.WithConfig(cfg)

Login:

err := cl.Login

(Optional) Enable automatic refresh of Kerberos Ticket Granting Ticket (TGT):

cl.EnableAutoSessionRenewal()

Authenticate to a Service

Generic Kerberos

To authenticate to a service a client will need to request a serivce ticket for a Service Principal Name (SPN) and form into an AP_REQ message along with an authenticator encrypted with the session key that was delivered from the KDC along with the service ticket.

The steps below outline how to do this.

  • Get the service ticket and session key for the service the client is authenticating to. The following method will use the client's cache either returning a valid cached ticket, renewing a cached ticket with the KDC or requesting a new ticket from the KDC. Therefore the GetServiceTicket method can be continually used for the most efficient interaction with the KDC.

    tkt, key, err := cl.GetServiceTicket("HTTP/host.test.gokrb5")
    

    The steps after this will be specifc to the application protocol but it will likely involve a client/server Authentication Protocol exchange (AP exchange). This will involve these steps:

    • Generate a new Authenticator and generate a sequence number and subkey: go auth := types.NewAuthenticator(cl.Credentials.Realm, cl.Credentials.CName) etype, _ := crypto.GetEtype(key.KeyType) auth.GenerateSeqNumberAndSubKey(key.KeyType, etype.GetKeyByteSize())
  • Set the checksum on the authenticator The checksum is an application specific value. Set as follows:

    auth.Cksum = types.Checksum{
    		CksumType: checksumIDint,
    		Checksum:  checksumBytesSlice,
    	}
    
    • Create the AP_REQ: go APReq, err := messages.NewAPReq(tkt, key, auth)

Now send the AP_REQ to the serivce. How this is done will be specific to the application use case.

HTTP SPNEGO

Create the HTTP request object and then call the client's SetSPNEGOHeader method passing the Service Principal Name (SPN)

r, _ := http.NewRequest("GET", "http://host.test.gokrb5/index.html", nil)
cl.SetSPNEGOHeader(r, "")
HTTPResp, err := http.DefaultClient.Do(r)

Kerberised Service

Validating Client Details

To validate the AP_REQ sent by the client on the service side call this method:

import 	"github.com/jcmturner/gokrb5/service"
if ok, creds, err := serivce.ValidateAPREQ(mt.APReq, kt, r.RemoteAddr); ok {
        // Perform application specifc actions
        // creds object has details about the client identity
}

Kerberos Web Service

A HTTP handler wrapper can be used to implement Kerberos SPNEGO authentication for web services. To configure the wrapper the keytab for the SPN and a Logger are required:

kt, err := keytab.Load("/path/to/file.keytab")
l := log.New(os.Stderr, "GOKRB5 Service: ", log.Ldate|log.Ltime|log.Lshortfile)

Create a handler function of the application's handling method (apphandler in the example below):

h := http.HandlerFunc(apphandler)

Configure the HTTP handler:

http.Handler("/", service.SPNEGOKRB5Authenticate(h, kt, l))

If authentication succeeds then the request's context will have the following values added so they can be accessed within the application's handler:

  • "authenticated" - Boolean indicating if the user is authenticated. Use of this value should also handle that this value may not be set and should assume "false" in that case.
  • "cname" - The authenticated user name.
  • "crealm" - The authenticated user's realm.

References

RFCs

Useful Links

Thanks

  • Greg Hudson from the MIT Consortium for Kerberos and Internet Trust for providing useful advice.

Known Issues

Issue Worked around? References
Golang's ASN1 package cannot unmarshal into slice of asn1.RawValue Yes https://github.com/golang/go/issues/17321
Golang's ASN1 package cannot marshal into a GeneralString Yes - using https://github.com/jcmturner/asn1 https://github.com/golang/go/issues/18832
Golang's ASN1 package cannot marshal into slice of strings and pass stringtype parameter tags to members Yes - using https://github.com/jcmturner/asn1 https://github.com/golang/go/issues/18834
Golang's ASN1 package cannot marshal with application tags Yes