From 2aa4ddb9e8908aac0323c6c092ef154620b3c3d4 Mon Sep 17 00:00:00 2001 From: zengchen1024 Date: Tue, 10 Jul 2018 16:52:39 +0800 Subject: [PATCH] support creating token by agency --- auth_options.go | 95 +++++++++++++++++++++--- openstack/client.go | 15 ++++ openstack/identity/v3/tokens/requests.go | 7 +- 3 files changed, 107 insertions(+), 10 deletions(-) diff --git a/auth_options.go b/auth_options.go index b09e139d7..cec66f001 100644 --- a/auth_options.go +++ b/auth_options.go @@ -81,6 +81,15 @@ type AuthOptions struct { // TokenID allows users to authenticate (possibly as another user) with an // authentication token ID. TokenID string `json:"-"` + + // AgencyNmae is the name of agnecy + AgencyName string `json:"xrole_name,omitempty"` + + // AgencyDomainName is the domain name who created the agency + AgencyDomainName string `json:"domain_name,omitempty"` + + // AgencyProjectName is the project name of agency + AgencyProjectName string } // ToTokenV2CreateMap allows AuthOptions to satisfy the AuthOptionsBuilder @@ -263,13 +272,7 @@ func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[s } func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) { - - var scope struct { - ProjectID string - ProjectName string - DomainID string - DomainName string - } + var scope scopeInfo if opts.TenantID != "" { scope.ProjectID = opts.TenantID @@ -278,9 +281,31 @@ func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) { scope.ProjectName = opts.TenantName scope.DomainID = opts.DomainID scope.DomainName = opts.DomainName + } else { + // support scoping to domain + scope.DomainID = opts.DomainID + scope.DomainName = opts.DomainName } } + return scope.BuildTokenV3ScopeMap() +} +func (opts *AuthOptions) CanReauth() bool { + return opts.AllowReauth +} + +func (opts *AuthOptions) AuthTokenID() string { + return "" +} + +type scopeInfo struct { + ProjectID string + ProjectName string + DomainID string + DomainName string +} + +func (scope *scopeInfo) BuildTokenV3ScopeMap() (map[string]interface{}, error) { if scope.ProjectName != "" { // ProjectName provided: either DomainID or DomainName must also be supplied. // ProjectID may not be supplied. @@ -349,6 +374,58 @@ func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) { return nil, nil } -func (opts AuthOptions) CanReauth() bool { - return opts.AllowReauth +type AgencyAuthOptions struct { + TokenID string + AgencyName string + AgencyDomainName string + AgencyProjectName string +} + +func (opts *AgencyAuthOptions) CanReauth() bool { + return false +} + +func (opts *AgencyAuthOptions) AuthTokenID() string { + return opts.TokenID +} + +func (opts *AgencyAuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) { + scope := scopeInfo{ + ProjectName: opts.AgencyProjectName, + DomainName: opts.AgencyDomainName, + } + + return scope.BuildTokenV3ScopeMap() +} + +func (opts *AgencyAuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) { + type assumeRoleReq struct { + DomainName string `json:"domain_name"` + AgencyName string `json:"xrole_name"` + } + + type identityReq struct { + Methods []string `json:"methods"` + AssumeRole assumeRoleReq `json:"assume_role"` + } + + type authReq struct { + Identity identityReq `json:"identity"` + } + + var req authReq + req.Identity.Methods = []string{"assume_role"} + req.Identity.AssumeRole = assumeRoleReq{ + DomainName: opts.AgencyDomainName, + AgencyName: opts.AgencyName, + } + r, err := BuildRequestBody(req, "auth") + if err != nil { + return r, err + } + + if len(scope) != 0 { + r["auth"].(map[string]interface{})["scope"] = scope + } + return r, nil } diff --git a/openstack/client.go b/openstack/client.go index 9e13cd2ef..a9e1f0021 100644 --- a/openstack/client.go +++ b/openstack/client.go @@ -196,6 +196,21 @@ func v3auth(client *golangsdk.ProviderClient, endpoint string, opts tokens3.Auth return err } + opts1, ok := opts.(*golangsdk.AuthOptions) + if ok && opts1.AgencyDomainName != "" && opts1.AgencyName != "" { + opts2 := golangsdk.AgencyAuthOptions{ + TokenID: token.ID, + AgencyName: opts1.AgencyName, + AgencyDomainName: opts1.AgencyDomainName, + AgencyProjectName: opts1.AgencyProjectName, + } + result = tokens3.Create(v3Client, &opts2) + token, err = result.ExtractToken() + if err != nil { + return err + } + } + project, err := result.ExtractProject() if err != nil { return err diff --git a/openstack/identity/v3/tokens/requests.go b/openstack/identity/v3/tokens/requests.go index b4b60499b..381ec2689 100644 --- a/openstack/identity/v3/tokens/requests.go +++ b/openstack/identity/v3/tokens/requests.go @@ -18,6 +18,7 @@ type AuthOptionsBuilder interface { ToTokenV3CreateMap(map[string]interface{}) (map[string]interface{}, error) ToTokenV3ScopeMap() (map[string]interface{}, error) CanReauth() bool + AuthTokenID() string } // AuthOptions represents options for authenticating a user. @@ -144,6 +145,10 @@ func (opts *AuthOptions) CanReauth() bool { return opts.AllowReauth } +func (opts *AuthOptions) AuthTokenID() string { + return "" +} + func subjectTokenHeaders(c *golangsdk.ServiceClient, subjectToken string) map[string]string { return map[string]string{ "X-Subject-Token": subjectToken, @@ -166,7 +171,7 @@ func Create(c *golangsdk.ServiceClient, opts AuthOptionsBuilder) (r CreateResult } resp, err := c.Post(tokenURL(c), b, &r.Body, &golangsdk.RequestOpts{ - MoreHeaders: map[string]string{"X-Auth-Token": ""}, + MoreHeaders: map[string]string{"X-Auth-Token": opts.AuthTokenID()}, }) r.Err = err if resp != nil {