From adfbc48b241971dfea034c0782cbbb037b5b3389 Mon Sep 17 00:00:00 2001 From: Hidetake Iwata Date: Sat, 24 Dec 2022 19:10:21 +0900 Subject: [PATCH] Handle verification_url field in device flow (#846) --- .../authentication/devicecode/devicecode.go | 11 +++++--- .../devicecode/devicecode_test.go | 27 +++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/pkg/usecases/authentication/devicecode/devicecode.go b/pkg/usecases/authentication/devicecode/devicecode.go index 098d771..1125167 100644 --- a/pkg/usecases/authentication/devicecode/devicecode.go +++ b/pkg/usecases/authentication/devicecode/devicecode.go @@ -26,14 +26,19 @@ func (u *DeviceCode) Do(ctx context.Context, in *Option, oidcClient client.Inter authResponse, err := oidcClient.GetDeviceAuthorization(ctx) if err != nil { - return nil, err + return nil, fmt.Errorf("authorization error: %w", err) } - if authResponse.VerificationURIComplete == "" { + if authResponse.VerificationURIComplete != "" { + u.openURL(ctx, in, authResponse.VerificationURIComplete) + } else if authResponse.VerificationURI != "" { u.Logger.Printf("Please enter the following code when asked in your browser: %s", authResponse.UserCode) u.openURL(ctx, in, authResponse.VerificationURI) + } else if authResponse.VerificationURL != "" { + u.Logger.Printf("Please enter the following code when asked in your browser: %s", authResponse.UserCode) + u.openURL(ctx, in, authResponse.VerificationURL) } else { - u.openURL(ctx, in, authResponse.VerificationURIComplete) + return nil, fmt.Errorf("no verification URI in the authorization response") } tokenSet, err := oidcClient.ExchangeDeviceCode(ctx, authResponse) diff --git a/pkg/usecases/authentication/devicecode/devicecode_test.go b/pkg/usecases/authentication/devicecode/devicecode_test.go index 949d882..5dbbce8 100644 --- a/pkg/usecases/authentication/devicecode/devicecode_test.go +++ b/pkg/usecases/authentication/devicecode/devicecode_test.go @@ -94,6 +94,33 @@ func TestDeviceCode(t *testing.T) { } }) + t.Run("Server returns verification_url", func(t *testing.T) { + mockBrowser := browser.NewMockInterface(t) + mockClient := client.NewMockInterface(t) + dc := &DeviceCode{ + Browser: mockBrowser, + Logger: logger.New(t), + } + mockResponse := &oauth2dev.AuthorizationResponse{ + DeviceCode: "device-code-1", + VerificationURL: "https://example.com/verificationCompleteURL", + ExpiresIn: 2, + Interval: 1, + } + mockClient.EXPECT().GetDeviceAuthorization(ctx).Return(mockResponse, nil).Once() + mockBrowser.EXPECT().Open("https://example.com/verificationCompleteURL").Return(nil).Once() + mockClient.EXPECT().ExchangeDeviceCode(mock.Anything, mockResponse).Return(&oidc.TokenSet{ + IDToken: "test-id-token", + }, nil).Once() + ts, err := dc.Do(ctx, &Option{}, mockClient) + if err != nil { + t.Errorf("returned unexpected error: %v", err) + } + if ts.IDToken != "test-id-token" { + t.Errorf("wrong returned tokenset: %v", err) + } + }) + t.Run("Error when exchanging the device code", func(t *testing.T) { mockBrowser := browser.NewMockInterface(t) mockClient := client.NewMockInterface(t)