Merge pull request #1846 from flant/refresh-token-expiration-policy
feat: Add refresh token expiration and rotation settings
This commit is contained in:
@@ -324,14 +324,15 @@ func testClientCRUD(t *testing.T, s storage.Storage) {
|
||||
func testRefreshTokenCRUD(t *testing.T, s storage.Storage) {
|
||||
id := storage.NewID()
|
||||
refresh := storage.RefreshToken{
|
||||
ID: id,
|
||||
Token: "bar",
|
||||
Nonce: "foo",
|
||||
ClientID: "client_id",
|
||||
ConnectorID: "client_secret",
|
||||
Scopes: []string{"openid", "email", "profile"},
|
||||
CreatedAt: time.Now().UTC().Round(time.Millisecond),
|
||||
LastUsed: time.Now().UTC().Round(time.Millisecond),
|
||||
ID: id,
|
||||
Token: "bar",
|
||||
ObsoleteToken: "",
|
||||
Nonce: "foo",
|
||||
ClientID: "client_id",
|
||||
ConnectorID: "client_secret",
|
||||
Scopes: []string{"openid", "email", "profile"},
|
||||
CreatedAt: time.Now().UTC().Round(time.Millisecond),
|
||||
LastUsed: time.Now().UTC().Round(time.Millisecond),
|
||||
Claims: storage.Claims{
|
||||
UserID: "1",
|
||||
Username: "jane",
|
||||
@@ -378,14 +379,15 @@ func testRefreshTokenCRUD(t *testing.T, s storage.Storage) {
|
||||
|
||||
id2 := storage.NewID()
|
||||
refresh2 := storage.RefreshToken{
|
||||
ID: id2,
|
||||
Token: "bar_2",
|
||||
Nonce: "foo_2",
|
||||
ClientID: "client_id_2",
|
||||
ConnectorID: "client_secret",
|
||||
Scopes: []string{"openid", "email", "profile"},
|
||||
CreatedAt: time.Now().UTC().Round(time.Millisecond),
|
||||
LastUsed: time.Now().UTC().Round(time.Millisecond),
|
||||
ID: id2,
|
||||
Token: "bar_2",
|
||||
ObsoleteToken: refresh.Token,
|
||||
Nonce: "foo_2",
|
||||
ClientID: "client_id_2",
|
||||
ConnectorID: "client_secret",
|
||||
Scopes: []string{"openid", "email", "profile"},
|
||||
CreatedAt: time.Now().UTC().Round(time.Millisecond),
|
||||
LastUsed: time.Now().UTC().Round(time.Millisecond),
|
||||
Claims: storage.Claims{
|
||||
UserID: "2",
|
||||
Username: "john",
|
||||
|
@@ -132,7 +132,8 @@ func toStorageAuthRequest(a AuthRequest) storage.AuthRequest {
|
||||
type RefreshToken struct {
|
||||
ID string `json:"id"`
|
||||
|
||||
Token string `json:"token"`
|
||||
Token string `json:"token"`
|
||||
ObsoleteToken string `json:"obsolete_token"`
|
||||
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
LastUsed time.Time `json:"last_used"`
|
||||
@@ -152,6 +153,7 @@ func toStorageRefreshToken(r RefreshToken) storage.RefreshToken {
|
||||
return storage.RefreshToken{
|
||||
ID: r.ID,
|
||||
Token: r.Token,
|
||||
ObsoleteToken: r.ObsoleteToken,
|
||||
CreatedAt: r.CreatedAt,
|
||||
LastUsed: r.LastUsed,
|
||||
ClientID: r.ClientID,
|
||||
@@ -167,6 +169,7 @@ func fromStorageRefreshToken(r storage.RefreshToken) RefreshToken {
|
||||
return RefreshToken{
|
||||
ID: r.ID,
|
||||
Token: r.Token,
|
||||
ObsoleteToken: r.ObsoleteToken,
|
||||
CreatedAt: r.CreatedAt,
|
||||
LastUsed: r.LastUsed,
|
||||
ClientID: r.ClientID,
|
||||
|
@@ -496,7 +496,8 @@ type RefreshToken struct {
|
||||
ClientID string `json:"clientID"`
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
|
||||
Token string `json:"token,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
ObsoleteToken string `json:"obsoleteToken,omitempty"`
|
||||
|
||||
Nonce string `json:"nonce,omitempty"`
|
||||
|
||||
@@ -516,6 +517,7 @@ func toStorageRefreshToken(r RefreshToken) storage.RefreshToken {
|
||||
return storage.RefreshToken{
|
||||
ID: r.ObjectMeta.Name,
|
||||
Token: r.Token,
|
||||
ObsoleteToken: r.ObsoleteToken,
|
||||
CreatedAt: r.CreatedAt,
|
||||
LastUsed: r.LastUsed,
|
||||
ClientID: r.ClientID,
|
||||
@@ -538,6 +540,7 @@ func (cli *client) fromStorageRefreshToken(r storage.RefreshToken) RefreshToken
|
||||
Namespace: cli.namespace,
|
||||
},
|
||||
Token: r.Token,
|
||||
ObsoleteToken: r.ObsoleteToken,
|
||||
CreatedAt: r.CreatedAt,
|
||||
LastUsed: r.LastUsed,
|
||||
ClientID: r.ClientID,
|
||||
|
@@ -285,16 +285,16 @@ func (c *conn) CreateRefresh(r storage.RefreshToken) error {
|
||||
claims_user_id, claims_username, claims_preferred_username,
|
||||
claims_email, claims_email_verified, claims_groups,
|
||||
connector_id, connector_data,
|
||||
token, created_at, last_used
|
||||
token, obsolete_token, created_at, last_used
|
||||
)
|
||||
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);
|
||||
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16);
|
||||
`,
|
||||
r.ID, r.ClientID, encoder(r.Scopes), r.Nonce,
|
||||
r.Claims.UserID, r.Claims.Username, r.Claims.PreferredUsername,
|
||||
r.Claims.Email, r.Claims.EmailVerified,
|
||||
encoder(r.Claims.Groups),
|
||||
r.ConnectorID, r.ConnectorData,
|
||||
r.Token, r.CreatedAt, r.LastUsed,
|
||||
r.Token, r.ObsoleteToken, r.CreatedAt, r.LastUsed,
|
||||
)
|
||||
if err != nil {
|
||||
if c.alreadyExistsCheck(err) {
|
||||
@@ -329,17 +329,18 @@ func (c *conn) UpdateRefreshToken(id string, updater func(old storage.RefreshTok
|
||||
connector_id = $10,
|
||||
connector_data = $11,
|
||||
token = $12,
|
||||
created_at = $13,
|
||||
last_used = $14
|
||||
obsolete_token = $13,
|
||||
created_at = $14,
|
||||
last_used = $15
|
||||
where
|
||||
id = $15
|
||||
id = $16
|
||||
`,
|
||||
r.ClientID, encoder(r.Scopes), r.Nonce,
|
||||
r.Claims.UserID, r.Claims.Username, r.Claims.PreferredUsername,
|
||||
r.Claims.Email, r.Claims.EmailVerified,
|
||||
encoder(r.Claims.Groups),
|
||||
r.ConnectorID, r.ConnectorData,
|
||||
r.Token, r.CreatedAt, r.LastUsed, id,
|
||||
r.Token, r.ObsoleteToken, r.CreatedAt, r.LastUsed, id,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("update refresh token: %v", err)
|
||||
@@ -360,7 +361,7 @@ func getRefresh(q querier, id string) (storage.RefreshToken, error) {
|
||||
claims_email, claims_email_verified,
|
||||
claims_groups,
|
||||
connector_id, connector_data,
|
||||
token, created_at, last_used
|
||||
token, obsolete_token, created_at, last_used
|
||||
from refresh_token where id = $1;
|
||||
`, id))
|
||||
}
|
||||
@@ -372,7 +373,7 @@ func (c *conn) ListRefreshTokens() ([]storage.RefreshToken, error) {
|
||||
claims_user_id, claims_username, claims_preferred_username,
|
||||
claims_email, claims_email_verified, claims_groups,
|
||||
connector_id, connector_data,
|
||||
token, created_at, last_used
|
||||
token, obsolete_token, created_at, last_used
|
||||
from refresh_token;
|
||||
`)
|
||||
if err != nil {
|
||||
@@ -401,7 +402,7 @@ func scanRefresh(s scanner) (r storage.RefreshToken, err error) {
|
||||
&r.Claims.Email, &r.Claims.EmailVerified,
|
||||
decoder(&r.Claims.Groups),
|
||||
&r.ConnectorID, &r.ConnectorData,
|
||||
&r.Token, &r.CreatedAt, &r.LastUsed,
|
||||
&r.Token, &r.ObsoleteToken, &r.CreatedAt, &r.LastUsed,
|
||||
)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
|
@@ -274,4 +274,11 @@ var migrations = []migration{
|
||||
add column code_challenge_method text not null default '';`,
|
||||
},
|
||||
},
|
||||
{
|
||||
stmts: []string{
|
||||
`
|
||||
alter table refresh_token
|
||||
add column obsolete_token text default '';`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@@ -271,7 +271,8 @@ type RefreshToken struct {
|
||||
// A single token that's rotated every time the refresh token is refreshed.
|
||||
//
|
||||
// May be empty.
|
||||
Token string
|
||||
Token string
|
||||
ObsoleteToken string
|
||||
|
||||
CreatedAt time.Time
|
||||
LastUsed time.Time
|
||||
|
Reference in New Issue
Block a user