github.com/opentelekomcloud/gophertelekomcloud@v0.9.3/openstack/identity/v3/tokens/requests.go (about)

     1  package tokens
     2  
     3  import (
     4  	"github.com/opentelekomcloud/gophertelekomcloud"
     5  )
     6  
     7  // Scope allows a created token to be limited to a specific domain or project.
     8  type Scope struct {
     9  	ProjectID   string
    10  	ProjectName string
    11  	DomainID    string
    12  	DomainName  string
    13  }
    14  
    15  // AuthOptionsBuilder provides the ability for extensions to add additional
    16  // parameters to AuthOptions. Extensions must satisfy all required methods.
    17  type AuthOptionsBuilder interface {
    18  	// ToTokenV3CreateMap assembles the Create request body, returning an error
    19  	// if parameters are missing or inconsistent.
    20  	ToTokenV3CreateMap(map[string]interface{}) (map[string]interface{}, error)
    21  	ToTokenV3ScopeMap() (map[string]interface{}, error)
    22  	CanReauth() bool
    23  	AuthTokenID() string
    24  	AuthHeaderDomainID() string
    25  }
    26  
    27  // AuthOptions represents options for authenticating a user.
    28  type AuthOptions struct {
    29  	// IdentityEndpoint specifies the HTTP endpoint that is required to work with
    30  	// the Identity API of the appropriate version. While it's ultimately needed
    31  	// by all of the identity services, it will often be populated by a
    32  	// provider-level function.
    33  	IdentityEndpoint string `json:"-"`
    34  
    35  	// Username is required if using Identity V2 API. Consult with your provider's
    36  	// control panel to discover your account's username. In Identity V3, either
    37  	// UserID or a combination of Username and DomainID or DomainName are needed.
    38  	Username string `json:"username,omitempty"`
    39  	UserID   string `json:"id,omitempty"`
    40  
    41  	Password string `json:"password,omitempty"`
    42  
    43  	// At most one of DomainID and DomainName must be provided if using Username
    44  	// with Identity V3. Otherwise, either are optional.
    45  	DomainID   string `json:"-"`
    46  	DomainName string `json:"name,omitempty"`
    47  
    48  	// AllowReauth should be set to true if you grant permission for Gophercloud
    49  	// to cache your credentials in memory, and to allow Gophercloud to attempt
    50  	// to re-authenticate automatically if/when your token expires.  If you set
    51  	// it to false, it will not cache these settings, but re-authentication will
    52  	// not be possible.  This setting defaults to false.
    53  	AllowReauth bool `json:"-"`
    54  
    55  	// TokenID allows users to authenticate (possibly as another user) with an
    56  	// authentication token ID.
    57  	TokenID string `json:"-"`
    58  
    59  	// Passcode is a Virtual MFA device verification code, which can be obtained on the MFA app.
    60  	Passcode string `json:"-"`
    61  
    62  	Scope Scope `json:"-"`
    63  }
    64  
    65  // ToTokenV3CreateMap builds a request body from AuthOptions.
    66  func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) {
    67  	golangsdkAuthOpts := golangsdk.AuthOptions{
    68  		Username:    opts.Username,
    69  		UserID:      opts.UserID,
    70  		Password:    opts.Password,
    71  		DomainID:    opts.DomainID,
    72  		DomainName:  opts.DomainName,
    73  		AllowReauth: opts.AllowReauth,
    74  		TokenID:     opts.TokenID,
    75  		Passcode:    opts.Passcode,
    76  	}
    77  
    78  	return golangsdkAuthOpts.ToTokenV3CreateMap(scope)
    79  }
    80  
    81  // ToTokenV3ScopeMap builds a scope request body from AuthOptions.
    82  func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) {
    83  	if opts.Scope.ProjectName != "" {
    84  		// ProjectName provided: either DomainID or DomainName must also be supplied.
    85  		// ProjectID may not be supplied.
    86  		if opts.Scope.DomainID == "" && opts.Scope.DomainName == "" {
    87  			return nil, golangsdk.ErrScopeDomainIDOrDomainName{}
    88  		}
    89  		if opts.Scope.ProjectID != "" {
    90  			return nil, golangsdk.ErrScopeProjectIDOrProjectName{}
    91  		}
    92  
    93  		if opts.Scope.DomainID != "" {
    94  			// ProjectName + DomainID
    95  			return map[string]interface{}{
    96  				"project": map[string]interface{}{
    97  					"name":   &opts.Scope.ProjectName,
    98  					"domain": map[string]interface{}{"id": &opts.Scope.DomainID},
    99  				},
   100  			}, nil
   101  		}
   102  
   103  		if opts.Scope.DomainName != "" {
   104  			// ProjectName + DomainName
   105  			return map[string]interface{}{
   106  				"project": map[string]interface{}{
   107  					"name":   &opts.Scope.ProjectName,
   108  					"domain": map[string]interface{}{"name": &opts.Scope.DomainName},
   109  				},
   110  			}, nil
   111  		}
   112  	} else if opts.Scope.ProjectID != "" {
   113  		// ProjectID provided. ProjectName, DomainID, and DomainName may not be provided.
   114  		if opts.Scope.DomainID != "" {
   115  			return nil, golangsdk.ErrScopeProjectIDAlone{}
   116  		}
   117  		if opts.Scope.DomainName != "" {
   118  			return nil, golangsdk.ErrScopeProjectIDAlone{}
   119  		}
   120  
   121  		// ProjectID
   122  		return map[string]interface{}{
   123  			"project": map[string]interface{}{
   124  				"id": &opts.Scope.ProjectID,
   125  			},
   126  		}, nil
   127  	} else if opts.Scope.DomainID != "" {
   128  		// DomainID provided. ProjectID, ProjectName, and DomainName may not be provided.
   129  		if opts.Scope.DomainName != "" {
   130  			return nil, golangsdk.ErrScopeDomainIDOrDomainName{}
   131  		}
   132  
   133  		// DomainID
   134  		return map[string]interface{}{
   135  			"domain": map[string]interface{}{
   136  				"id": &opts.Scope.DomainID,
   137  			},
   138  		}, nil
   139  	} else if opts.Scope.DomainName != "" {
   140  		// DomainName
   141  		return map[string]interface{}{
   142  			"domain": map[string]interface{}{
   143  				"name": &opts.Scope.DomainName,
   144  			},
   145  		}, nil
   146  	}
   147  
   148  	return nil, nil
   149  }
   150  
   151  func (opts *AuthOptions) CanReauth() bool {
   152  	return opts.AllowReauth
   153  }
   154  
   155  func (opts *AuthOptions) AuthTokenID() string {
   156  	return ""
   157  }
   158  
   159  func (opts *AuthOptions) AuthHeaderDomainID() string {
   160  	return ""
   161  }
   162  
   163  func subjectTokenHeaders(_ *golangsdk.ServiceClient, subjectToken string) map[string]string {
   164  	return map[string]string{
   165  		"X-Subject-Token": subjectToken,
   166  	}
   167  }
   168  
   169  // Create authenticates and either generates a new token, or changes the Scope
   170  // of an existing token.
   171  func Create(c *golangsdk.ServiceClient, opts AuthOptionsBuilder) (r CreateResult) {
   172  	scope, err := opts.ToTokenV3ScopeMap()
   173  	if err != nil {
   174  		r.Err = err
   175  		return
   176  	}
   177  
   178  	b, err := opts.ToTokenV3CreateMap(scope)
   179  	if err != nil {
   180  		r.Err = err
   181  		return
   182  	}
   183  
   184  	resp, err := c.Post(tokenURL(c), b, &r.Body, &golangsdk.RequestOpts{
   185  		MoreHeaders: map[string]string{
   186  			"X-Auth-Token": opts.AuthTokenID(),
   187  			"X-Domain-Id":  opts.AuthHeaderDomainID(),
   188  		},
   189  	})
   190  	r.Err = err
   191  	if resp != nil {
   192  		r.Header = resp.Header
   193  	}
   194  	return
   195  }
   196  
   197  // Get validates and retrieves information about another token.
   198  func Get(c *golangsdk.ServiceClient, token string) (r GetResult) {
   199  	resp, err := c.Get(tokenURL(c), &r.Body, &golangsdk.RequestOpts{
   200  		MoreHeaders: subjectTokenHeaders(c, token),
   201  		OkCodes:     []int{200, 203},
   202  	})
   203  	if resp != nil {
   204  		r.Err = err
   205  		r.Header = resp.Header
   206  	}
   207  	return
   208  }
   209  
   210  // Validate determines if a specified token is valid or not.
   211  func Validate(c *golangsdk.ServiceClient, token string) (bool, error) {
   212  	resp, err := c.Request("HEAD", tokenURL(c), &golangsdk.RequestOpts{
   213  		MoreHeaders: subjectTokenHeaders(c, token),
   214  		OkCodes:     []int{200, 204, 404},
   215  	})
   216  	if err != nil {
   217  		return false, err
   218  	}
   219  
   220  	return resp.StatusCode == 200 || resp.StatusCode == 204, nil
   221  }
   222  
   223  // Revoke immediately makes specified token invalid.
   224  func Revoke(c *golangsdk.ServiceClient, token string) (r RevokeResult) {
   225  	_, r.Err = c.Delete(tokenURL(c), &golangsdk.RequestOpts{
   226  		MoreHeaders: subjectTokenHeaders(c, token),
   227  	})
   228  	return
   229  }