2023-04-19 08:46:02 +00:00
|
|
|
package oidc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2024-05-16 05:07:56 +00:00
|
|
|
"slices"
|
2023-04-19 08:46:02 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/zitadel/logging"
|
2024-05-16 05:07:56 +00:00
|
|
|
"github.com/zitadel/oidc/v3/pkg/oidc"
|
2023-10-17 15:19:51 +00:00
|
|
|
"github.com/zitadel/oidc/v3/pkg/op"
|
2023-04-19 08:46:02 +00:00
|
|
|
|
|
|
|
"github.com/zitadel/zitadel/internal/api/ui/login"
|
|
|
|
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
DeviceAuthDefaultLifetime = 5 * time.Minute
|
|
|
|
DeviceAuthDefaultPollInterval = 5 * time.Second
|
|
|
|
)
|
|
|
|
|
|
|
|
type DeviceAuthorizationConfig struct {
|
|
|
|
Lifetime time.Duration
|
|
|
|
PollInterval time.Duration
|
|
|
|
UserCode *UserCodeConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
type UserCodeConfig struct {
|
|
|
|
CharSet string
|
|
|
|
CharAmount int
|
|
|
|
DashInterval int
|
|
|
|
}
|
|
|
|
|
|
|
|
// toOPConfig converts DeviceAuthorizationConfig to a [op.DeviceAuthorizationConfig],
|
|
|
|
// setting sane defaults for empty values.
|
|
|
|
// Safe to call when c is nil.
|
|
|
|
func (c *DeviceAuthorizationConfig) toOPConfig() op.DeviceAuthorizationConfig {
|
|
|
|
out := op.DeviceAuthorizationConfig{
|
|
|
|
Lifetime: DeviceAuthDefaultLifetime,
|
|
|
|
PollInterval: DeviceAuthDefaultPollInterval,
|
|
|
|
UserFormPath: login.EndpointDeviceAuth,
|
|
|
|
UserCode: op.UserCodeBase20,
|
|
|
|
}
|
|
|
|
if c == nil {
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
if c.Lifetime != 0 {
|
|
|
|
out.Lifetime = c.Lifetime
|
|
|
|
}
|
|
|
|
if c.PollInterval != 0 {
|
|
|
|
out.PollInterval = c.PollInterval
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.UserCode == nil {
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
if c.UserCode.CharSet != "" {
|
|
|
|
out.UserCode.CharSet = c.UserCode.CharSet
|
|
|
|
}
|
|
|
|
if c.UserCode.CharAmount != 0 {
|
|
|
|
out.UserCode.CharAmount = c.UserCode.CharAmount
|
|
|
|
}
|
|
|
|
if c.UserCode.DashInterval != 0 {
|
|
|
|
out.UserCode.DashInterval = c.UserCode.CharAmount
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
// StoreDeviceAuthorization creates a new Device Authorization request.
|
|
|
|
// Implements the op.DeviceAuthorizationStorage interface.
|
2024-04-03 06:06:21 +00:00
|
|
|
func (o *OPStorage) StoreDeviceAuthorization(ctx context.Context, clientID, deviceCode, userCode string, expires time.Time, scope []string) (err error) {
|
2023-04-19 08:46:02 +00:00
|
|
|
const logMsg = "store device authorization"
|
2024-04-03 06:06:21 +00:00
|
|
|
logger := logging.WithFields("client_id", clientID, "device_code", deviceCode, "user_code", userCode, "expires", expires, "scope", scope)
|
2023-04-19 08:46:02 +00:00
|
|
|
|
|
|
|
ctx, span := tracing.NewSpan(ctx)
|
|
|
|
defer func() {
|
|
|
|
logger.OnError(err).Error(logMsg)
|
|
|
|
span.EndWithError(err)
|
|
|
|
}()
|
2024-04-03 06:06:21 +00:00
|
|
|
scope, audience, err := o.createAuthRequestScopeAndAudience(ctx, clientID, scope)
|
2023-04-19 08:46:02 +00:00
|
|
|
if err != nil {
|
2024-04-03 06:06:21 +00:00
|
|
|
return err
|
2023-04-19 08:46:02 +00:00
|
|
|
}
|
2024-05-16 05:07:56 +00:00
|
|
|
details, err := o.command.AddDeviceAuth(ctx, clientID, deviceCode, userCode, expires, scope, audience, slices.Contains(scope, oidc.ScopeOfflineAccess))
|
2023-04-19 08:46:02 +00:00
|
|
|
if err == nil {
|
2023-12-20 12:21:08 +00:00
|
|
|
logger.SetFields("details", details).Debug(logMsg)
|
2023-04-19 08:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-05-16 05:07:56 +00:00
|
|
|
func (o *OPStorage) GetDeviceAuthorizatonState(ctx context.Context, _, deviceCode string) (state *op.DeviceAuthorizationState, err error) {
|
|
|
|
return nil, nil
|
2023-04-19 08:46:02 +00:00
|
|
|
}
|