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  ```