Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encryption efficiency improvements #539

Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -55,6 +55,7 @@

## Changes since v5.1.1

- [#539](https://github.com/oauth2-proxy/oauth2-proxy/pull/539) Refactor encryption ciphers and add AES-GCM support (@NickMeves)
- [#601](https://github.com/oauth2-proxy/oauth2-proxy/pull/601) Ensure decrypted user/email are valid UTF8 (@JoelSpeed)
- [#560](https://github.com/oauth2-proxy/oauth2-proxy/pull/560) Fallback to UserInfo is User ID claim not present (@JoelSpeed)
- [#598](https://github.com/oauth2-proxy/oauth2-proxy/pull/598) acr_values no longer sent to IdP when empty (@ScottGuymer)
Expand Down
6 changes: 3 additions & 3 deletions pkg/apis/options/sessions.go
Expand Up @@ -4,9 +4,9 @@ import "github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"

// SessionOptions contains configuration options for the SessionStore providers.
type SessionOptions struct {
Type string `flag:"session-store-type" cfg:"session_store_type"`
Cipher *encryption.Cipher `cfg:",internal"`
Redis RedisStoreOptions `cfg:",squash"`
Type string `flag:"session-store-type" cfg:"session_store_type"`
Cipher encryption.Cipher `cfg:",internal"`
Redis RedisStoreOptions `cfg:",squash"`
}

// CookieSessionStoreType is used to indicate the CookieSessionStore should be
Expand Down
51 changes: 31 additions & 20 deletions pkg/apis/sessions/session_state.go
Expand Up @@ -60,7 +60,7 @@ func (s *SessionState) String() string {
}

// EncodeSessionState returns string representation of the current session
func (s *SessionState) EncodeSessionState(c *encryption.Cipher) (string, error) {
func (s *SessionState) EncodeSessionState(c encryption.Cipher) (string, error) {
var ss SessionState
if c == nil {
// Store only Email and User when cipher is unavailable
Expand All @@ -77,7 +77,7 @@ func (s *SessionState) EncodeSessionState(c *encryption.Cipher) (string, error)
&ss.IDToken,
&ss.RefreshToken,
} {
err := c.EncryptInto(s)
err := into(s, c.Encrypt)
if err != nil {
return "", err
}
Expand All @@ -89,7 +89,7 @@ func (s *SessionState) EncodeSessionState(c *encryption.Cipher) (string, error)
}

// DecodeSessionState decodes the session cookie string into a SessionState
func DecodeSessionState(v string, c *encryption.Cipher) (*SessionState, error) {
func DecodeSessionState(v string, c encryption.Cipher) (*SessionState, error) {
var ss SessionState
err := json.Unmarshal([]byte(v), &ss)
if err != nil {
Expand All @@ -104,24 +104,18 @@ func DecodeSessionState(v string, c *encryption.Cipher) (*SessionState, error) {
PreferredUsername: ss.PreferredUsername,
}
} else {
// Backward compatibility with using unencrypted Email
if ss.Email != "" {
decryptedEmail, errEmail := c.Decrypt(ss.Email)
if errEmail == nil {
if !utf8.ValidString(decryptedEmail) {
return nil, errors.New("invalid value for decrypted email")
}
ss.Email = decryptedEmail
// Backward compatibility with using unencrypted Email or User
// Decryption errors will leave original string
err = into(&ss.Email, c.Decrypt)
if err == nil {
if !utf8.ValidString(ss.Email) {
return nil, errors.New("invalid value for decrypted email")
}
}
// Backward compatibility with using unencrypted User
if ss.User != "" {
decryptedUser, errUser := c.Decrypt(ss.User)
if errUser == nil {
if !utf8.ValidString(decryptedUser) {
return nil, errors.New("invalid value for decrypted user")
}
ss.User = decryptedUser
err = into(&ss.User, c.Decrypt)
if err == nil {
if !utf8.ValidString(ss.User) {
return nil, errors.New("invalid value for decrypted user")
}
}

Expand All @@ -131,11 +125,28 @@ func DecodeSessionState(v string, c *encryption.Cipher) (*SessionState, error) {
&ss.IDToken,
&ss.RefreshToken,
} {
err := c.DecryptInto(s)
err := into(s, c.Decrypt)
if err != nil {
return nil, err
}
}
}
return &ss, nil
}

// codecFunc is a function that takes a []byte and encodes/decodes it
type codecFunc func([]byte) ([]byte, error)

func into(s *string, f codecFunc) error {
// Do not encrypt/decrypt nil or empty strings
if s == nil || *s == "" {
return nil
}

d, err := f([]byte(*s))
if err != nil {
return err
}
*s = string(d)
return nil
}