github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/azure/internal/azureauth/discovery.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package azureauth
     5  
     6  import (
     7  	"context"
     8  	"net/http"
     9  	"net/url"
    10  	"regexp"
    11  	"strings"
    12  
    13  	"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-06-01/subscriptions"
    14  	"github.com/juju/errors"
    15  	"github.com/juju/utils"
    16  )
    17  
    18  const authenticateHeaderKey = "WWW-Authenticate"
    19  
    20  var authorizationUriRegexp = regexp.MustCompile(`authorization_uri="([^"]*)"`)
    21  
    22  // DiscoverAuthorizationID returns the OAuth authorization URI for the given
    23  // subscription ID. This can be used to determine the AD tenant ID.
    24  func DiscoverAuthorizationURI(sdkCtx context.Context, client subscriptions.Client, subscriptionID string) (*url.URL, error) {
    25  	// We make an unauthenticated request to the Azure API, which
    26  	// responds with the authentication URL with the tenant ID in it.
    27  	result, err := client.Get(sdkCtx, subscriptionID)
    28  	if err == nil {
    29  		return nil, errors.New("expected unauthorized error response")
    30  	}
    31  	if result.Response.Response == nil {
    32  		return nil, errors.Trace(err)
    33  	}
    34  	if result.StatusCode != http.StatusUnauthorized {
    35  		return nil, errors.Annotatef(err, "expected unauthorized error response, got %v", result.StatusCode)
    36  	}
    37  
    38  	header := result.Header.Get(authenticateHeaderKey)
    39  	if header == "" {
    40  		return nil, errors.Errorf("%s header not found", authenticateHeaderKey)
    41  	}
    42  	match := authorizationUriRegexp.FindStringSubmatch(header)
    43  	if match == nil {
    44  		return nil, errors.Errorf(
    45  			"authorization_uri not found in %s header (%q)",
    46  			authenticateHeaderKey, header,
    47  		)
    48  	}
    49  	return url.Parse(match[1])
    50  }
    51  
    52  // AuthorizationURITenantID returns the tenant ID portion of the given URL,
    53  // which is expected to have come from DiscoverAuthorizationURI.
    54  func AuthorizationURITenantID(url *url.URL) (string, error) {
    55  	path := strings.TrimPrefix(url.Path, "/")
    56  	if _, err := utils.UUIDFromString(path); err != nil {
    57  		return "", errors.NotValidf("authorization_uri %q", url)
    58  	}
    59  	return path, nil
    60  }