123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- // Package credentials provides credentials management for Kerberos 5 authentication.
- package credentials
- import (
- "bytes"
- "encoding/gob"
- "encoding/json"
- "time"
- "github.com/hashicorp/go-uuid"
- "github.com/jcmturner/gokrb5/v8/iana/nametype"
- "github.com/jcmturner/gokrb5/v8/keytab"
- "github.com/jcmturner/gokrb5/v8/types"
- )
- 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 New(username string, realm string) *Credentials {
- uid, err := uuid.GenerateUUID()
- if err != nil {
- uid = "00unique-sess-ions-uuid-unavailable0"
- }
- return &Credentials{
- username: username,
- displayName: username,
- realm: realm,
- cname: types.NewPrincipalName(nametype.KRB_NT_PRINCIPAL, username),
- keytab: keytab.New(),
- attributes: make(map[string]interface{}),
- groupMembership: make(map[string]bool),
- sessionID: uid,
- human: true,
- }
- }
- // NewFromPrincipalName creates a new Credentials instance with the user details provides as a PrincipalName type.
- func NewFromPrincipalName(cname types.PrincipalName, realm string) *Credentials {
- c := New(cname.PrincipalNameString(), realm)
- c.cname = cname
- return c
- }
- // WithKeytab sets the Keytab in the Credentials struct.
- func (c *Credentials) WithKeytab(kt *keytab.Keytab) *Credentials {
- c.keytab = kt
- c.password = ""
- return c
- }
- // Keytab returns the credential's Keytab.
- func (c *Credentials) Keytab() *keytab.Keytab {
- return c.keytab
- }
- // HasKeytab queries if the Credentials has a keytab defined.
- func (c *Credentials) HasKeytab() bool {
- if c.keytab != nil && len(c.keytab.Entries) > 0 {
- return true
- }
- return false
- }
- // WithPassword sets the password in the Credentials struct.
- func (c *Credentials) WithPassword(password string) *Credentials {
- c.password = password
- c.keytab = keytab.New() // clear any keytab
- return c
- }
- // Password returns the credential's password.
- func (c *Credentials) Password() string {
- return c.password
- }
- // HasPassword queries if the Credentials has a password defined.
- func (c *Credentials) HasPassword() bool {
- if c.password != "" {
- return true
- }
- return false
- }
- // SetValidUntil sets the expiry time of the credentials
- func (c *Credentials) SetValidUntil(t time.Time) {
- c.validUntil = t
- }
- // SetADCredentials adds ADCredentials attributes to the credentials
- func (c *Credentials) SetADCredentials(a ADCredentials) {
- c.SetAttribute(AttributeKeyADCredentials, a)
- if a.FullName != "" {
- c.SetDisplayName(a.FullName)
- }
- if a.EffectiveName != "" {
- c.SetUserName(a.EffectiveName)
- }
- for i := range a.GroupMembershipSIDs {
- c.AddAuthzAttribute(a.GroupMembershipSIDs[i])
- }
- }
- // GetADCredentials returns ADCredentials attributes sorted in the credential
- func (c *Credentials) GetADCredentials() ADCredentials {
- if a, ok := c.attributes[AttributeKeyADCredentials].(ADCredentials); ok {
- return a
- }
- return ADCredentials{}
- }
- // Methods to implement goidentity.Identity interface
- // UserName returns the credential's username.
- func (c *Credentials) UserName() string {
- return c.username
- }
- // SetUserName sets the username value on the credential.
- func (c *Credentials) SetUserName(s string) {
- c.username = s
- }
- // CName returns the credential's client principal name.
- func (c *Credentials) CName() types.PrincipalName {
- return c.cname
- }
- // SetCName sets the client principal name on the credential.
- func (c *Credentials) SetCName(pn types.PrincipalName) {
- c.cname = pn
- }
- // Domain returns the credential's domain.
- func (c *Credentials) Domain() string {
- return c.realm
- }
- // SetDomain sets the domain value on the credential.
- func (c *Credentials) SetDomain(s string) {
- c.realm = s
- }
- // Realm returns the credential's realm. Same as the domain.
- func (c *Credentials) Realm() string {
- return c.Domain()
- }
- // SetRealm sets the realm value on the credential. Same as the domain
- func (c *Credentials) SetRealm(s string) {
- c.SetDomain(s)
- }
- // DisplayName returns the credential's display name.
- func (c *Credentials) DisplayName() string {
- return c.displayName
- }
- // SetDisplayName sets the display name value on the credential.
- func (c *Credentials) SetDisplayName(s string) {
- c.displayName = s
- }
- // Human returns if the credential represents a human or not.
- func (c *Credentials) Human() bool {
- return c.human
- }
- // SetHuman sets the credential as human.
- func (c *Credentials) SetHuman(b bool) {
- c.human = b
- }
- // AuthTime returns the time the credential was authenticated.
- func (c *Credentials) AuthTime() time.Time {
- return c.authTime
- }
- // SetAuthTime sets the time the credential was authenticated.
- func (c *Credentials) SetAuthTime(t time.Time) {
- c.authTime = t
- }
- // AuthzAttributes returns the credentials authorizing attributes.
- func (c *Credentials) AuthzAttributes() []string {
- s := make([]string, len(c.groupMembership))
- i := 0
- for a := range c.groupMembership {
- s[i] = a
- i++
- }
- return s
- }
- // Authenticated indicates if the credential has been successfully authenticated or not.
- func (c *Credentials) Authenticated() bool {
- return c.authenticated
- }
- // SetAuthenticated sets the credential as having been successfully authenticated.
- func (c *Credentials) SetAuthenticated(b bool) {
- c.authenticated = b
- }
- // AddAuthzAttribute adds an authorization attribute to the credential.
- func (c *Credentials) AddAuthzAttribute(a string) {
- c.groupMembership[a] = true
- }
- // RemoveAuthzAttribute removes an authorization attribute from the credential.
- func (c *Credentials) RemoveAuthzAttribute(a string) {
- if _, ok := c.groupMembership[a]; !ok {
- return
- }
- delete(c.groupMembership, a)
- }
- // EnableAuthzAttribute toggles an authorization attribute to an enabled state on the credential.
- func (c *Credentials) EnableAuthzAttribute(a string) {
- if enabled, ok := c.groupMembership[a]; ok && !enabled {
- c.groupMembership[a] = true
- }
- }
- // DisableAuthzAttribute toggles an authorization attribute to a disabled state on the credential.
- func (c *Credentials) DisableAuthzAttribute(a string) {
- if enabled, ok := c.groupMembership[a]; ok && enabled {
- c.groupMembership[a] = false
- }
- }
- // Authorized indicates if the credential has the specified authorizing attribute.
- func (c *Credentials) Authorized(a string) bool {
- if enabled, ok := c.groupMembership[a]; ok && enabled {
- return true
- }
- return false
- }
- // SessionID returns the credential's session ID.
- func (c *Credentials) SessionID() string {
- return c.sessionID
- }
- // Expired indicates if the credential has expired.
- func (c *Credentials) Expired() bool {
- if !c.validUntil.IsZero() && time.Now().UTC().After(c.validUntil) {
- return true
- }
- return false
- }
- // ValidUntil returns the credential's valid until date
- func (c *Credentials) ValidUntil() time.Time {
- return c.validUntil
- }
- // Attributes returns the Credentials' attributes map.
- func (c *Credentials) Attributes() map[string]interface{} {
- return c.attributes
- }
- // SetAttribute sets the value of an attribute.
- func (c *Credentials) SetAttribute(k string, v interface{}) {
- c.attributes[k] = v
- }
- // SetAttributes replaces the attributes map with the one provided.
- func (c *Credentials) SetAttributes(a map[string]interface{}) {
- c.attributes = a
- }
- // RemoveAttribute deletes an attribute from the attribute map that has the key provided.
- func (c *Credentials) RemoveAttribute(k string) {
- delete(c.attributes, k)
- }
- // Marshal the Credentials into a byte slice
- func (c *Credentials) Marshal() ([]byte, error) {
- gob.Register(map[string]interface{}{})
- gob.Register(ADCredentials{})
- buf := new(bytes.Buffer)
- enc := gob.NewEncoder(buf)
- mc := marshalCredentials{
- Username: c.username,
- DisplayName: c.displayName,
- Realm: c.realm,
- CName: c.cname,
- Keytab: c.HasKeytab(),
- Password: c.HasPassword(),
- Attributes: c.attributes,
- ValidUntil: c.validUntil,
- Authenticated: c.authenticated,
- Human: c.human,
- AuthTime: c.authTime,
- GroupMembership: c.groupMembership,
- SessionID: c.sessionID,
- }
- err := enc.Encode(&mc)
- if err != nil {
- return []byte{}, err
- }
- return buf.Bytes(), nil
- }
- // Unmarshal a byte slice into Credentials
- func (c *Credentials) Unmarshal(b []byte) error {
- gob.Register(map[string]interface{}{})
- gob.Register(ADCredentials{})
- mc := new(marshalCredentials)
- buf := bytes.NewBuffer(b)
- dec := gob.NewDecoder(buf)
- err := dec.Decode(mc)
- if err != nil {
- return err
- }
- c.username = mc.Username
- c.displayName = mc.DisplayName
- c.realm = mc.Realm
- c.cname = mc.CName
- c.attributes = mc.Attributes
- c.validUntil = mc.ValidUntil
- c.authenticated = mc.Authenticated
- c.human = mc.Human
- c.authTime = mc.AuthTime
- c.groupMembership = mc.GroupMembership
- c.sessionID = mc.SessionID
- return nil
- }
- // JSON return details of the Credentials in a JSON format.
- func (c *Credentials) JSON() (string, error) {
- mc := marshalCredentials{
- Username: c.username,
- DisplayName: c.displayName,
- Realm: c.realm,
- CName: c.cname,
- Keytab: c.HasKeytab(),
- Password: c.HasPassword(),
- ValidUntil: c.validUntil,
- Authenticated: c.authenticated,
- Human: c.human,
- AuthTime: c.authTime,
- SessionID: c.sessionID,
- }
- b, err := json.MarshalIndent(mc, "", " ")
- if err != nil {
- return "", err
- }
- return string(b), nil
- }
|