Skip to content
Snippets Groups Projects
Commit 1bd91852 authored by Gabriel Zachmann's avatar Gabriel Zachmann
Browse files

implement creating transfer code from existing ST

parent 104487fd
No related branches found
No related tags found
No related merge requests found
Showing
with 175 additions and 20 deletions
...@@ -55,10 +55,12 @@ features: ...@@ -55,10 +55,12 @@ features:
# Support for short super tokens # Support for short super tokens
short_tokens: short_tokens:
enabled: true enabled: true
len: 64 # Default 64, max 256
# Support for transfer codes for super tokens # Support for transfer codes for super tokens
transfer_codes: transfer_codes:
enabled: true enabled: true
len: 8 # Default 8, max 64
# Support for polling codes that are used by native applications. Only disable this if you have good reasons for it. # Support for polling codes that are used by native applications. Only disable this if you have good reasons for it.
polling_codes: polling_codes:
......
...@@ -47,8 +47,15 @@ var defaultConfig = Config{ ...@@ -47,8 +47,15 @@ var defaultConfig = Config{
model.OIDCFlowAuthorizationCode, model.OIDCFlowAuthorizationCode,
}, },
TokenRevocation: onlyEnable{true}, TokenRevocation: onlyEnable{true},
ShortTokens: onlyEnable{true}, ShortTokens: shortTokenConfig{
TransferCodes: onlyEnable{true}, Enabled: true,
Len: 64,
},
TransferCodes: transferCodeConfig{
Enabled: true,
Len: 8,
ExpiresAfter: 300,
},
Polling: pollingConf{ Polling: pollingConf{
Enabled: true, Enabled: true,
PollingCodeExpiresAfter: 300, PollingCodeExpiresAfter: 300,
...@@ -74,13 +81,24 @@ type Config struct { ...@@ -74,13 +81,24 @@ type Config struct {
} }
type featuresConf struct { type featuresConf struct {
EnabledOIDCFlows []model.OIDCFlow `yaml:"enabled_oidc_flows"` EnabledOIDCFlows []model.OIDCFlow `yaml:"enabled_oidc_flows"`
TokenRevocation onlyEnable `yaml:"token_revocation"` TokenRevocation onlyEnable `yaml:"token_revocation"`
ShortTokens onlyEnable `yaml:"short_tokens"` ShortTokens shortTokenConfig `yaml:"short_tokens"`
TransferCodes onlyEnable `yaml:"transfer_codes"` TransferCodes transferCodeConfig `yaml:"transfer_codes"`
Polling pollingConf `yaml:"polling_codes"` Polling pollingConf `yaml:"polling_codes"`
AccessTokenGrant onlyEnable `yaml:"access_token_grant"` AccessTokenGrant onlyEnable `yaml:"access_token_grant"`
SignedJWTGrant onlyEnable `yaml:"signed_jwt_grant"` SignedJWTGrant onlyEnable `yaml:"signed_jwt_grant"`
}
type shortTokenConfig struct {
Enabled bool `yaml:"enabled"`
Len int `yaml:"len"`
}
type transferCodeConfig struct {
Enabled bool `yaml:"enabled"`
Len int `yaml:"len"`
ExpiresAfter int `yaml:"expires_after"`
} }
type onlyEnable struct { type onlyEnable struct {
......
...@@ -39,7 +39,7 @@ func HandleAccessTokenEndpoint(ctx *fiber.Ctx) error { ...@@ -39,7 +39,7 @@ func HandleAccessTokenEndpoint(ctx *fiber.Ctx) error {
} }
log.Trace("Checked grant type") log.Trace("Checked grant type")
revoked, dbErr := dbUtils.CheckTokenRevoked(req.SuperToken) token, revoked, dbErr := dbUtils.CheckTokenRevoked(req.SuperToken)
if dbErr != nil { if dbErr != nil {
return model.ErrorToInternalServerErrorResponse(dbErr).Send(ctx) return model.ErrorToInternalServerErrorResponse(dbErr).Send(ctx)
} }
...@@ -51,6 +51,7 @@ func HandleAccessTokenEndpoint(ctx *fiber.Ctx) error { ...@@ -51,6 +51,7 @@ func HandleAccessTokenEndpoint(ctx *fiber.Ctx) error {
return res.Send(ctx) return res.Send(ctx)
} }
log.Trace("Checked token not revoked") log.Trace("Checked token not revoked")
req.SuperToken = token
st, err := supertoken.ParseJWT(req.SuperToken) st, err := supertoken.ParseJWT(req.SuperToken)
if err != nil { if err != nil {
......
package pkg
type CreateTransferCodeRequest struct {
SuperToken string `json:"super_token"`
}
package pkg
import (
"github.com/zachmann/mytoken/internal/model"
)
type TransferCodeResponse struct {
SuperTokenType model.ResponseType `json:"super_token_type"`
TransferCode string `json:"transfer_code"`
ExpiresIn uint64 `json:"expires_in"`
}
package super
import (
"encoding/json"
uuid "github.com/satori/go.uuid"
"github.com/jmoiron/sqlx"
"github.com/zachmann/mytoken/internal/supertoken/event"
event2 "github.com/zachmann/mytoken/internal/supertoken/event/pkg"
"github.com/zachmann/mytoken/internal/utils/dbUtils"
"github.com/zachmann/mytoken/internal/config"
"github.com/zachmann/mytoken/internal/utils"
"github.com/zachmann/mytoken/internal/db"
"github.com/gofiber/fiber/v2"
"github.com/zachmann/mytoken/internal/endpoints/token/super/pkg"
"github.com/zachmann/mytoken/internal/model"
"github.com/zachmann/mytoken/internal/utils/ctxUtils"
)
func HandleCreateTransferCodeForExistingSuperToken(ctx *fiber.Ctx) error {
token := ctxUtils.GetAuthHeaderToken(ctx)
if len(token) == 0 {
var req pkg.CreateTransferCodeRequest
if err := json.Unmarshal(ctx.Body(), &req); err != nil {
res := &model.Response{
Status: fiber.StatusBadRequest,
Response: model.BadRequestError(err.Error()),
}
return res.Send(ctx)
}
token = req.SuperToken
if len(token) == 0 {
res := &model.Response{
Status: fiber.StatusUnauthorized,
Response: model.BadRequestError("required parameter 'super_token' missing"),
}
return res.Send(ctx)
}
}
superToken, revoked, dbErr := dbUtils.CheckTokenRevoked(token)
if dbErr != nil {
return model.ErrorToInternalServerErrorResponse(dbErr).Send(ctx)
}
if revoked {
res := &model.Response{
Status: fiber.StatusUnauthorized,
Response: model.InvalidTokenError("token not valid"),
}
return res.Send(ctx)
}
transferCode := utils.RandASCIIString(config.Get().Features.TransferCodes.Len)
expiresIn := config.Get().Features.TransferCodes.ExpiresAfter
var stid uuid.UUID
if err := db.Transact(func(tx *sqlx.Tx) error {
if err := tx.Get(&stid, `SELECT id FROM SuperTokens WHERE token=?`, superToken); err != nil {
return err
}
if _, err := tx.Exec(`INSERT INTO TransferCodes (transfer_code, ST_id, expires_in, new_st) VALUES(?,?,?,0)`, transferCode, stid, expiresIn); err != nil {
return err
}
return nil
}); err != nil {
return model.ErrorToInternalServerErrorResponse(err).Send(ctx)
}
if err := event.LogEvent(&event2.Event{
Type: event2.STEventTransferCodeCreated,
Comment: "from existing ST",
}, stid, *ctxUtils.NetworkData(ctx)); err != nil {
return model.ErrorToInternalServerErrorResponse(err).Send(ctx)
}
res := &model.Response{
Status: fiber.StatusOK,
Response: pkg.TransferCodeResponse{
SuperTokenType: model.ResponseTypeTransferCode,
TransferCode: transferCode,
ExpiresIn: uint64(expiresIn),
},
}
return res.Send(ctx)
}
...@@ -68,7 +68,7 @@ func (g *GrantType) UnmarshalJSON(data []byte) error { ...@@ -68,7 +68,7 @@ func (g *GrantType) UnmarshalJSON(data []byte) error {
return nil return nil
} }
func (g *GrantType) MarshalJSON() ([]byte, error) { func (g GrantType) MarshalJSON() ([]byte, error) {
return json.Marshal(g.String()) return json.Marshal(g.String())
} }
......
...@@ -64,7 +64,7 @@ func (f *OIDCFlow) UnmarshalJSON(data []byte) error { ...@@ -64,7 +64,7 @@ func (f *OIDCFlow) UnmarshalJSON(data []byte) error {
return nil return nil
} }
func (f *OIDCFlow) MarshalJSON() ([]byte, error) { func (f OIDCFlow) MarshalJSON() ([]byte, error) {
return json.Marshal(f.String()) return json.Marshal(f.String())
} }
......
...@@ -65,7 +65,7 @@ func (r *ResponseType) UnmarshalJSON(data []byte) error { ...@@ -65,7 +65,7 @@ func (r *ResponseType) UnmarshalJSON(data []byte) error {
return nil return nil
} }
func (r *ResponseType) MarshalJSON() ([]byte, error) { func (r ResponseType) MarshalJSON() ([]byte, error) {
return json.Marshal(r.String()) return json.Marshal(r.String())
} }
......
...@@ -21,4 +21,7 @@ func addAPIv0Routes(s fiber.Router) { ...@@ -21,4 +21,7 @@ func addAPIv0Routes(s fiber.Router) {
if config.Get().Features.TokenRevocation.Enabled { if config.Get().Features.TokenRevocation.Enabled {
tokens.Post("/revoke", revocation.HandleRevoke) tokens.Post("/revoke", revocation.HandleRevoke)
} }
if config.Get().Features.TransferCodes.Enabled {
tokens.Post("/transfer", super.HandleCreateTransferCodeForExistingSuperToken)
}
} }
...@@ -62,7 +62,7 @@ func eventStringToInt(str string) int { ...@@ -62,7 +62,7 @@ func eventStringToInt(str string) int {
} }
// AllEvents hold all possible Events // AllEvents hold all possible Events
var allEvents = [...]string{"unknown", "AT_created", "ST_created", "tokeninfo_history", "tokeninfo_tree", "tokeninfo_list_super_tokens", "mng_enabled_AT_grant", "mng_disabled_AT_grant", "mng_enabled_JWT_grant", "mng_disabled_JWT_grant", "mng_linked_grant", "mng_unlinked_grant", "mng_enabled_tracing", "mng_disabled_tracing", "inherited_RT"} var allEvents = [...]string{"unknown", "AT_created", "ST_created", "tokeninfo_history", "tokeninfo_tree", "tokeninfo_list_super_tokens", "mng_enabled_AT_grant", "mng_disabled_AT_grant", "mng_enabled_JWT_grant", "mng_disabled_JWT_grant", "mng_linked_grant", "mng_unlinked_grant", "mng_enabled_tracing", "mng_disabled_tracing", "inherited_RT", "transfer_code_created", "transfer_code_used"}
// Events for SuperTokens // Events for SuperTokens
const ( const (
...@@ -81,5 +81,7 @@ const ( ...@@ -81,5 +81,7 @@ const (
STEventMngTracingEnabled STEventMngTracingEnabled
STEventMngTracingDisabled STEventMngTracingDisabled
STEventInheritedRT STEventInheritedRT
STEventTransferCodeCreated
STEventTransferCodeUsed
maxEvent maxEvent
) )
...@@ -38,7 +38,7 @@ func HandleSuperTokenFromSuperToken(ctx *fiber.Ctx) *model.Response { ...@@ -38,7 +38,7 @@ func HandleSuperTokenFromSuperToken(ctx *fiber.Ctx) *model.Response {
// GrantType already checked // GrantType already checked
revoked, dbErr := dbUtils.CheckTokenRevoked(req.SuperToken) token, revoked, dbErr := dbUtils.CheckTokenRevoked(req.SuperToken)
if dbErr != nil { if dbErr != nil {
return model.ErrorToInternalServerErrorResponse(dbErr) return model.ErrorToInternalServerErrorResponse(dbErr)
} }
...@@ -49,6 +49,7 @@ func HandleSuperTokenFromSuperToken(ctx *fiber.Ctx) *model.Response { ...@@ -49,6 +49,7 @@ func HandleSuperTokenFromSuperToken(ctx *fiber.Ctx) *model.Response {
} }
} }
log.Trace("Checked token not revoked") log.Trace("Checked token not revoked")
req.SuperToken = token
st, err := supertoken.ParseJWT(req.SuperToken) st, err := supertoken.ParseJWT(req.SuperToken)
if err != nil { if err != nil {
......
package ctxUtils
import (
"strings"
"github.com/gofiber/fiber/v2"
)
func GetAuthHeaderToken(ctx *fiber.Ctx) (token string) {
authHeader := string(ctx.Request().Header.Peek("Authorization"))
if strings.HasPrefix(strings.ToLower(authHeader), "bearer ") {
token = authHeader[7:]
}
return
}
...@@ -73,13 +73,22 @@ FROM childs ...@@ -73,13 +73,22 @@ FROM childs
return err return err
} }
func CheckTokenRevoked(token string) (bool, error) { // CheckTokenRevoked takes a short super token or a normal super token and checks if it was revoked. If the token is found in the db, the super token string will be returned.
// Therefore, this function can also be used to exchange a short super token into a normal one.
func CheckTokenRevoked(token string) (string, bool, error) {
var count int var count int
if err := db.DB().Get(&count, `SELECT COUNT(1) FROM SuperTokens WHERE token=?`, token); err != nil { if err := db.DB().Get(&count, `SELECT COUNT(1) FROM SuperTokens WHERE token=?`, token); err != nil {
return true, err return token, true, err
} }
if count == 0 { if count > 0 { // token was found as SuperToken
return true, nil return token, false, nil
} }
return false, nil var superToken string
if err := db.DB().Get(&superToken, `SELECT token FROM ShortSuperTokensV WHERE short_token=?`, token); err != nil {
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
return token, true, err
}
return superToken, true, nil
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment