1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2025-08-08 22:46:33 +02:00

Add preferred_username support (OIDC provider) (#420)

* Add support for preferred username.

* Add missing TOC entries.

* Add note about preferred_username support.

* Adjust tests.

* Check on not implemented error for GetPreferredUsername() call.

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk>
This commit is contained in:
Felix Fontein
2020-03-01 16:02:51 +01:00
committed by GitHub
parent 0bca3564b5
commit d934309b44
8 changed files with 118 additions and 51 deletions

View File

@ -12,13 +12,14 @@ import (
// SessionState is used to store information about the currently authenticated user session
type SessionState struct {
AccessToken string `json:",omitempty"`
IDToken string `json:",omitempty"`
CreatedAt time.Time `json:"-"`
ExpiresOn time.Time `json:"-"`
RefreshToken string `json:",omitempty"`
Email string `json:",omitempty"`
User string `json:",omitempty"`
AccessToken string `json:",omitempty"`
IDToken string `json:",omitempty"`
CreatedAt time.Time `json:"-"`
ExpiresOn time.Time `json:"-"`
RefreshToken string `json:",omitempty"`
Email string `json:",omitempty"`
User string `json:",omitempty"`
PreferredUsername string `json:",omitempty"`
}
// SessionStateJSON is used to encode SessionState into JSON without exposing time.Time zero value
@ -46,7 +47,7 @@ func (s *SessionState) Age() time.Duration {
// String constructs a summary of the session state
func (s *SessionState) String() string {
o := fmt.Sprintf("Session{email:%s user:%s", s.Email, s.User)
o := fmt.Sprintf("Session{email:%s user:%s PreferredUsername:%s", s.Email, s.User, s.PreferredUsername)
if s.AccessToken != "" {
o += " token:true"
}
@ -72,6 +73,7 @@ func (s *SessionState) EncodeSessionState(c *encryption.Cipher) (string, error)
// Store only Email and User when cipher is unavailable
ss.Email = s.Email
ss.User = s.User
ss.PreferredUsername = s.PreferredUsername
} else {
ss = *s
var err error
@ -87,6 +89,12 @@ func (s *SessionState) EncodeSessionState(c *encryption.Cipher) (string, error)
return "", err
}
}
if ss.PreferredUsername != "" {
ss.PreferredUsername, err = c.Encrypt(ss.PreferredUsername)
if err != nil {
return "", err
}
}
if ss.AccessToken != "" {
ss.AccessToken, err = c.Encrypt(ss.AccessToken)
if err != nil {
@ -199,8 +207,9 @@ func DecodeSessionState(v string, c *encryption.Cipher) (*SessionState, error) {
if c == nil {
// Load only Email and User when cipher is unavailable
ss = &SessionState{
Email: ss.Email,
User: ss.User,
Email: ss.Email,
User: ss.User,
PreferredUsername: ss.PreferredUsername,
}
} else {
// Backward compatibility with using unencrypted Email
@ -217,6 +226,12 @@ func DecodeSessionState(v string, c *encryption.Cipher) (*SessionState, error) {
ss.User = decryptedUser
}
}
if ss.PreferredUsername != "" {
ss.PreferredUsername, err = c.Decrypt(ss.PreferredUsername)
if err != nil {
return nil, err
}
}
if ss.AccessToken != "" {
ss.AccessToken, err = c.Decrypt(ss.AccessToken)
if err != nil {

View File

@ -19,12 +19,13 @@ func TestSessionStateSerialization(t *testing.T) {
c2, err := encryption.NewCipher([]byte(altSecret))
assert.Equal(t, nil, err)
s := &sessions.SessionState{
Email: "user@domain.com",
AccessToken: "token1234",
IDToken: "rawtoken1234",
CreatedAt: time.Now(),
ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
RefreshToken: "refresh4321",
Email: "user@domain.com",
PreferredUsername: "user",
AccessToken: "token1234",
IDToken: "rawtoken1234",
CreatedAt: time.Now(),
ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
RefreshToken: "refresh4321",
}
encoded, err := s.EncodeSessionState(c)
assert.Equal(t, nil, err)
@ -34,6 +35,7 @@ func TestSessionStateSerialization(t *testing.T) {
assert.Equal(t, nil, err)
assert.Equal(t, "user@domain.com", ss.User)
assert.Equal(t, s.Email, ss.Email)
assert.Equal(t, s.PreferredUsername, ss.PreferredUsername)
assert.Equal(t, s.AccessToken, ss.AccessToken)
assert.Equal(t, s.IDToken, ss.IDToken)
assert.Equal(t, s.CreatedAt.Unix(), ss.CreatedAt.Unix())
@ -46,6 +48,7 @@ func TestSessionStateSerialization(t *testing.T) {
assert.Equal(t, nil, err)
assert.NotEqual(t, "user@domain.com", ss.User)
assert.NotEqual(t, s.Email, ss.Email)
assert.NotEqual(t, s.PreferredUsername, ss.PreferredUsername)
assert.Equal(t, s.CreatedAt.Unix(), ss.CreatedAt.Unix())
assert.Equal(t, s.ExpiresOn.Unix(), ss.ExpiresOn.Unix())
assert.NotEqual(t, s.AccessToken, ss.AccessToken)
@ -59,12 +62,13 @@ func TestSessionStateSerializationWithUser(t *testing.T) {
c2, err := encryption.NewCipher([]byte(altSecret))
assert.Equal(t, nil, err)
s := &sessions.SessionState{
User: "just-user",
Email: "user@domain.com",
AccessToken: "token1234",
CreatedAt: time.Now(),
ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
RefreshToken: "refresh4321",
User: "just-user",
PreferredUsername: "ju",
Email: "user@domain.com",
AccessToken: "token1234",
CreatedAt: time.Now(),
ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
RefreshToken: "refresh4321",
}
encoded, err := s.EncodeSessionState(c)
assert.Equal(t, nil, err)
@ -74,6 +78,7 @@ func TestSessionStateSerializationWithUser(t *testing.T) {
assert.Equal(t, nil, err)
assert.Equal(t, s.User, ss.User)
assert.Equal(t, s.Email, ss.Email)
assert.Equal(t, s.PreferredUsername, ss.PreferredUsername)
assert.Equal(t, s.AccessToken, ss.AccessToken)
assert.Equal(t, s.CreatedAt.Unix(), ss.CreatedAt.Unix())
assert.Equal(t, s.ExpiresOn.Unix(), ss.ExpiresOn.Unix())
@ -85,6 +90,7 @@ func TestSessionStateSerializationWithUser(t *testing.T) {
assert.Equal(t, nil, err)
assert.NotEqual(t, s.User, ss.User)
assert.NotEqual(t, s.Email, ss.Email)
assert.NotEqual(t, s.PreferredUsername, ss.PreferredUsername)
assert.Equal(t, s.CreatedAt.Unix(), ss.CreatedAt.Unix())
assert.Equal(t, s.ExpiresOn.Unix(), ss.ExpiresOn.Unix())
assert.NotEqual(t, s.AccessToken, ss.AccessToken)
@ -93,11 +99,12 @@ func TestSessionStateSerializationWithUser(t *testing.T) {
func TestSessionStateSerializationNoCipher(t *testing.T) {
s := &sessions.SessionState{
Email: "user@domain.com",
AccessToken: "token1234",
CreatedAt: time.Now(),
ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
RefreshToken: "refresh4321",
Email: "user@domain.com",
PreferredUsername: "user",
AccessToken: "token1234",
CreatedAt: time.Now(),
ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
RefreshToken: "refresh4321",
}
encoded, err := s.EncodeSessionState(nil)
assert.Equal(t, nil, err)
@ -107,18 +114,20 @@ func TestSessionStateSerializationNoCipher(t *testing.T) {
assert.Equal(t, nil, err)
assert.Equal(t, "user@domain.com", ss.User)
assert.Equal(t, s.Email, ss.Email)
assert.Equal(t, s.PreferredUsername, ss.PreferredUsername)
assert.Equal(t, "", ss.AccessToken)
assert.Equal(t, "", ss.RefreshToken)
}
func TestSessionStateSerializationNoCipherWithUser(t *testing.T) {
s := &sessions.SessionState{
User: "just-user",
Email: "user@domain.com",
AccessToken: "token1234",
CreatedAt: time.Now(),
ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
RefreshToken: "refresh4321",
User: "just-user",
Email: "user@domain.com",
PreferredUsername: "user",
AccessToken: "token1234",
CreatedAt: time.Now(),
ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
RefreshToken: "refresh4321",
}
encoded, err := s.EncodeSessionState(nil)
assert.Equal(t, nil, err)
@ -128,6 +137,7 @@ func TestSessionStateSerializationNoCipherWithUser(t *testing.T) {
assert.Equal(t, nil, err)
assert.Equal(t, s.User, ss.User)
assert.Equal(t, s.Email, ss.Email)
assert.Equal(t, s.PreferredUsername, ss.PreferredUsername)
assert.Equal(t, "", ss.AccessToken)
assert.Equal(t, "", ss.RefreshToken)
}