github.com/jcmturner/gokrb5/v8@v8.4.4/credentials/credentials.go (about) 1 // Package credentials provides credentials management for Kerberos 5 authentication. 2 package credentials 3 4 import ( 5 "bytes" 6 "encoding/gob" 7 "encoding/json" 8 "time" 9 10 "github.com/hashicorp/go-uuid" 11 "github.com/jcmturner/gokrb5/v8/iana/nametype" 12 "github.com/jcmturner/gokrb5/v8/keytab" 13 "github.com/jcmturner/gokrb5/v8/types" 14 ) 15 16 const ( 17 // AttributeKeyADCredentials assigned number for AD credentials. 18 AttributeKeyADCredentials = "gokrb5AttributeKeyADCredentials" 19 ) 20 21 // Credentials struct for a user. 22 // Contains either a keytab, password or both. 23 // Keytabs are used over passwords if both are defined. 24 type Credentials struct { 25 username string 26 displayName string 27 realm string 28 cname types.PrincipalName 29 keytab *keytab.Keytab 30 password string 31 attributes map[string]interface{} 32 validUntil time.Time 33 authenticated bool 34 human bool 35 authTime time.Time 36 groupMembership map[string]bool 37 sessionID string 38 } 39 40 // marshalCredentials is used to enable marshaling and unmarshaling of credentials 41 // without having exported fields on the Credentials struct 42 type marshalCredentials struct { 43 Username string 44 DisplayName string 45 Realm string 46 CName types.PrincipalName `json:"-"` 47 Keytab bool 48 Password bool 49 Attributes map[string]interface{} `json:"-"` 50 ValidUntil time.Time 51 Authenticated bool 52 Human bool 53 AuthTime time.Time 54 GroupMembership map[string]bool `json:"-"` 55 SessionID string 56 } 57 58 // ADCredentials contains information obtained from the PAC. 59 type ADCredentials struct { 60 EffectiveName string 61 FullName string 62 UserID int 63 PrimaryGroupID int 64 LogOnTime time.Time 65 LogOffTime time.Time 66 PasswordLastSet time.Time 67 GroupMembershipSIDs []string 68 LogonDomainName string 69 LogonDomainID string 70 LogonServer string 71 } 72 73 // New creates a new Credentials instance. 74 func New(username string, realm string) *Credentials { 75 uid, err := uuid.GenerateUUID() 76 if err != nil { 77 uid = "00unique-sess-ions-uuid-unavailable0" 78 } 79 return &Credentials{ 80 username: username, 81 displayName: username, 82 realm: realm, 83 cname: types.NewPrincipalName(nametype.KRB_NT_PRINCIPAL, username), 84 keytab: keytab.New(), 85 attributes: make(map[string]interface{}), 86 groupMembership: make(map[string]bool), 87 sessionID: uid, 88 human: true, 89 } 90 } 91 92 // NewFromPrincipalName creates a new Credentials instance with the user details provides as a PrincipalName type. 93 func NewFromPrincipalName(cname types.PrincipalName, realm string) *Credentials { 94 c := New(cname.PrincipalNameString(), realm) 95 c.cname = cname 96 return c 97 } 98 99 // WithKeytab sets the Keytab in the Credentials struct. 100 func (c *Credentials) WithKeytab(kt *keytab.Keytab) *Credentials { 101 c.keytab = kt 102 c.password = "" 103 return c 104 } 105 106 // Keytab returns the credential's Keytab. 107 func (c *Credentials) Keytab() *keytab.Keytab { 108 return c.keytab 109 } 110 111 // HasKeytab queries if the Credentials has a keytab defined. 112 func (c *Credentials) HasKeytab() bool { 113 if c.keytab != nil && len(c.keytab.Entries) > 0 { 114 return true 115 } 116 return false 117 } 118 119 // WithPassword sets the password in the Credentials struct. 120 func (c *Credentials) WithPassword(password string) *Credentials { 121 c.password = password 122 c.keytab = keytab.New() // clear any keytab 123 return c 124 } 125 126 // Password returns the credential's password. 127 func (c *Credentials) Password() string { 128 return c.password 129 } 130 131 // HasPassword queries if the Credentials has a password defined. 132 func (c *Credentials) HasPassword() bool { 133 if c.password != "" { 134 return true 135 } 136 return false 137 } 138 139 // SetValidUntil sets the expiry time of the credentials 140 func (c *Credentials) SetValidUntil(t time.Time) { 141 c.validUntil = t 142 } 143 144 // SetADCredentials adds ADCredentials attributes to the credentials 145 func (c *Credentials) SetADCredentials(a ADCredentials) { 146 c.SetAttribute(AttributeKeyADCredentials, a) 147 if a.FullName != "" { 148 c.SetDisplayName(a.FullName) 149 } 150 if a.EffectiveName != "" { 151 c.SetUserName(a.EffectiveName) 152 } 153 for i := range a.GroupMembershipSIDs { 154 c.AddAuthzAttribute(a.GroupMembershipSIDs[i]) 155 } 156 } 157 158 // GetADCredentials returns ADCredentials attributes sorted in the credential 159 func (c *Credentials) GetADCredentials() ADCredentials { 160 if a, ok := c.attributes[AttributeKeyADCredentials].(ADCredentials); ok { 161 return a 162 } 163 return ADCredentials{} 164 } 165 166 // Methods to implement goidentity.Identity interface 167 168 // UserName returns the credential's username. 169 func (c *Credentials) UserName() string { 170 return c.username 171 } 172 173 // SetUserName sets the username value on the credential. 174 func (c *Credentials) SetUserName(s string) { 175 c.username = s 176 } 177 178 // CName returns the credential's client principal name. 179 func (c *Credentials) CName() types.PrincipalName { 180 return c.cname 181 } 182 183 // SetCName sets the client principal name on the credential. 184 func (c *Credentials) SetCName(pn types.PrincipalName) { 185 c.cname = pn 186 } 187 188 // Domain returns the credential's domain. 189 func (c *Credentials) Domain() string { 190 return c.realm 191 } 192 193 // SetDomain sets the domain value on the credential. 194 func (c *Credentials) SetDomain(s string) { 195 c.realm = s 196 } 197 198 // Realm returns the credential's realm. Same as the domain. 199 func (c *Credentials) Realm() string { 200 return c.Domain() 201 } 202 203 // SetRealm sets the realm value on the credential. Same as the domain 204 func (c *Credentials) SetRealm(s string) { 205 c.SetDomain(s) 206 } 207 208 // DisplayName returns the credential's display name. 209 func (c *Credentials) DisplayName() string { 210 return c.displayName 211 } 212 213 // SetDisplayName sets the display name value on the credential. 214 func (c *Credentials) SetDisplayName(s string) { 215 c.displayName = s 216 } 217 218 // Human returns if the credential represents a human or not. 219 func (c *Credentials) Human() bool { 220 return c.human 221 } 222 223 // SetHuman sets the credential as human. 224 func (c *Credentials) SetHuman(b bool) { 225 c.human = b 226 } 227 228 // AuthTime returns the time the credential was authenticated. 229 func (c *Credentials) AuthTime() time.Time { 230 return c.authTime 231 } 232 233 // SetAuthTime sets the time the credential was authenticated. 234 func (c *Credentials) SetAuthTime(t time.Time) { 235 c.authTime = t 236 } 237 238 // AuthzAttributes returns the credentials authorizing attributes. 239 func (c *Credentials) AuthzAttributes() []string { 240 s := make([]string, len(c.groupMembership)) 241 i := 0 242 for a := range c.groupMembership { 243 s[i] = a 244 i++ 245 } 246 return s 247 } 248 249 // Authenticated indicates if the credential has been successfully authenticated or not. 250 func (c *Credentials) Authenticated() bool { 251 return c.authenticated 252 } 253 254 // SetAuthenticated sets the credential as having been successfully authenticated. 255 func (c *Credentials) SetAuthenticated(b bool) { 256 c.authenticated = b 257 } 258 259 // AddAuthzAttribute adds an authorization attribute to the credential. 260 func (c *Credentials) AddAuthzAttribute(a string) { 261 c.groupMembership[a] = true 262 } 263 264 // RemoveAuthzAttribute removes an authorization attribute from the credential. 265 func (c *Credentials) RemoveAuthzAttribute(a string) { 266 if _, ok := c.groupMembership[a]; !ok { 267 return 268 } 269 delete(c.groupMembership, a) 270 } 271 272 // EnableAuthzAttribute toggles an authorization attribute to an enabled state on the credential. 273 func (c *Credentials) EnableAuthzAttribute(a string) { 274 if enabled, ok := c.groupMembership[a]; ok && !enabled { 275 c.groupMembership[a] = true 276 } 277 } 278 279 // DisableAuthzAttribute toggles an authorization attribute to a disabled state on the credential. 280 func (c *Credentials) DisableAuthzAttribute(a string) { 281 if enabled, ok := c.groupMembership[a]; ok && enabled { 282 c.groupMembership[a] = false 283 } 284 } 285 286 // Authorized indicates if the credential has the specified authorizing attribute. 287 func (c *Credentials) Authorized(a string) bool { 288 if enabled, ok := c.groupMembership[a]; ok && enabled { 289 return true 290 } 291 return false 292 } 293 294 // SessionID returns the credential's session ID. 295 func (c *Credentials) SessionID() string { 296 return c.sessionID 297 } 298 299 // Expired indicates if the credential has expired. 300 func (c *Credentials) Expired() bool { 301 if !c.validUntil.IsZero() && time.Now().UTC().After(c.validUntil) { 302 return true 303 } 304 return false 305 } 306 307 // ValidUntil returns the credential's valid until date 308 func (c *Credentials) ValidUntil() time.Time { 309 return c.validUntil 310 } 311 312 // Attributes returns the Credentials' attributes map. 313 func (c *Credentials) Attributes() map[string]interface{} { 314 return c.attributes 315 } 316 317 // SetAttribute sets the value of an attribute. 318 func (c *Credentials) SetAttribute(k string, v interface{}) { 319 c.attributes[k] = v 320 } 321 322 // SetAttributes replaces the attributes map with the one provided. 323 func (c *Credentials) SetAttributes(a map[string]interface{}) { 324 c.attributes = a 325 } 326 327 // RemoveAttribute deletes an attribute from the attribute map that has the key provided. 328 func (c *Credentials) RemoveAttribute(k string) { 329 delete(c.attributes, k) 330 } 331 332 // Marshal the Credentials into a byte slice 333 func (c *Credentials) Marshal() ([]byte, error) { 334 gob.Register(map[string]interface{}{}) 335 gob.Register(ADCredentials{}) 336 buf := new(bytes.Buffer) 337 enc := gob.NewEncoder(buf) 338 mc := marshalCredentials{ 339 Username: c.username, 340 DisplayName: c.displayName, 341 Realm: c.realm, 342 CName: c.cname, 343 Keytab: c.HasKeytab(), 344 Password: c.HasPassword(), 345 Attributes: c.attributes, 346 ValidUntil: c.validUntil, 347 Authenticated: c.authenticated, 348 Human: c.human, 349 AuthTime: c.authTime, 350 GroupMembership: c.groupMembership, 351 SessionID: c.sessionID, 352 } 353 err := enc.Encode(&mc) 354 if err != nil { 355 return []byte{}, err 356 } 357 return buf.Bytes(), nil 358 } 359 360 // Unmarshal a byte slice into Credentials 361 func (c *Credentials) Unmarshal(b []byte) error { 362 gob.Register(map[string]interface{}{}) 363 gob.Register(ADCredentials{}) 364 mc := new(marshalCredentials) 365 buf := bytes.NewBuffer(b) 366 dec := gob.NewDecoder(buf) 367 err := dec.Decode(mc) 368 if err != nil { 369 return err 370 } 371 c.username = mc.Username 372 c.displayName = mc.DisplayName 373 c.realm = mc.Realm 374 c.cname = mc.CName 375 c.attributes = mc.Attributes 376 c.validUntil = mc.ValidUntil 377 c.authenticated = mc.Authenticated 378 c.human = mc.Human 379 c.authTime = mc.AuthTime 380 c.groupMembership = mc.GroupMembership 381 c.sessionID = mc.SessionID 382 return nil 383 } 384 385 // JSON return details of the Credentials in a JSON format. 386 func (c *Credentials) JSON() (string, error) { 387 mc := marshalCredentials{ 388 Username: c.username, 389 DisplayName: c.displayName, 390 Realm: c.realm, 391 CName: c.cname, 392 Keytab: c.HasKeytab(), 393 Password: c.HasPassword(), 394 ValidUntil: c.validUntil, 395 Authenticated: c.authenticated, 396 Human: c.human, 397 AuthTime: c.authTime, 398 SessionID: c.sessionID, 399 } 400 b, err := json.MarshalIndent(mc, "", " ") 401 if err != nil { 402 return "", err 403 } 404 return string(b), nil 405 }