github.com/jcmturner/gokrb5/v8@v8.4.4/USAGE.md (about) 1 ## Version 8 Usage 2 3 ### Configuration 4 The gokrb5 libraries use the same krb5.conf configuration file format as MIT Kerberos, 5 described [here](https://web.mit.edu/kerberos/krb5-latest/doc/admin/conf_files/krb5_conf.html). 6 Config instances can be created by loading from a file path or by passing a string, io.Reader or bufio.Scanner to the 7 relevant method: 8 ```go 9 import "github.com/jcmturner/gokrb5/v8/config" 10 cfg, err := config.Load("/path/to/config/file") 11 cfg, err := config.NewFromString(krb5Str) //String must have appropriate newline separations 12 cfg, err := config.NewFromReader(reader) 13 cfg, err := config.NewFromScanner(scanner) 14 ``` 15 ### Keytab files 16 Standard keytab files can be read from a file or from a slice of bytes: 17 ```go 18 import "github.com/jcmturner/gokrb5/v8/keytab" 19 ktFromFile, err := keytab.Load("/path/to/file.keytab") 20 ktFromBytes, err := keytab.Parse(b) 21 22 ``` 23 24 --- 25 26 ### Kerberos Client 27 **Create** a client instance with either a password or a keytab. 28 A configuration must also be passed. Additionally optional additional settings can be provided. 29 ```go 30 import "github.com/jcmturner/gokrb5/v8/client" 31 cl := client.NewWithPassword("username", "REALM.COM", "password", cfg) 32 cl := client.NewWithKeytab("username", "REALM.COM", kt, cfg) 33 ``` 34 Optional settings are provided using the functions defined in the ``client/settings.go`` source file. 35 36 **Login**: 37 ```go 38 err := cl.Login() 39 ``` 40 Kerberos Ticket Granting Tickets (TGT) will be automatically renewed unless the client was created from a CCache. 41 42 A client can be **destroyed** with the following method: 43 ```go 44 cl.Destroy() 45 ``` 46 47 #### Active Directory KDC and FAST negotiation 48 Active Directory does not commonly support FAST negotiation so you will need to disable this on the client. 49 If this is the case you will see this error: 50 ```KDC did not respond appropriately to FAST negotiation``` 51 To resolve this disable PA-FX-Fast on the client before performing Login(). 52 This is done with one of the optional client settings as shown below: 53 ```go 54 cl := client.NewWithPassword("username", "REALM.COM", "password", cfg, client.DisablePAFXFAST(true)) 55 ``` 56 57 #### Authenticate to a Service 58 59 ##### HTTP SPNEGO 60 Create the HTTP request object and then create an SPNEGO client and use this to process the request with methods that 61 are the same as on a HTTP client. 62 If nil is passed as the HTTP client when creating the SPNEGO client the http.DefaultClient is used. 63 When creating the SPNEGO client pass the Service Principal Name (SPN) or auto generate the SPN from the request 64 object by passing a null string "". 65 ```go 66 r, _ := http.NewRequest("GET", "http://host.test.gokrb5/index.html", nil) 67 spnegoCl := spnego.NewClient(cl, nil, "") 68 resp, err := spnegoCl.Do(r) 69 ``` 70 71 ##### Generic Kerberos Client 72 To authenticate to a service a client will need to request a service ticket for a Service Principal Name (SPN) and form 73 into an AP_REQ message along with an authenticator encrypted with the session key that was delivered from the KDC along 74 with the service ticket. 75 76 The steps below outline how to do this. 77 * Get the service ticket and session key for the service the client is authenticating to. 78 The following method will use the client's cache either returning a valid cached ticket, renewing a cached ticket with 79 the KDC or requesting a new ticket from the KDC. 80 Therefore the GetServiceTicket method can be continually used for the most efficient interaction with the KDC. 81 ```go 82 tkt, key, err := cl.GetServiceTicket("HTTP/host.test.gokrb5") 83 ``` 84 85 The steps after this will be specific to the application protocol but it will likely involve a client/server 86 Authentication Protocol exchange (AP exchange). 87 This will involve these steps: 88 89 * Generate a new Authenticator and generate a sequence number and subkey: 90 ```go 91 auth, _ := types.NewAuthenticator(cl.Credentials.Realm, cl.Credentials.CName) 92 etype, _ := crypto.GetEtype(key.KeyType) 93 auth.GenerateSeqNumberAndSubKey(key.KeyType, etype.GetKeyByteSize()) 94 ``` 95 * Set the checksum on the authenticator 96 The checksum is an application specific value. Set as follows: 97 ```go 98 auth.Cksum = types.Checksum{ 99 CksumType: checksumIDint, 100 Checksum: checksumBytesSlice, 101 } 102 ``` 103 * Create the AP_REQ: 104 ```go 105 APReq, err := messages.NewAPReq(tkt, key, auth) 106 ``` 107 108 Now send the AP_REQ to the service. How this is done will be specific to the application use case. 109 110 #### Changing a Client Password 111 This feature uses the Microsoft Kerberos Password Change protocol (RFC 3244). 112 This is implemented in Microsoft Active Directory and in MIT krb5kdc as of version 1.7. 113 Typically the kpasswd server listens on port 464. 114 115 Below is example code for how to use this feature: 116 ```go 117 cfg, err := config.Load("/path/to/config/file") 118 if err != nil { 119 panic(err.Error()) 120 } 121 kt, err := keytab.Load("/path/to/file.keytab") 122 if err != nil { 123 panic(err.Error()) 124 } 125 cl := client.NewWithKeytab("username", "REALM.COM", kt) 126 cl.WithConfig(cfg) 127 128 ok, err := cl.ChangePasswd("newpassword") 129 if err != nil { 130 panic(err.Error()) 131 } 132 if !ok { 133 panic("failed to change password") 134 } 135 ``` 136 137 The client kerberos config (krb5.conf) will need to have either the kpassd_server or admin_server defined in the 138 relevant [realms] section. For example: 139 ``` 140 REALM.COM = { 141 kdc = 127.0.0.1:88 142 kpasswd_server = 127.0.0.1:464 143 default_domain = realm.com 144 } 145 ``` 146 See https://web.mit.edu/kerberos/krb5-latest/doc/admin/conf_files/krb5_conf.html#realms for more information. 147 148 #### Client Diagnostics 149 In the event of issues the configuration of a client can be investigated with its ``Diagnostics`` method. 150 This will check that the required enctypes defined in the client's krb5 config are available in its keytab. 151 It will also check that KDCs can be resolved for the client's REALM. 152 The error returned will contain details of any failed checks. 153 The configuration details of the client will be written to the ``io.Writer`` provided. 154 155 --- 156 157 ### Kerberised Service 158 159 #### SPNEGO/Kerberos HTTP Service 160 A HTTP handler wrapper can be used to implement Kerberos SPNEGO authentication for web services. 161 To configure the wrapper the keytab for the SPN and a Logger are required: 162 ```go 163 kt, err := keytab.Load("/path/to/file.keytab") 164 l := log.New(os.Stderr, "GOKRB5 Service: ", log.Ldate|log.Ltime|log.Lshortfile) 165 ``` 166 Create a handler function of the application's handling method (apphandler in the example below): 167 ```go 168 h := http.HandlerFunc(apphandler) 169 ``` 170 Configure the HTTP handler: 171 ```go 172 http.Handler("/", spnego.SPNEGOKRB5Authenticate(h, &kt, service.Logger(l))) 173 ``` 174 The handler to be wrapped and the keytab are required arguments. 175 Additional optional settings can be provided, such as the logger shown above. 176 177 Another example of optional settings may be that when using Active Directory where the SPN is mapped to a user account 178 the keytab may contain an entry for this user account. In this case this should be specified as below with the 179 ``KeytabPrincipal``: 180 ```go 181 http.Handler("/", spnego.SPNEGOKRB5Authenticate(h, &kt, service.Logger(l), service.KeytabPrincipal(pn))) 182 ``` 183 184 ##### Session Management 185 For efficiency reasons it is not desirable to authenticate on every call to a web service. 186 Therefore most authenticated web applications implement some form of session with the user. 187 Such sessions can be supported by passing a "session manager" into the ``SPNEGOKRB5Authenticate`` wrapper handler. 188 In order to not demand a specific session manager solution, the session manager must implement a simple interface: 189 ```go 190 type SessionMgr interface { 191 New(w http.ResponseWriter, r *http.Request, k string, v []byte) error 192 Get(r *http.Request, k string) ([]byte, error) 193 } 194 ``` 195 - New - creates a new session for the request and adds a piece of data (key/value pair) to the session 196 - Get - extract from an existing session the value held within it under the key provided. 197 This should return nil bytes or an error if there is no existing session. 198 199 The session manager (sm) that implements this interface should then be passed to the ``SPNEGOKRB5Authenticate`` wrapper 200 handler as below: 201 ```go 202 http.Handler("/", spnego.SPNEGOKRB5Authenticate(h, &kt, service.Logger(l), service.SessionManager(sm))) 203 ``` 204 205 The ``httpServer.go`` source file in the examples directory shows how this can be used with the popular gorilla web toolkit. 206 207 ##### Validating Users and Accessing Users' Details 208 If authentication succeeds then the request's context will have a credentials objected added to it. 209 This object implements the ``github.com/jcmturner/goidentity/identity`` interface. 210 If Microsoft Active Directory is used as the KDC then additional ADCredentials are available in the 211 ``credentials.Attributes`` map under the key ``credentials.AttributeKeyADCredentials``. 212 For example the SIDs of the users group membership are available and can be used by your application for authorization. 213 214 Checking and access the credentials within your application: 215 ```go 216 // Get a goidentity credentials object from the request's context 217 creds := goidentity.FromHTTPRequestContext(r) 218 // Check if it indicates it is authenticated 219 if creds != nil && creds.Authenticated() { 220 // Check for Active Directory attributes 221 if ADCredsJSON, ok := creds.Attributes()[credentials.AttributeKeyADCredentials]; ok { 222 ADCreds := new(credentials.ADCredentials) 223 // Unmarshal the AD attributes 224 err := json.Unmarshal([]byte(ADCredsJSON), ADCreds) 225 if err == nil { 226 // Now access the fields of the ADCredentials struct. For example: ADCreds.GroupMembershipSIDs 227 } 228 } 229 } else { 230 // Not authenticated user 231 w.WriteHeader(http.StatusUnauthorized) 232 fmt.Fprint(w, "Authentication failed") 233 } 234 ``` 235 236 #### Generic Kerberised Service - Validating Client Details 237 To validate the AP_REQ sent by the client on the service side call this method: 238 ```go 239 import "github.com/jcmturner/gokrb5/v8/service" 240 s := service.NewSettings(&kt) // kt is a keytab and optional settings can also be provided. 241 if ok, creds, err := service.VerifyAPREQ(&APReq, s); ok { 242 // Perform application specific actions 243 // creds object has details about the client identity 244 } 245 ```