github.com/jcmturner/gokrb5/v8@v8.4.4/service/authenticator.go (about) 1 package service 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "strings" 7 "time" 8 9 goidentity "github.com/jcmturner/goidentity/v6" 10 "github.com/jcmturner/gokrb5/v8/client" 11 "github.com/jcmturner/gokrb5/v8/config" 12 "github.com/jcmturner/gokrb5/v8/credentials" 13 ) 14 15 // NewKRB5BasicAuthenticator creates a new NewKRB5BasicAuthenticator 16 func NewKRB5BasicAuthenticator(headerVal string, krb5conf *config.Config, serviceSettings *Settings, clientSettings *client.Settings) KRB5BasicAuthenticator { 17 return KRB5BasicAuthenticator{ 18 BasicHeaderValue: headerVal, 19 clientConfig: krb5conf, 20 serviceSettings: serviceSettings, 21 clientSettings: clientSettings, 22 } 23 } 24 25 // KRB5BasicAuthenticator implements gokrb5.com/jcmturner/goidentity.Authenticator interface. 26 // It takes username and password so can be used for basic authentication. 27 type KRB5BasicAuthenticator struct { 28 BasicHeaderValue string 29 serviceSettings *Settings 30 clientSettings *client.Settings 31 clientConfig *config.Config 32 realm string 33 username string 34 password string 35 } 36 37 // Authenticate and return the identity. The boolean indicates if the authentication was successful. 38 func (a KRB5BasicAuthenticator) Authenticate() (i goidentity.Identity, ok bool, err error) { 39 a.realm, a.username, a.password, err = parseBasicHeaderValue(a.BasicHeaderValue) 40 if err != nil { 41 err = fmt.Errorf("could not parse basic authentication header: %v", err) 42 return 43 } 44 cl := client.NewWithPassword(a.username, a.realm, a.password, a.clientConfig) 45 err = cl.Login() 46 if err != nil { 47 // Username and/or password could be wrong 48 err = fmt.Errorf("error with user credentials during login: %v", err) 49 return 50 } 51 tkt, _, err := cl.GetServiceTicket(a.serviceSettings.SName()) 52 if err != nil { 53 err = fmt.Errorf("could not get service ticket: %v", err) 54 return 55 } 56 err = tkt.DecryptEncPart(a.serviceSettings.Keytab, a.serviceSettings.KeytabPrincipal()) 57 if err != nil { 58 err = fmt.Errorf("could not decrypt service ticket: %v", err) 59 return 60 } 61 cl.Credentials.SetAuthTime(time.Now().UTC()) 62 cl.Credentials.SetAuthenticated(true) 63 isPAC, pac, err := tkt.GetPACType(a.serviceSettings.Keytab, a.serviceSettings.KeytabPrincipal(), a.serviceSettings.Logger()) 64 if isPAC && err != nil { 65 err = fmt.Errorf("error processing PAC: %v", err) 66 return 67 } 68 if isPAC { 69 // There is a valid PAC. Adding attributes to creds 70 cl.Credentials.SetADCredentials(credentials.ADCredentials{ 71 GroupMembershipSIDs: pac.KerbValidationInfo.GetGroupMembershipSIDs(), 72 LogOnTime: pac.KerbValidationInfo.LogOnTime.Time(), 73 LogOffTime: pac.KerbValidationInfo.LogOffTime.Time(), 74 PasswordLastSet: pac.KerbValidationInfo.PasswordLastSet.Time(), 75 EffectiveName: pac.KerbValidationInfo.EffectiveName.Value, 76 FullName: pac.KerbValidationInfo.FullName.Value, 77 UserID: int(pac.KerbValidationInfo.UserID), 78 PrimaryGroupID: int(pac.KerbValidationInfo.PrimaryGroupID), 79 LogonServer: pac.KerbValidationInfo.LogonServer.Value, 80 LogonDomainName: pac.KerbValidationInfo.LogonDomainName.Value, 81 LogonDomainID: pac.KerbValidationInfo.LogonDomainID.String(), 82 }) 83 } 84 ok = true 85 i = cl.Credentials 86 return 87 } 88 89 // Mechanism returns the authentication mechanism. 90 func (a KRB5BasicAuthenticator) Mechanism() string { 91 return "Kerberos Basic" 92 } 93 94 func parseBasicHeaderValue(s string) (domain, username, password string, err error) { 95 b, err := base64.StdEncoding.DecodeString(s) 96 if err != nil { 97 return 98 } 99 v := string(b) 100 vc := strings.SplitN(v, ":", 2) 101 password = vc[1] 102 // Domain and username can be specified in 2 formats: 103 // <Username> - no domain specified 104 // <Domain>\<Username> 105 // <Username>@<Domain> 106 if strings.Contains(vc[0], `\`) { 107 u := strings.SplitN(vc[0], `\`, 2) 108 domain = u[0] 109 username = u[1] 110 } else if strings.Contains(vc[0], `@`) { 111 u := strings.SplitN(vc[0], `@`, 2) 112 domain = u[1] 113 username = u[0] 114 } else { 115 username = vc[0] 116 } 117 return 118 }