Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for 3LO loopback flow #132

Merged
merged 30 commits into from
Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
77b4169
initial commit
ulisesL Jun 21, 2022
5c06a86
Added DisableAutoOpenConsentPage option. Removed ConsentPageAllowRedi…
ulisesL Jun 22, 2022
af6fde4
Modify getTimeDuration to handle incorrect units.
ulisesL Jun 22, 2022
5a36623
Improve comments for OverriddenURI.
ulisesL Jun 22, 2022
6f719ce
Introduce maxWaitForListenAndServe constant.
ulisesL Jun 22, 2022
4d833c0
Fix comment for consent page parameters.
ulisesL Jun 22, 2022
d9850f6
Remove Test3LOFlow fetch; 3lo; old interface --scope flag
ulisesL Jun 22, 2022
436cd0c
Improve '--credentials' description.
ulisesL Jun 22, 2022
5324b06
Move consent page options.
ulisesL Jun 22, 2022
e2035a8
Move consent page parameters.
ulisesL Jun 22, 2022
7636cb6
Rename localhost.go to loopback.go and add description.
ulisesL Jun 25, 2022
6b3169e
Add TODO to remove Test3LOFlow and rename tests in test3LOLoopbackFlow.
ulisesL Jun 25, 2022
7748c3e
Add --scope option in 'old interface' test in Test3LOLoopbackFlow.
ulisesL Jun 25, 2022
d3b8729
Fix usage of --disableAutoOpenConsentPage and documentation.
ulisesL Jun 25, 2022
ca8ff9f
Create clientIDFile util file.
ulisesL Jun 26, 2022
b7e21a0
Remove empty lines in cli_test.go and browser.go
ulisesL Jun 26, 2022
ba2e96e
Remove OverriddenURI logic.
ulisesL Jun 26, 2022
5359ff5
Fix regex expression in createKey in cache.go.
ulisesL Jun 26, 2022
affb2a1
Fix redirect_uris replacement in createKey in cache.go
ulisesL Jun 26, 2022
e1c9371
Move authorization handlers out of main. Remove extra empty lines.
ulisesL Jun 27, 2022
c0720d7
Rename clientIdFile.go.
ulisesL Jun 27, 2022
b9c9033
Fix typos.
ulisesL Jun 28, 2022
9359ce2
Improve comments in auth-handlers.go.
ulisesL Jun 28, 2022
2f44228
Reduce branching when handling 3LO loopback in main.
ulisesL Jun 28, 2022
90adb9f
Move consentPageSettings logic inside 3LO loopback case.
ulisesL Jun 28, 2022
0d26dec
Change scope of defer function in main. It should be inside the 3LO l…
ulisesL Jun 28, 2022
c4ea4be
Remove empty lines in loopback.go
ulisesL Jun 28, 2022
fd3c1ba
Print something saying could not auto open URL if OpenURL errors.
ulisesL Jun 28, 2022
2b43ee5
Replace ReplaceContentAll with strings.Replace.
ulisesL Jun 28, 2022
8ff4908
Fix TestServiceAccountImpersonationFlow.
ulisesL Jun 28, 2022
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
Prev Previous commit
Next Next commit
Move authorization handlers out of main. Remove extra empty lines.
  • Loading branch information
ulisesL committed Jun 27, 2022
commit e1c93715d576fe8247da50c5c9285abad7ec920e
77 changes: 1 addition & 76 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,13 @@ package main
import (
"fmt"
"io/ioutil"
"net/url"
"os"
"regexp"
"strings"
"time"

"github.com/google/oauth2l/util"
"github.com/jessevdk/go-flags"

"golang.org/x/oauth2/authhandler"
)

const (
Expand Down Expand Up @@ -145,76 +142,6 @@ func readJSON(file string) (string, error) {
return "", nil
}

// 3LO authorization handler. Determines what algorithm to use
// to get the authorization code.
//
// Note that the "state" parameter is used to prevent CSRF attacks.
func cmdAuthorizationHandler(state string, consentSettings util.ConsentPageSettings,
authCodeServer *util.AuthorizationCodeServer) authhandler.AuthorizationHandler {
return func(authCodeURL string) (string, string, error) {

decodedValue, _ := url.ParseQuery(authCodeURL)
redirectURL := decodedValue.Get("redirect_uri")

if strings.Contains(redirectURL, "localhost") {
return cmdAuthorizationLoopback(authCodeURL, consentSettings, authCodeServer)
}

return cmdAuthorizationInteractive(state, authCodeURL)
}
}

// Interactive 3LO authorization. Prints the authorization URL on stdout
// and reads the authorization code from stdin.
//
// Note that the "state" parameter is used to prevent CSRF attacks.
// For convenience, cmdAuthorizationInteractive returns a pre-configured state
// instead of requiring the user to copy it from the browser.
func cmdAuthorizationInteractive(state string, authCodeURL string) (string, string, error) {
fmt.Printf("Go to the following link in your browser:\n\n %s\n\n", authCodeURL)
fmt.Println("Enter authorization code:")
var code string
fmt.Scanln(&code)
return code, state, nil
}

// Loopback 3LO authorization. Prints the authorization URL on stdout
// and opens a new browser window and redirects it to the authCodeURL.
// It then reads the authorization code from a localhost endpoint.
//
// Note that the "state" parameter is used to prevent CSRF attacks.
// For convenience, cmdAuthorizationLoopback returns the state
// associated with the authorization code sent to the localhost.
func cmdAuthorizationLoopback(authCodeURL string, consentSettings util.ConsentPageSettings,
authCodeServer *util.AuthorizationCodeServer) (string, string, error) {

const (
// Max wait time for the server to start listening and serving
maxWaitForListenAndServe time.Duration = 10 * time.Second
)

started, _ := (*authCodeServer).WaitForListeningAndServing(maxWaitForListenAndServe)

if started {

// Auto open consent disabled - true case
if consentSettings.DisableAutoOpenConsentPage {
fmt.Println("Go to the following link in your browser:")
fmt.Println("\n", authCodeURL)
} else {
fmt.Println("Your browser has been opened to visit:")
fmt.Println("\n", authCodeURL)

b := util.Browser{}
b.OpenURL(authCodeURL)
}

(*authCodeServer).WaitForConsentPageToReturnControl()
}
code, err := (*authCodeServer).GetAuthenticationCode()
return code.Code, code.State, err
}

// Append Google OAuth scope prefix if not provided and joins
// the slice into a whitespace-separated string.
func parseScopes(scopes []string) string {
Expand Down Expand Up @@ -256,7 +183,6 @@ func getCommonFetchOptions(cmdOpts commandOptions, cmd string) commonFetchOption

// Generates a time duration
func getTimeDuration(quantity int, units string) (time.Duration, error) {

switch units {
case "seconds":
return time.Duration(quantity) * time.Second, nil
Expand Down Expand Up @@ -321,7 +247,6 @@ func getInfoOptions(cmdOpts commandOptions, cmd string) infoOptions {
}

func main() {

var authCodeServer util.AuthorizationCodeServer = nil
ulisesL marked this conversation as resolved.
Show resolved Hide resolved
defer func() {
if authCodeServer != nil {
Expand Down Expand Up @@ -494,7 +419,7 @@ func main() {
settings = &util.Settings{
CredentialsJSON: json,
Scope: parseScopes(scopes),
AuthHandler: cmdAuthorizationHandler(defaultState, consentPageSettings, &authCodeServer),
AuthHandler: util.Get3LOAuthorizationHandler(defaultState, consentPageSettings, &authCodeServer),
State: defaultState,
Audience: audience,
QuotaProject: quotaProject,
Expand Down
99 changes: 99 additions & 0 deletions util/auth-handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//
// Copyright 2020 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Contains authorization handler functions.
package util

import (
"fmt"
"net/url"
"strings"
"time"

"golang.org/x/oauth2/authhandler"
)

// 3LO authorization handler. Determines what algorithm to use
// to get the authorization code.
//
// Note that the "state" parameter is used to prevent CSRF attacks.
func Get3LOAuthorizationHandler(state string, consentSettings ConsentPageSettings,
authCodeServer *AuthorizationCodeServer) authhandler.AuthorizationHandler {
return func(authCodeURL string) (string, string, error) {
decodedValue, _ := url.ParseQuery(authCodeURL)
redirectURL := decodedValue.Get("redirect_uri")

if strings.Contains(redirectURL, "localhost") {
return authorization3LOLoopback(authCodeURL, consentSettings, authCodeServer)
}

return authorization3LOOutOfBand(state, authCodeURL)
}
}

// authorization3LOOutOfBand prints the authorization URL on stdout
// and reads the authorization code from stdin.
//
// Note that the "state" parameter is used to prevent CSRF attacks.
// For convenience, cmdAuthorizationInteractive returns a pre-configured state
ulisesL marked this conversation as resolved.
Show resolved Hide resolved
// instead of requiring the user to copy it from the browser.
func authorization3LOOutOfBand(state string, authCodeURL string) (string, string, error) {
fmt.Printf("Go to the following link in your browser:\n\n %s\n\n", authCodeURL)
fmt.Println("Enter authorization code:")
var code string
fmt.Scanln(&code)
return code, state, nil
}

// authorization3LOLoopback prints the authorization URL on stdout
// and redirects the user to the authCodeURL in a new browser's tab.
// if `DisableAutoOpenConsentPage` is set, then the user is instructed
// to manually open the authCodeURL in a new browser's tab.
//
// The code and state output parameters in this function are the same
// as the ones generated after the user grants permission on the consent page.
// When the user interacts with the consent page, an error or a code-status-tuple
ulisesL marked this conversation as resolved.
Show resolved Hide resolved
// is expected to be returned to the Auth Code Localhost Server endpoint
// (see loopback.go for more info).
func authorization3LOLoopback(authCodeURL string, consentSettings ConsentPageSettings,
authCodeServer *AuthorizationCodeServer) (string, string, error) {
const (
// Max wait time for the server to start listening and serving
maxWaitForListenAndServe time.Duration = 10 * time.Second
)

// (Step 1) Start local Auth Code Server
if started, _ := (*authCodeServer).WaitForListeningAndServing(maxWaitForListenAndServe); started {
// (Step 2) Provide access to the consent page
if consentSettings.DisableAutoOpenConsentPage { // Auto open consent disabled
fmt.Println("Go to the following link in your browser:")
fmt.Println("\n", authCodeURL)
} else { // Auto open consent
fmt.Println("Your browser has been opened to visit:")
fmt.Println("\n", authCodeURL)

b := Browser{}
b.OpenURL(authCodeURL)
ulisesL marked this conversation as resolved.
Show resolved Hide resolved
}

// (Step 3) Wait for user to interact with consent page
(*authCodeServer).WaitForConsentPageToReturnControl()
}

// (Step 4) Attempt to get Authorization code. If one was not received
// default string values are returned.
code, err := (*authCodeServer).GetAuthenticationCode()
return code.Code, code.State, err
}
1 change: 0 additions & 1 deletion util/browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ type Browser struct{}
func (b *Browser) OpenURL(url string) error {
var err error
rt := runtime.GOOS

switch rt {
case "darwin":
err = exec.Command("open", url).Start()
Expand Down