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 }