credentials.go 10 KB

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