// Package credentials provides credentials management for Kerberos 5 authentication.
package credentials import ( ) const ( // AttributeKeyADCredentials assigned number for AD credentials. AttributeKeyADCredentials = "gokrb5AttributeKeyADCredentials" ) // Credentials struct for a user. // Contains either a keytab, password or both. // Keytabs are used over passwords if both are defined. type Credentials struct { username string displayName string realm string cname types.PrincipalName keytab *keytab.Keytab password string attributes map[string]interface{} validUntil time.Time authenticated bool human bool authTime time.Time groupMembership map[string]bool sessionID string } // marshalCredentials is used to enable marshaling and unmarshaling of credentials // without having exported fields on the Credentials struct type marshalCredentials struct { Username string DisplayName string Realm string CName types.PrincipalName `json:"-"` Keytab bool Password bool Attributes map[string]interface{} `json:"-"` ValidUntil time.Time Authenticated bool Human bool AuthTime time.Time GroupMembership map[string]bool `json:"-"` SessionID string } // ADCredentials contains information obtained from the PAC. type ADCredentials struct { EffectiveName string FullName string UserID int PrimaryGroupID int LogOnTime time.Time LogOffTime time.Time PasswordLastSet time.Time GroupMembershipSIDs []string LogonDomainName string LogonDomainID string LogonServer string } // New creates a new Credentials instance. func ( string, string) *Credentials { , := uuid.GenerateUUID() if != nil { = "00unique-sess-ions-uuid-unavailable0" } return &Credentials{ username: , displayName: , realm: , cname: types.NewPrincipalName(nametype.KRB_NT_PRINCIPAL, ), keytab: keytab.New(), attributes: make(map[string]interface{}), groupMembership: make(map[string]bool), sessionID: , human: true, } } // NewFromPrincipalName creates a new Credentials instance with the user details provides as a PrincipalName type. func ( types.PrincipalName, string) *Credentials { := New(.PrincipalNameString(), ) .cname = return } // WithKeytab sets the Keytab in the Credentials struct. func ( *Credentials) ( *keytab.Keytab) *Credentials { .keytab = .password = "" return } // Keytab returns the credential's Keytab. func ( *Credentials) () *keytab.Keytab { return .keytab } // HasKeytab queries if the Credentials has a keytab defined. func ( *Credentials) () bool { if .keytab != nil && len(.keytab.Entries) > 0 { return true } return false } // WithPassword sets the password in the Credentials struct. func ( *Credentials) ( string) *Credentials { .password = .keytab = keytab.New() // clear any keytab return } // Password returns the credential's password. func ( *Credentials) () string { return .password } // HasPassword queries if the Credentials has a password defined. func ( *Credentials) () bool { if .password != "" { return true } return false } // SetValidUntil sets the expiry time of the credentials func ( *Credentials) ( time.Time) { .validUntil = } // SetADCredentials adds ADCredentials attributes to the credentials func ( *Credentials) ( ADCredentials) { .SetAttribute(AttributeKeyADCredentials, ) if .FullName != "" { .SetDisplayName(.FullName) } if .EffectiveName != "" { .SetUserName(.EffectiveName) } for := range .GroupMembershipSIDs { .AddAuthzAttribute(.GroupMembershipSIDs[]) } } // GetADCredentials returns ADCredentials attributes sorted in the credential func ( *Credentials) () ADCredentials { if , := .attributes[AttributeKeyADCredentials].(ADCredentials); { return } return ADCredentials{} } // Methods to implement goidentity.Identity interface // UserName returns the credential's username. func ( *Credentials) () string { return .username } // SetUserName sets the username value on the credential. func ( *Credentials) ( string) { .username = } // CName returns the credential's client principal name. func ( *Credentials) () types.PrincipalName { return .cname } // SetCName sets the client principal name on the credential. func ( *Credentials) ( types.PrincipalName) { .cname = } // Domain returns the credential's domain. func ( *Credentials) () string { return .realm } // SetDomain sets the domain value on the credential. func ( *Credentials) ( string) { .realm = } // Realm returns the credential's realm. Same as the domain. func ( *Credentials) () string { return .Domain() } // SetRealm sets the realm value on the credential. Same as the domain func ( *Credentials) ( string) { .SetDomain() } // DisplayName returns the credential's display name. func ( *Credentials) () string { return .displayName } // SetDisplayName sets the display name value on the credential. func ( *Credentials) ( string) { .displayName = } // Human returns if the credential represents a human or not. func ( *Credentials) () bool { return .human } // SetHuman sets the credential as human. func ( *Credentials) ( bool) { .human = } // AuthTime returns the time the credential was authenticated. func ( *Credentials) () time.Time { return .authTime } // SetAuthTime sets the time the credential was authenticated. func ( *Credentials) ( time.Time) { .authTime = } // AuthzAttributes returns the credentials authorizing attributes. func ( *Credentials) () []string { := make([]string, len(.groupMembership)) := 0 for := range .groupMembership { [] = ++ } return } // Authenticated indicates if the credential has been successfully authenticated or not. func ( *Credentials) () bool { return .authenticated } // SetAuthenticated sets the credential as having been successfully authenticated. func ( *Credentials) ( bool) { .authenticated = } // AddAuthzAttribute adds an authorization attribute to the credential. func ( *Credentials) ( string) { .groupMembership[] = true } // RemoveAuthzAttribute removes an authorization attribute from the credential. func ( *Credentials) ( string) { if , := .groupMembership[]; ! { return } delete(.groupMembership, ) } // EnableAuthzAttribute toggles an authorization attribute to an enabled state on the credential. func ( *Credentials) ( string) { if , := .groupMembership[]; && ! { .groupMembership[] = true } } // DisableAuthzAttribute toggles an authorization attribute to a disabled state on the credential. func ( *Credentials) ( string) { if , := .groupMembership[]; && { .groupMembership[] = false } } // Authorized indicates if the credential has the specified authorizing attribute. func ( *Credentials) ( string) bool { if , := .groupMembership[]; && { return true } return false } // SessionID returns the credential's session ID. func ( *Credentials) () string { return .sessionID } // Expired indicates if the credential has expired. func ( *Credentials) () bool { if !.validUntil.IsZero() && time.Now().UTC().After(.validUntil) { return true } return false } // ValidUntil returns the credential's valid until date func ( *Credentials) () time.Time { return .validUntil } // Attributes returns the Credentials' attributes map. func ( *Credentials) () map[string]interface{} { return .attributes } // SetAttribute sets the value of an attribute. func ( *Credentials) ( string, interface{}) { .attributes[] = } // SetAttributes replaces the attributes map with the one provided. func ( *Credentials) ( map[string]interface{}) { .attributes = } // RemoveAttribute deletes an attribute from the attribute map that has the key provided. func ( *Credentials) ( string) { delete(.attributes, ) } // Marshal the Credentials into a byte slice func ( *Credentials) () ([]byte, error) { gob.Register(map[string]interface{}{}) gob.Register(ADCredentials{}) := new(bytes.Buffer) := gob.NewEncoder() := marshalCredentials{ Username: .username, DisplayName: .displayName, Realm: .realm, CName: .cname, Keytab: .HasKeytab(), Password: .HasPassword(), Attributes: .attributes, ValidUntil: .validUntil, Authenticated: .authenticated, Human: .human, AuthTime: .authTime, GroupMembership: .groupMembership, SessionID: .sessionID, } := .Encode(&) if != nil { return []byte{}, } return .Bytes(), nil } // Unmarshal a byte slice into Credentials func ( *Credentials) ( []byte) error { gob.Register(map[string]interface{}{}) gob.Register(ADCredentials{}) := new(marshalCredentials) := bytes.NewBuffer() := gob.NewDecoder() := .Decode() if != nil { return } .username = .Username .displayName = .DisplayName .realm = .Realm .cname = .CName .attributes = .Attributes .validUntil = .ValidUntil .authenticated = .Authenticated .human = .Human .authTime = .AuthTime .groupMembership = .GroupMembership .sessionID = .SessionID return nil } // JSON return details of the Credentials in a JSON format. func ( *Credentials) () (string, error) { := marshalCredentials{ Username: .username, DisplayName: .displayName, Realm: .realm, CName: .cname, Keytab: .HasKeytab(), Password: .HasPassword(), ValidUntil: .validUntil, Authenticated: .authenticated, Human: .human, AuthTime: .authTime, SessionID: .sessionID, } , := json.MarshalIndent(, "", " ") if != nil { return "", } return string(), nil }