Skip to content

Commit

Permalink
refactor: Move CurrentAuthenticationModesOffered from provider to broker
Browse files Browse the repository at this point in the history
The decision which authentication modes are offered is (currently) not
provider-specific. Lets make the interface simpler until we actually
have a need to make it provider-specific.
  • Loading branch information
adombeck committed Feb 4, 2025
1 parent 9ab63c6 commit ac0a46a
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 113 deletions.
44 changes: 34 additions & 10 deletions internal/broker/broker.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,6 @@ func (b *Broker) GetAuthenticationModes(sessionID string, supportedUILayouts []m

supportedAuthModes := b.supportedAuthModesFromLayout(supportedUILayouts)

log.Debugf(context.Background(), "Supported UI Layouts for session %s: %#v", sessionID, supportedUILayouts)
log.Debugf(context.Background(), "Supported Authentication modes for session %s: %#v", sessionID, supportedAuthModes)

// Checks if the token exists in the cache.
tokenExists, err := fileutils.FileExists(session.tokenPath)
if err != nil {
Expand All @@ -246,17 +243,17 @@ func (b *Broker) GetAuthenticationModes(sessionID string, supportedUILayouts []m
}
}

availableModes, err := b.provider.CurrentAuthenticationModesOffered(
session.mode,
supportedAuthModes,
tokenExists,
!session.isOffline,
endpoints,
session.currentAuthStep)
availableModes, err := b.availableAuthModes(session, tokenExists, endpoints)
if err != nil {
return nil, err
}

for _, mode := range availableModes {
if _, ok := supportedAuthModes[mode]; !ok {
return nil, fmt.Errorf("auth mode %q required by the provider, but is not supported locally", mode)
}
}

for _, id := range availableModes {
authModes = append(authModes, map[string]string{
"id": id,
Expand All @@ -276,6 +273,33 @@ func (b *Broker) GetAuthenticationModes(sessionID string, supportedUILayouts []m
return authModes, nil
}

func (b *Broker) availableAuthModes(session session, tokenExists bool, endpoints map[string]struct{}) (availableModes []string, err error) {
switch session.mode {
case sessionmode.ChangePassword, sessionmode.ChangePasswordOld:
if !tokenExists {
return nil, errors.New("user has no cached token")
}
availableModes = []string{authmodes.Password}
if session.currentAuthStep > 0 {
availableModes = []string{authmodes.NewPassword}
}

default: // auth mode
if _, ok := endpoints[authmodes.DeviceQr]; ok && !session.isOffline {
availableModes = []string{authmodes.DeviceQr}
} else if _, ok := endpoints[authmodes.Device]; ok && !session.isOffline {
availableModes = []string{authmodes.Device}
}
if tokenExists {
availableModes = append([]string{authmodes.Password}, availableModes...)
}
if session.currentAuthStep > 0 {
availableModes = []string{authmodes.NewPassword}
}
}
return availableModes, nil
}

func (b *Broker) supportedAuthModesFromLayout(supportedUILayouts []map[string]string) (supportedModes map[string]string) {
supportedModes = make(map[string]string)
for _, layout := range supportedUILayouts {
Expand Down
49 changes: 0 additions & 49 deletions internal/providers/msentraid/msentraid.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import (
msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go"
msgraphauth "github.com/microsoftgraph/msgraph-sdk-go-core/authentication"
msgraphmodels "github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/ubuntu/authd-oidc-brokers/internal/broker/authmodes"
"github.com/ubuntu/authd-oidc-brokers/internal/broker/sessionmode"
"github.com/ubuntu/authd-oidc-brokers/internal/consts"
providerErrors "github.com/ubuntu/authd-oidc-brokers/internal/providers/errors"
"github.com/ubuntu/authd-oidc-brokers/internal/providers/info"
Expand Down Expand Up @@ -280,53 +278,6 @@ func isSecurityGroup(group msgraphmodels.Groupable) bool {
return !slices.Contains(group.GetGroupTypes(), "Unified")
}

// CurrentAuthenticationModesOffered returns the generic authentication modes supported by the provider.
//
// Token validity is not considered, only the presence of a token.
func (p Provider) CurrentAuthenticationModesOffered(
sessionMode string,
supportedAuthModes map[string]string,
tokenExists bool,
providerReachable bool,
endpoints map[string]struct{},
currentAuthStep int,
) ([]string, error) {
log.Debugf(context.Background(), "In CurrentAuthenticationModesOffered: sessionMode=%q, supportedAuthModes=%q, tokenExists=%t, providerReachable=%t, endpoints=%q, currentAuthStep=%d\n", sessionMode, supportedAuthModes, tokenExists, providerReachable, endpoints, currentAuthStep)
var offeredModes []string
switch sessionMode {
case sessionmode.ChangePassword, sessionmode.ChangePasswordOld:
if !tokenExists {
return nil, errors.New("user has no cached token")
}
offeredModes = []string{authmodes.Password}
if currentAuthStep > 0 {
offeredModes = []string{authmodes.NewPassword}
}

default: // auth mode
if _, ok := endpoints[authmodes.DeviceQr]; ok && providerReachable {
offeredModes = []string{authmodes.DeviceQr}
} else if _, ok := endpoints[authmodes.Device]; ok && providerReachable {
offeredModes = []string{authmodes.Device}
}
if tokenExists {
offeredModes = append([]string{authmodes.Password}, offeredModes...)
}
if currentAuthStep > 0 {
offeredModes = []string{authmodes.NewPassword}
}
}
log.Debugf(context.Background(), "Offered modes: %q", offeredModes)

for _, mode := range offeredModes {
if _, ok := supportedAuthModes[mode]; !ok {
return nil, fmt.Errorf("auth mode %q required by the provider, but is not supported locally", mode)
}
}

return offeredModes, nil
}

// NormalizeUsername parses a username into a normalized version.
func (p Provider) NormalizeUsername(username string) string {
// Microsoft Entra usernames are case-insensitive. We can safely use strings.ToLower here without worrying about
Expand Down
46 changes: 0 additions & 46 deletions internal/providers/noprovider/noprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ package noprovider

import (
"context"
"errors"
"fmt"

"github.com/coreos/go-oidc/v3/oidc"
"github.com/ubuntu/authd-oidc-brokers/internal/broker/authmodes"
"github.com/ubuntu/authd-oidc-brokers/internal/broker/sessionmode"
"github.com/ubuntu/authd-oidc-brokers/internal/providers/info"
"golang.org/x/oauth2"
)
Expand Down Expand Up @@ -37,49 +34,6 @@ func (p NoProvider) AuthOptions() []oauth2.AuthCodeOption {
return []oauth2.AuthCodeOption{}
}

// CurrentAuthenticationModesOffered returns the generic authentication modes supported by the provider.
func (p NoProvider) CurrentAuthenticationModesOffered(
sessionMode string,
supportedAuthModes map[string]string,
tokenExists bool,
providerReachable bool,
endpoints map[string]struct{},
currentAuthStep int,
) ([]string, error) {
var offeredModes []string
switch sessionMode {
case sessionmode.ChangePassword, sessionmode.ChangePasswordOld:
if !tokenExists {
return nil, errors.New("user has no cached token")
}
offeredModes = []string{authmodes.Password}
if currentAuthStep > 0 {
offeredModes = []string{authmodes.NewPassword}
}

default: // auth mode
if _, ok := endpoints[authmodes.DeviceQr]; ok && providerReachable {
offeredModes = []string{authmodes.DeviceQr}
} else if _, ok := endpoints[authmodes.Device]; ok && providerReachable {
offeredModes = []string{authmodes.Device}
}
if tokenExists {
offeredModes = append([]string{authmodes.Password}, offeredModes...)
}
if currentAuthStep > 0 {
offeredModes = []string{authmodes.NewPassword}
}
}

for _, mode := range offeredModes {
if _, ok := supportedAuthModes[mode]; !ok {
return nil, fmt.Errorf("auth mode %q required by the provider, but is not supported locally", mode)
}
}

return offeredModes, nil
}

// GetExtraFields returns the extra fields of the token which should be stored persistently.
func (p NoProvider) GetExtraFields(token *oauth2.Token) map[string]interface{} {
return nil
Expand Down
8 changes: 0 additions & 8 deletions internal/providers/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,6 @@ type Provider interface {
AdditionalScopes() []string
AuthOptions() []oauth2.AuthCodeOption
CheckTokenScopes(token *oauth2.Token) error
CurrentAuthenticationModesOffered(
sessionMode string,
supportedAuthModes map[string]string,
tokenExists bool,
providerReachable bool,
endpoints map[string]struct{},
currentAuthStep int,
) ([]string, error)
GetExtraFields(token *oauth2.Token) map[string]interface{}
GetMetadata(provider *oidc.Provider) (map[string]interface{}, error)
GetUserInfo(ctx context.Context, accessToken *oauth2.Token, idToken *oidc.IDToken, providerMetadata map[string]interface{}) (info.User, error)
Expand Down

0 comments on commit ac0a46a

Please sign in to comment.