Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ in addition to information about authd architecture and troubleshooting.
## Brokers

authd uses brokers to interface with cloud identity providers through a
[DBus API](https://github.com/ubuntu/authd/blob/HEAD/examplebroker/com.ubuntu.auth.ExampleBroker.xml).
[DBus API](https://github.com/ubuntu/authd/blob/HEAD/internal/examplebroker/com.ubuntu.auth.ExampleBroker.xml).

Currently [MS Entra ID](https://learn.microsoft.com/en-us/entra/fundamentals/whatis)
and [Google IAM](https://cloud.google.com/iam/docs/overview)
Expand Down
19 changes: 19 additions & 0 deletions brokers/auth/authmode.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
5 changes: 5 additions & 0 deletions brokers/auth/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//go:build generate

//go:generate go run -tags generate ../../internal/cmd/types-parser -source-package "github.com/ubuntu/authd/internal/proto/authd" -types "authd.GAMResponse_AuthenticationMode" -types-aliases "Mode" -package auth -output ./authmode.go -converter ../../internal/proto/authd/authmode.go -converter-import "github.com/ubuntu/authd/brokers/auth" -converter-package "authd"

package auth
81 changes: 81 additions & 0 deletions brokers/auth/mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package auth

import (
"fmt"

"github.com/ubuntu/authd/brokers/layouts"
)

// InvalidModeError defines an error for invalid [Mode] errors.
type InvalidModeError struct {
Message string
}

// Error is the implementation of the error interface.
func (e InvalidModeError) Error() string {
return e.Message
}

// Is makes this error insensitive to the actual error content.
func (InvalidModeError) Is(err error) bool { return err == InvalidModeError{} }

// ModeOptions is the function signature used to tweak the qrcode.
type ModeOptions func(*Mode)

// NewMode allows to create a new [Mode] with [ModeOptions].
func NewMode(id, label string, opts ...ModeOptions) Mode {
mode := Mode{Id: id, Label: label}
for _, opt := range opts {
opt(&mode)
}

return mode
}

// ToMap creates a string map from the [Mode] that is used by DBus protocol.
func (mode Mode) ToMap() (map[string]string, error) {
if mode.Id == "" {
return nil, InvalidModeError{"invalid empty mode ID"}
}
if mode.Label == "" {
return nil, InvalidModeError{"invalid empty mode label"}
}

return map[string]string{
layouts.ID: mode.Id,
layouts.Label: mode.Label,
}, nil
}

// NewModeFromMap allows to create a new [Mode] from a map of strings how it's used in the DBus protocol.
func NewModeFromMap(mode map[string]string) (Mode, error) {
id := mode[layouts.ID]
label := mode[layouts.Label]

if id == "" {
return Mode{}, InvalidModeError{
fmt.Sprintf("invalid authentication mode, missing %q key: %v", layouts.ID, mode),
}
}
if label == "" {
return Mode{}, InvalidModeError{
fmt.Sprintf("invalid authentication mode, missing %q key: %v", layouts.Label, mode),
}
}

return NewMode(id, label), nil
}

// NewModeMaps creates a list of string maps from the list of [Mode] how it's used by DBus protocol.
func NewModeMaps(modes []Mode) ([]map[string]string, error) {
var maps []map[string]string

for _, m := range modes {
m, err := m.ToMap()
if err != nil {
return nil, err
}
maps = append(maps, m)
}
return maps, nil
}
152 changes: 152 additions & 0 deletions brokers/auth/mode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package auth_test

import (
"testing"

"github.com/stretchr/testify/require"
"github.com/ubuntu/authd/brokers/auth"
"github.com/ubuntu/authd/brokers/layouts"
)

func TestAuthModeMap(t *testing.T) {
t.Parallel()

testCases := map[string]struct {
id string
label string

want map[string]string
wantError error
}{
"Simple": {
id: "some-id",
label: "Some Label",
want: map[string]string{
layouts.ID: "some-id",
layouts.Label: "Some Label",
},
},

// Error cases.
"Error on Empty ID": {
wantError: auth.InvalidModeError{},
},
"Error on Empty Label": {
id: "some-id",
wantError: auth.InvalidModeError{},
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
t.Parallel()

mode := auth.NewMode(tc.id, tc.label)
require.NotNil(t, mode, "Setup: Mode creation failed")

m, err := mode.ToMap()
require.ErrorIs(t, err, tc.wantError)
require.Equal(t, tc.want, m)

if tc.wantError != nil {
return
}

newMode, err := auth.NewModeFromMap(m)
require.NoError(t, err)
require.Equal(t, mode, newMode)
})
}
}

func TestAuthModesFromMapErrors(t *testing.T) {
t.Parallel()

testCases := map[string]struct {
id string
wantError error
}{
"Error on Empty ID": {},
"Error on Empty Label": {
id: "some-id",
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
t.Parallel()

newMode, err := auth.NewModeFromMap(map[string]string{
layouts.ID: tc.id,
})
require.Zero(t, newMode, "Mode should be unset")
require.ErrorIs(t, err, auth.InvalidModeError{})
})
}
}

func TestModeList(t *testing.T) {
t.Parallel()

testCases := map[string]struct {
modes []auth.Mode

want []map[string]string
wantError error
}{
"Empty": {},
"Single mode": {
modes: []auth.Mode{
auth.NewMode("some-id", "Some Label"),
},
want: []map[string]string{
{
layouts.ID: "some-id",
layouts.Label: "Some Label",
},
},
},
"Multiple modes": {
modes: []auth.Mode{
auth.NewMode("some-id", "Some Label"),
auth.NewMode("some-other-id", "Some Other Label"),
},
want: []map[string]string{
{
layouts.ID: "some-id",
layouts.Label: "Some Label",
},
{
layouts.ID: "some-other-id",
layouts.Label: "Some Other Label",
},
},
},

// Error cases
"Error for invalid ID": {
modes: []auth.Mode{
auth.NewMode("some-id", "Some Label"),
auth.NewMode("", ""),
auth.NewMode("some-other-id", "Some Other Label"),
},
wantError: auth.InvalidModeError{},
},
// Error cases
"Error for invalid Label": {
modes: []auth.Mode{
auth.NewMode("some-id", "Some Label"),
auth.NewMode("some-id", ""),
auth.NewMode("some-other-id", "Some Other Label"),
},
wantError: auth.InvalidModeError{},
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
t.Parallel()

maps, err := auth.NewModeMaps(tc.modes)
require.ErrorIs(t, err, tc.wantError)
require.Equal(t, tc.want, maps)
})
}
}
File renamed without changes.
5 changes: 5 additions & 0 deletions brokers/layouts/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//go:build generate

//go:generate go run -tags generate ../../internal/cmd/types-parser -source-package "github.com/ubuntu/authd/internal/proto/authd" -types "authd.UILayout" -types-aliases "UILayout" -package layouts -output ./uilayout.go -converter ../../internal/proto/authd/uilayout.go -converter-import "github.com/ubuntu/authd/brokers/layouts" -converter-package "authd"

package layouts
Loading
Loading