feat: token introspection (#83)
* introspect * introspect and client assertion * introspect and client assertion * scopes * token introspection * introspect * refactoring * fixes * clenaup * Update example/internal/mock/storage.go Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * clenaup Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
parent
fa92a20615
commit
1518c843de
46 changed files with 1672 additions and 570 deletions
|
@ -1,7 +1,10 @@
|
|||
package oidc
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
|
@ -14,6 +17,8 @@ import (
|
|||
const (
|
||||
//BearerToken defines the token_type `Bearer`, which is returned in a successful token response
|
||||
BearerToken = "Bearer"
|
||||
|
||||
PrefixBearer = BearerToken + " "
|
||||
)
|
||||
|
||||
type Tokens struct {
|
||||
|
@ -397,7 +402,7 @@ type AccessTokenResponse struct {
|
|||
type JWTProfileAssertion struct {
|
||||
PrivateKeyID string `json:"-"`
|
||||
PrivateKey []byte `json:"-"`
|
||||
Issuer string `json:"issuer"`
|
||||
Issuer string `json:"iss"`
|
||||
Subject string `json:"sub"`
|
||||
Audience Audience `json:"aud"`
|
||||
Expiration Time `json:"exp"`
|
||||
|
@ -412,6 +417,19 @@ func NewJWTProfileAssertionFromKeyJSON(filename string, audience []string) (*JWT
|
|||
return NewJWTProfileAssertionFromFileData(data, audience)
|
||||
}
|
||||
|
||||
func NewJWTProfileAssertionStringFromFileData(data []byte, audience []string) (string, error) {
|
||||
keyData := new(struct {
|
||||
KeyID string `json:"keyId"`
|
||||
Key string `json:"key"`
|
||||
UserID string `json:"userId"`
|
||||
})
|
||||
err := json.Unmarshal(data, keyData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return GenerateJWTProfileToken(NewJWTProfileAssertion(keyData.UserID, keyData.KeyID, audience, []byte(keyData.Key)))
|
||||
}
|
||||
|
||||
func NewJWTProfileAssertionFromFileData(data []byte, audience []string) (*JWTProfileAssertion, error) {
|
||||
keyData := new(struct {
|
||||
KeyID string `json:"keyId"`
|
||||
|
@ -454,3 +472,46 @@ func AppendClientIDToAudience(clientID string, audience []string) []string {
|
|||
}
|
||||
return append(audience, clientID)
|
||||
}
|
||||
|
||||
func GenerateJWTProfileToken(assertion *JWTProfileAssertion) (string, error) {
|
||||
privateKey, err := bytesToPrivateKey(assertion.PrivateKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
key := jose.SigningKey{
|
||||
Algorithm: jose.RS256,
|
||||
Key: &jose.JSONWebKey{Key: privateKey, KeyID: assertion.PrivateKeyID},
|
||||
}
|
||||
signer, err := jose.NewSigner(key, &jose.SignerOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
marshalledAssertion, err := json.Marshal(assertion)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
signedAssertion, err := signer.Sign(marshalledAssertion)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return signedAssertion.CompactSerialize()
|
||||
}
|
||||
|
||||
func bytesToPrivateKey(priv []byte) (*rsa.PrivateKey, error) {
|
||||
block, _ := pem.Decode(priv)
|
||||
enc := x509.IsEncryptedPEMBlock(block)
|
||||
b := block.Bytes
|
||||
var err error
|
||||
if enc {
|
||||
b, err = x509.DecryptPEMBlock(block, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
key, err := x509.ParsePKCS1PrivateKey(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue