AUTH-7260: Add support for login interstitial auto closure
Adds a switch `--auto-close` which automatically closes Access login interstitial windows/tabs immediately after the user chooses Approve or Deny.
This commit is contained in:
parent
08efe4c103
commit
50104548cf
|
|
@ -26,11 +26,12 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type StartOptions struct {
|
type StartOptions struct {
|
||||||
AppInfo *token.AppInfo
|
AppInfo *token.AppInfo
|
||||||
OriginURL string
|
OriginURL string
|
||||||
Headers http.Header
|
Headers http.Header
|
||||||
Host string
|
Host string
|
||||||
TLSClientConfig *tls.Config
|
TLSClientConfig *tls.Config
|
||||||
|
AutoCloseInterstitial bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connection wraps up all the needed functions to forward over the tunnel
|
// Connection wraps up all the needed functions to forward over the tunnel
|
||||||
|
|
@ -46,7 +47,6 @@ type StdinoutStream struct{}
|
||||||
// Read will read from Stdin
|
// Read will read from Stdin
|
||||||
func (c *StdinoutStream) Read(p []byte) (int, error) {
|
func (c *StdinoutStream) Read(p []byte) (int, error) {
|
||||||
return os.Stdin.Read(p)
|
return os.Stdin.Read(p)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write will write to Stdout
|
// Write will write to Stdout
|
||||||
|
|
@ -139,7 +139,7 @@ func BuildAccessRequest(options *StartOptions, log *zerolog.Logger) (*http.Reque
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := token.FetchTokenWithRedirect(req.URL, options.AppInfo, log)
|
token, err := token.FetchTokenWithRedirect(req.URL, options.AppInfo, options.AutoCloseInterstitial, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,10 @@ func Commands() []*cli.Command {
|
||||||
Name: "no-verbose",
|
Name: "no-verbose",
|
||||||
Usage: "print only the jwt to stdout",
|
Usage: "print only the jwt to stdout",
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "auto-close",
|
||||||
|
Usage: "automatically close the auth interstitial after action",
|
||||||
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: appURLFlag,
|
Name: appURLFlag,
|
||||||
},
|
},
|
||||||
|
|
@ -322,7 +326,7 @@ func curl(c *cli.Context) error {
|
||||||
log.Info().Msg("You don't have an Access token set. Please run access token <access application> to fetch one.")
|
log.Info().Msg("You don't have an Access token set. Please run access token <access application> to fetch one.")
|
||||||
return run("curl", cmdArgs...)
|
return run("curl", cmdArgs...)
|
||||||
}
|
}
|
||||||
tok, err = token.FetchToken(appURL, appInfo, log)
|
tok, err = token.FetchToken(appURL, appInfo, c.Bool(cfdflags.AutoCloseInterstitial), log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("Failed to refresh token")
|
log.Err(err).Msg("Failed to refresh token")
|
||||||
return err
|
return err
|
||||||
|
|
@ -442,7 +446,7 @@ func sshGen(c *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cfdToken, err := token.FetchTokenWithRedirect(fetchTokenURL, appInfo, log)
|
cfdToken, err := token.FetchTokenWithRedirect(fetchTokenURL, appInfo, c.Bool(cfdflags.AutoCloseInterstitial), log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -542,7 +546,7 @@ func verifyTokenAtEdge(appUrl *url.URL, appInfo *token.AppInfo, c *cli.Context,
|
||||||
if c.IsSet(sshTokenSecretFlag) {
|
if c.IsSet(sshTokenSecretFlag) {
|
||||||
headers.Add(cfAccessClientSecretHeader, c.String(sshTokenSecretFlag))
|
headers.Add(cfAccessClientSecretHeader, c.String(sshTokenSecretFlag))
|
||||||
}
|
}
|
||||||
options := &carrier.StartOptions{AppInfo: appInfo, OriginURL: appUrl.String(), Headers: headers}
|
options := &carrier.StartOptions{AppInfo: appInfo, OriginURL: appUrl.String(), Headers: headers, AutoCloseInterstitial: c.Bool(cfdflags.AutoCloseInterstitial)}
|
||||||
|
|
||||||
if valid, err := isTokenValid(options, log); err != nil {
|
if valid, err := isTokenValid(options, log); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -163,4 +163,7 @@ const (
|
||||||
|
|
||||||
// Management hostname to signify incoming management requests
|
// Management hostname to signify incoming management requests
|
||||||
ManagementHostname = "management-hostname"
|
ManagementHostname = "management-hostname"
|
||||||
|
|
||||||
|
// Automatically close the login interstitial browser window after the user makes a decision.
|
||||||
|
AutoCloseInterstitial = "auto-close"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
||||||
|
cfdflags "github.com/cloudflare/cloudflared/cmd/cloudflared/flags"
|
||||||
"github.com/cloudflare/cloudflared/config"
|
"github.com/cloudflare/cloudflared/config"
|
||||||
"github.com/cloudflare/cloudflared/credentials"
|
"github.com/cloudflare/cloudflared/credentials"
|
||||||
"github.com/cloudflare/cloudflared/logger"
|
"github.com/cloudflare/cloudflared/logger"
|
||||||
|
|
@ -97,6 +98,7 @@ func login(c *cli.Context) error {
|
||||||
callbackStoreURL,
|
callbackStoreURL,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
c.Bool(cfdflags.AutoCloseInterstitial),
|
||||||
log,
|
log,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -185,18 +185,18 @@ func Init(version string) {
|
||||||
|
|
||||||
// FetchTokenWithRedirect will either load a stored token or generate a new one
|
// FetchTokenWithRedirect will either load a stored token or generate a new one
|
||||||
// it appends the full url as the redirect URL to the access cli request if opening the browser
|
// it appends the full url as the redirect URL to the access cli request if opening the browser
|
||||||
func FetchTokenWithRedirect(appURL *url.URL, appInfo *AppInfo, log *zerolog.Logger) (string, error) {
|
func FetchTokenWithRedirect(appURL *url.URL, appInfo *AppInfo, autoClose bool, log *zerolog.Logger) (string, error) {
|
||||||
return getToken(appURL, appInfo, false, log)
|
return getToken(appURL, appInfo, false, autoClose, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchToken will either load a stored token or generate a new one
|
// FetchToken will either load a stored token or generate a new one
|
||||||
// it appends the host of the appURL as the redirect URL to the access cli request if opening the browser
|
// it appends the host of the appURL as the redirect URL to the access cli request if opening the browser
|
||||||
func FetchToken(appURL *url.URL, appInfo *AppInfo, log *zerolog.Logger) (string, error) {
|
func FetchToken(appURL *url.URL, appInfo *AppInfo, autoClose bool, log *zerolog.Logger) (string, error) {
|
||||||
return getToken(appURL, appInfo, true, log)
|
return getToken(appURL, appInfo, true, autoClose, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getToken will either load a stored token or generate a new one
|
// getToken will either load a stored token or generate a new one
|
||||||
func getToken(appURL *url.URL, appInfo *AppInfo, useHostOnly bool, log *zerolog.Logger) (string, error) {
|
func getToken(appURL *url.URL, appInfo *AppInfo, useHostOnly bool, autoClose bool, log *zerolog.Logger) (string, error) {
|
||||||
if token, err := GetAppTokenIfExists(appInfo); token != "" && err == nil {
|
if token, err := GetAppTokenIfExists(appInfo); token != "" && err == nil {
|
||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
@ -249,18 +249,19 @@ func getToken(appURL *url.URL, appInfo *AppInfo, useHostOnly bool, log *zerolog.
|
||||||
return appToken, nil
|
return appToken, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getTokensFromEdge(appURL, appInfo.AppAUD, appTokenPath, orgTokenPath, useHostOnly, log)
|
return getTokensFromEdge(appURL, appInfo.AppAUD, appTokenPath, orgTokenPath, useHostOnly, autoClose, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTokensFromEdge will attempt to use the transfer service to retrieve an app and org token, save them to disk,
|
// getTokensFromEdge will attempt to use the transfer service to retrieve an app and org token, save them to disk,
|
||||||
// and return the app token.
|
// and return the app token.
|
||||||
func getTokensFromEdge(appURL *url.URL, appAUD, appTokenPath, orgTokenPath string, useHostOnly bool, log *zerolog.Logger) (string, error) {
|
func getTokensFromEdge(appURL *url.URL, appAUD, appTokenPath, orgTokenPath string, useHostOnly bool, autoClose bool, log *zerolog.Logger) (string, error) {
|
||||||
|
fmt.Println("Get tokens from edge ", autoClose)
|
||||||
// If no org token exists or if it couldn't be exchanged for an app token, then run the transfer service flow.
|
// If no org token exists or if it couldn't be exchanged for an app token, then run the transfer service flow.
|
||||||
|
|
||||||
// this weird parameter is the resource name (token) and the key/value
|
// this weird parameter is the resource name (token) and the key/value
|
||||||
// we want to send to the transfer service. the key is token and the value
|
// we want to send to the transfer service. the key is token and the value
|
||||||
// is blank (basically just the id generated in the transfer service)
|
// is blank (basically just the id generated in the transfer service)
|
||||||
resourceData, err := RunTransfer(appURL, appAUD, keyName, keyName, "", true, useHostOnly, log)
|
resourceData, err := RunTransfer(appURL, appAUD, keyName, keyName, "", true, useHostOnly, autoClose, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrap(err, "failed to run transfer service")
|
return "", errors.Wrap(err, "failed to run transfer service")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,12 @@ const (
|
||||||
// The "dance" we refer to is building a HTTP request, opening that in a browser waiting for
|
// The "dance" we refer to is building a HTTP request, opening that in a browser waiting for
|
||||||
// the user to complete an action, while it long polls in the background waiting for an
|
// the user to complete an action, while it long polls in the background waiting for an
|
||||||
// action to be completed to download the resource.
|
// action to be completed to download the resource.
|
||||||
func RunTransfer(transferURL *url.URL, appAUD, resourceName, key, value string, shouldEncrypt bool, useHostOnly bool, log *zerolog.Logger) ([]byte, error) {
|
func RunTransfer(transferURL *url.URL, appAUD, resourceName, key, value string, shouldEncrypt bool, useHostOnly bool, autoClose bool, log *zerolog.Logger) ([]byte, error) {
|
||||||
encrypterClient, err := NewEncrypter("cloudflared_priv.pem", "cloudflared_pub.pem")
|
encrypterClient, err := NewEncrypter("cloudflared_priv.pem", "cloudflared_pub.pem")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
requestURL, err := buildRequestURL(transferURL, appAUD, key, value+encrypterClient.PublicKey(), shouldEncrypt, useHostOnly)
|
requestURL, err := buildRequestURL(transferURL, appAUD, key, value+encrypterClient.PublicKey(), shouldEncrypt, useHostOnly, autoClose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +75,7 @@ func RunTransfer(transferURL *url.URL, appAUD, resourceName, key, value string,
|
||||||
// BuildRequestURL creates a request suitable for a resource transfer.
|
// BuildRequestURL creates a request suitable for a resource transfer.
|
||||||
// it will return a constructed url based off the base url and query key/value provided.
|
// it will return a constructed url based off the base url and query key/value provided.
|
||||||
// cli will build a url for cli transfer request.
|
// cli will build a url for cli transfer request.
|
||||||
func buildRequestURL(baseURL *url.URL, appAUD string, key, value string, cli, useHostOnly bool) (string, error) {
|
func buildRequestURL(baseURL *url.URL, appAUD string, key, value string, cli, useHostOnly bool, autoClose bool) (string, error) {
|
||||||
q := baseURL.Query()
|
q := baseURL.Query()
|
||||||
q.Set(key, value)
|
q.Set(key, value)
|
||||||
q.Set("aud", appAUD)
|
q.Set("aud", appAUD)
|
||||||
|
|
@ -90,7 +90,11 @@ func buildRequestURL(baseURL *url.URL, appAUD string, key, value string, cli, us
|
||||||
q.Set("redirect_url", baseURL.String()) // we add the token as a query param on both the redirect_url and the main url
|
q.Set("redirect_url", baseURL.String()) // we add the token as a query param on both the redirect_url and the main url
|
||||||
q.Set("send_org_token", "true") // indicates that the cli endpoint should return both the org and app token
|
q.Set("send_org_token", "true") // indicates that the cli endpoint should return both the org and app token
|
||||||
q.Set("edge_token_transfer", "true") // use new LoginHelper service built on workers
|
q.Set("edge_token_transfer", "true") // use new LoginHelper service built on workers
|
||||||
baseURL.RawQuery = q.Encode() // and this actual baseURL.
|
if autoClose {
|
||||||
|
q.Set("close_interstitial", "true") // Automatically close the success window.
|
||||||
|
}
|
||||||
|
|
||||||
|
baseURL.RawQuery = q.Encode() // and this actual baseURL.
|
||||||
baseURL.Path = "cdn-cgi/access/cli"
|
baseURL.Path = "cdn-cgi/access/cli"
|
||||||
return baseURL.String(), nil
|
return baseURL.String(), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue