mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: implement oauth2 RFC 7009 token revocation endpoint (#20362)
Adds RFC 7009 token revocation endpoint
This commit is contained in:
@@ -2,32 +2,68 @@ package oauth2provider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/userpassword"
|
||||
"github.com/coder/coder/v2/cryptorand"
|
||||
)
|
||||
|
||||
type AppSecret struct {
|
||||
// Formatted contains the secret. This value is owned by the client, not the
|
||||
// server. It is formatted to include the prefix.
|
||||
Formatted string
|
||||
// Prefix is the ID of this secret owned by the server. When a client uses a
|
||||
// secret, this is the matching string to do a lookup on the hashed value. We
|
||||
// cannot use the hashed value directly because the server does not store the
|
||||
// salt.
|
||||
Prefix string
|
||||
const (
|
||||
// SecretIdentifier is the prefix added to all generated secrets.
|
||||
SecretIdentifier = "coder"
|
||||
)
|
||||
|
||||
// Constants for OAuth2 secret generation
|
||||
const (
|
||||
secretLength = 40 // Length of the actual secret part
|
||||
displaySecretLength = 6 // Length of visible part in UI (last 6 characters)
|
||||
)
|
||||
|
||||
type HashedAppSecret struct {
|
||||
AppSecret
|
||||
// Hashed is the server stored hash(secret,salt,...). Used for verifying a
|
||||
// secret.
|
||||
Hashed string
|
||||
}
|
||||
|
||||
type AppSecret struct {
|
||||
// Formatted contains the secret. This value is owned by the client, not the
|
||||
// server. It is formatted to include the prefix.
|
||||
Formatted string
|
||||
// Secret is the raw secret value. This value should only be known to the client.
|
||||
Secret string
|
||||
// Prefix is the ID of this secret owned by the server. When a client uses a
|
||||
// secret, this is the matching string to do a lookup on the hashed value. We
|
||||
// cannot use the hashed value directly because the server does not store the
|
||||
// salt.
|
||||
Prefix string
|
||||
}
|
||||
|
||||
// ParseFormattedSecret parses a formatted secret like "coder_<prefix>_<secret"
|
||||
func ParseFormattedSecret(formatted string) (AppSecret, error) {
|
||||
parts := strings.Split(formatted, "_")
|
||||
if len(parts) != 3 {
|
||||
return AppSecret{}, xerrors.Errorf("incorrect number of parts: %d", len(parts))
|
||||
}
|
||||
if parts[0] != SecretIdentifier {
|
||||
return AppSecret{}, xerrors.Errorf("incorrect scheme: %s", parts[0])
|
||||
}
|
||||
return AppSecret{
|
||||
Formatted: formatted,
|
||||
Prefix: parts[1],
|
||||
Secret: parts[2],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GenerateSecret generates a secret to be used as a client secret, refresh
|
||||
// token, or authorization code.
|
||||
func GenerateSecret() (AppSecret, error) {
|
||||
func GenerateSecret() (HashedAppSecret, error) {
|
||||
// 40 characters matches the length of GitHub's client secrets.
|
||||
secret, err := cryptorand.String(40)
|
||||
secret, err := cryptorand.String(secretLength)
|
||||
if err != nil {
|
||||
return AppSecret{}, err
|
||||
return HashedAppSecret{}, err
|
||||
}
|
||||
|
||||
// This ID is prefixed to the secret so it can be used to look up the secret
|
||||
@@ -35,17 +71,20 @@ func GenerateSecret() (AppSecret, error) {
|
||||
// will not have the salt.
|
||||
prefix, err := cryptorand.String(10)
|
||||
if err != nil {
|
||||
return AppSecret{}, err
|
||||
return HashedAppSecret{}, err
|
||||
}
|
||||
|
||||
hashed, err := userpassword.Hash(secret)
|
||||
if err != nil {
|
||||
return AppSecret{}, err
|
||||
return HashedAppSecret{}, err
|
||||
}
|
||||
|
||||
return AppSecret{
|
||||
Formatted: fmt.Sprintf("coder_%s_%s", prefix, secret),
|
||||
Prefix: prefix,
|
||||
Hashed: hashed,
|
||||
return HashedAppSecret{
|
||||
AppSecret: AppSecret{
|
||||
Formatted: fmt.Sprintf("%s_%s_%s", SecretIdentifier, prefix, secret),
|
||||
Secret: secret,
|
||||
Prefix: prefix,
|
||||
},
|
||||
Hashed: hashed,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user