mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-12-07 18:06:21 +00:00
vSphere Cloud Provider: update vmware/gomvomi godeps
This commit is contained in:
193
vendor/github.com/vmware/govmomi/sts/client.go
generated
vendored
Normal file
193
vendor/github.com/vmware/govmomi/sts/client.go
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/lookup"
|
||||
"github.com/vmware/govmomi/lookup/types"
|
||||
"github.com/vmware/govmomi/sts/internal"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
)
|
||||
|
||||
const (
|
||||
Namespace = "oasis:names:tc:SAML:2.0:assertion"
|
||||
Path = "/sts/STSService"
|
||||
)
|
||||
|
||||
// Client is a soap.Client targeting the STS (Secure Token Service) API endpoint.
|
||||
type Client struct {
|
||||
*soap.Client
|
||||
}
|
||||
|
||||
// NewClient returns a client targeting the STS API endpoint.
|
||||
// The Client.URL will be set to that of the Lookup Service's endpoint registration,
|
||||
// as the SSO endpoint can be external to vCenter. If the Lookup Service is not available,
|
||||
// URL defaults to Path on the vim25.Client.URL.Host.
|
||||
func NewClient(ctx context.Context, c *vim25.Client) (*Client, error) {
|
||||
filter := &types.LookupServiceRegistrationFilter{
|
||||
ServiceType: &types.LookupServiceRegistrationServiceType{
|
||||
Product: "com.vmware.cis",
|
||||
Type: "sso:sts",
|
||||
},
|
||||
EndpointType: &types.LookupServiceRegistrationEndpointType{
|
||||
Protocol: "wsTrust",
|
||||
Type: "com.vmware.cis.cs.identity.sso",
|
||||
},
|
||||
}
|
||||
|
||||
url := lookup.EndpointURL(ctx, c, Path, filter)
|
||||
sc := c.Client.NewServiceClient(url, Namespace)
|
||||
|
||||
return &Client{sc}, nil
|
||||
}
|
||||
|
||||
// TokenRequest parameters for issuing a SAML token.
|
||||
// At least one of Userinfo or Certificate must be specified.
|
||||
type TokenRequest struct {
|
||||
Userinfo *url.Userinfo // Userinfo when set issues a Bearer token
|
||||
Certificate *tls.Certificate // Certificate when set issues a HoK token
|
||||
Lifetime time.Duration // Lifetime is the token's lifetime, defaults to 10m
|
||||
Renewable bool // Renewable allows the issued token to be renewed
|
||||
Delegatable bool // Delegatable allows the issued token to be delegated (e.g. for use with ActAs)
|
||||
Token string // Token for Renew request or Issue request ActAs identity
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(req TokenRequest, kind string, s *Signer) (internal.RequestSecurityToken, error) {
|
||||
if req.Lifetime == 0 {
|
||||
req.Lifetime = 5 * time.Minute
|
||||
}
|
||||
|
||||
created := time.Now().UTC()
|
||||
rst := internal.RequestSecurityToken{
|
||||
TokenType: c.Namespace,
|
||||
RequestType: "http://docs.oasis-open.org/ws-sx/ws-trust/200512/" + kind,
|
||||
SignatureAlgorithm: internal.SHA256,
|
||||
Lifetime: &internal.Lifetime{
|
||||
Created: created.Format(internal.Time),
|
||||
Expires: created.Add(req.Lifetime).Format(internal.Time),
|
||||
},
|
||||
Renewing: &internal.Renewing{
|
||||
Allow: req.Renewable,
|
||||
// /wst:RequestSecurityToken/wst:Renewing/@OK
|
||||
// "It NOT RECOMMENDED to use this as it can leave you open to certain types of security attacks.
|
||||
// Issuers MAY restrict the period after expiration during which time the token can be renewed.
|
||||
// This window is governed by the issuer's policy."
|
||||
OK: false,
|
||||
},
|
||||
Delegatable: req.Delegatable,
|
||||
}
|
||||
|
||||
if req.Certificate == nil {
|
||||
if req.Userinfo == nil {
|
||||
return rst, errors.New("one of TokenRequest Certificate or Userinfo is required")
|
||||
}
|
||||
rst.KeyType = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer"
|
||||
} else {
|
||||
rst.KeyType = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/PublicKey"
|
||||
rst.UseKey = &internal.UseKey{Sig: newID()}
|
||||
s.keyID = rst.UseKey.Sig
|
||||
}
|
||||
|
||||
return rst, nil
|
||||
}
|
||||
|
||||
func (s *Signer) setLifetime(lifetime *internal.Lifetime) error {
|
||||
var err error
|
||||
if lifetime != nil {
|
||||
s.Lifetime.Created, err = time.Parse(internal.Time, lifetime.Created)
|
||||
if err == nil {
|
||||
s.Lifetime.Expires, err = time.Parse(internal.Time, lifetime.Expires)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Issue is used to request a security token.
|
||||
// The returned Signer can be used to sign SOAP requests, such as the SessionManager LoginByToken method and the RequestSecurityToken method itself.
|
||||
// One of TokenRequest Certificate or Userinfo is required, with Certificate taking precedence.
|
||||
// When Certificate is set, a Holder-of-Key token will be requested. Otherwise, a Bearer token is requested with the Userinfo credentials.
|
||||
// See: http://docs.oasis-open.org/ws-sx/ws-trust/v1.4/errata01/os/ws-trust-1.4-errata01-os-complete.html#_Toc325658937
|
||||
func (c *Client) Issue(ctx context.Context, req TokenRequest) (*Signer, error) {
|
||||
s := &Signer{
|
||||
Certificate: req.Certificate,
|
||||
user: req.Userinfo,
|
||||
}
|
||||
|
||||
rst, err := c.newRequest(req, "Issue", s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.Token != "" {
|
||||
rst.ActAs = &internal.Target{
|
||||
Token: req.Token,
|
||||
}
|
||||
}
|
||||
|
||||
header := soap.Header{
|
||||
Security: s,
|
||||
Action: rst.Action(),
|
||||
}
|
||||
|
||||
res, err := internal.Issue(c.WithHeader(ctx, header), c, &rst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Token = res.RequestSecurityTokenResponse.RequestedSecurityToken.Assertion
|
||||
|
||||
return s, s.setLifetime(res.RequestSecurityTokenResponse.Lifetime)
|
||||
}
|
||||
|
||||
// Renew is used to request a security token renewal.
|
||||
func (c *Client) Renew(ctx context.Context, req TokenRequest) (*Signer, error) {
|
||||
s := &Signer{
|
||||
Certificate: req.Certificate,
|
||||
}
|
||||
|
||||
rst, err := c.newRequest(req, "Renew", s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.Token == "" {
|
||||
return nil, errors.New("TokenRequest Token is required")
|
||||
}
|
||||
|
||||
rst.RenewTarget = &internal.Target{Token: req.Token}
|
||||
|
||||
header := soap.Header{
|
||||
Security: s,
|
||||
Action: rst.Action(),
|
||||
}
|
||||
|
||||
res, err := internal.Renew(c.WithHeader(ctx, header), c, &rst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Token = res.RequestedSecurityToken.Assertion
|
||||
|
||||
return s, s.setLifetime(res.Lifetime)
|
||||
}
|
||||
694
vendor/github.com/vmware/govmomi/sts/internal/types.go
generated
vendored
Normal file
694
vendor/github.com/vmware/govmomi/sts/internal/types.go
generated
vendored
Normal file
@@ -0,0 +1,694 @@
|
||||
/*
|
||||
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
// The sts/internal package provides the types for invoking the sts.Issue method.
|
||||
// The sts.Issue and SessionManager LoginByToken methods require an XML signature.
|
||||
// Unlike the JRE and .NET runtimes, the Go stdlib does not support XML signing.
|
||||
// We should considering contributing to the goxmldsig package and gosaml2 to meet
|
||||
// the needs of sts.Issue rather than maintaining this package long term.
|
||||
// The tricky part of xmldig is the XML canonicalization (C14N), which is responsible
|
||||
// for most of the make-your-eyes bleed XML formatting in this package.
|
||||
// C14N is also why some structures use xml.Name without a field tag and methods modify the xml.Name directly,
|
||||
// though also working around Go's handling of XML namespace prefixes.
|
||||
// Most of the types in this package were originally generated from the wsdl and hacked up gen/ scripts,
|
||||
// but have since been modified by hand.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"github.com/vmware/govmomi/vim25/xml"
|
||||
)
|
||||
|
||||
const (
|
||||
XSI = "http://www.w3.org/2001/XMLSchema-instance"
|
||||
WSU = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
|
||||
DSIG = "http://www.w3.org/2000/09/xmldsig#"
|
||||
SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
|
||||
Time = "2006-01-02T15:04:05.000Z"
|
||||
)
|
||||
|
||||
// Security is used as soap.Envelope.Header.Security when signing requests.
|
||||
type Security struct {
|
||||
XMLName xml.Name `xml:"wsse:Security"`
|
||||
WSSE string `xml:"xmlns:wsse,attr"`
|
||||
WSU string `xml:"xmlns:wsu,attr"`
|
||||
Timestamp Timestamp
|
||||
BinarySecurityToken *BinarySecurityToken `xml:",omitempty"`
|
||||
UsernameToken *UsernameToken `xml:",omitempty"`
|
||||
Assertion string `xml:",innerxml"`
|
||||
Signature *Signature `xml:",omitempty"`
|
||||
}
|
||||
|
||||
type Timestamp struct {
|
||||
XMLName xml.Name `xml:"wsu:Timestamp"`
|
||||
NS string `xml:"xmlns:wsu,attr"`
|
||||
ID string `xml:"wsu:Id,attr"`
|
||||
Created string `xml:"wsu:Created"`
|
||||
Expires string `xml:"wsu:Expires"`
|
||||
}
|
||||
|
||||
func (t *Timestamp) C14N() string {
|
||||
return Marshal(t)
|
||||
}
|
||||
|
||||
type BinarySecurityToken struct {
|
||||
XMLName xml.Name `xml:"wsse:BinarySecurityToken"`
|
||||
EncodingType string `xml:"EncodingType,attr"`
|
||||
ValueType string `xml:"ValueType,attr"`
|
||||
ID string `xml:"wsu:Id,attr"`
|
||||
Value string `xml:",chardata"`
|
||||
}
|
||||
|
||||
type UsernameToken struct {
|
||||
XMLName xml.Name `xml:"wsse:UsernameToken"`
|
||||
Username string `xml:"wsse:Username"`
|
||||
Password string `xml:"wsse:Password"`
|
||||
}
|
||||
|
||||
type Signature struct {
|
||||
XMLName xml.Name
|
||||
NS string `xml:"xmlns:ds,attr"`
|
||||
ID string `xml:"Id,attr"`
|
||||
SignedInfo SignedInfo
|
||||
SignatureValue Value
|
||||
KeyInfo KeyInfo
|
||||
}
|
||||
|
||||
func (s *Signature) C14N() string {
|
||||
return fmt.Sprintf(`<ds:Signature xmlns:ds="%s">%s%s%s</ds:Signature>`,
|
||||
DSIG, s.SignedInfo.C14N(), s.SignatureValue.C14N(), s.KeyInfo.C14N())
|
||||
}
|
||||
|
||||
type SignedInfo struct {
|
||||
XMLName xml.Name
|
||||
NS string `xml:"xmlns:ds,attr,omitempty"`
|
||||
CanonicalizationMethod Method
|
||||
SignatureMethod Method
|
||||
Reference []Reference
|
||||
}
|
||||
|
||||
func (s SignedInfo) C14N() string {
|
||||
ns := "" // empty in ActAs c14n form for example
|
||||
if s.NS != "" {
|
||||
ns = fmt.Sprintf(` xmlns:ds="%s"`, s.NS)
|
||||
}
|
||||
|
||||
c14n := []string{fmt.Sprintf("<ds:SignedInfo%s>", ns)}
|
||||
c14n = append(c14n, s.CanonicalizationMethod.C14N(), s.SignatureMethod.C14N())
|
||||
for i := range s.Reference {
|
||||
c14n = append(c14n, s.Reference[i].C14N())
|
||||
}
|
||||
c14n = append(c14n, "</ds:SignedInfo>")
|
||||
|
||||
return strings.Join(c14n, "")
|
||||
}
|
||||
|
||||
type Method struct {
|
||||
XMLName xml.Name
|
||||
Algorithm string `xml:",attr"`
|
||||
}
|
||||
|
||||
func (m *Method) C14N() string {
|
||||
return mkns("ds", m, &m.XMLName)
|
||||
}
|
||||
|
||||
type Value struct {
|
||||
XMLName xml.Name
|
||||
Value string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
func (v *Value) C14N() string {
|
||||
return mkns("ds", v, &v.XMLName)
|
||||
}
|
||||
|
||||
type Reference struct {
|
||||
XMLName xml.Name
|
||||
URI string `xml:",attr"`
|
||||
Transforms Transforms
|
||||
DigestMethod Method
|
||||
DigestValue Value
|
||||
}
|
||||
|
||||
func (r Reference) C14N() string {
|
||||
for i := range r.Transforms.Transform {
|
||||
t := &r.Transforms.Transform[i]
|
||||
t.XMLName.Local = "ds:Transform"
|
||||
t.XMLName.Space = ""
|
||||
|
||||
if t.InclusiveNamespaces != nil {
|
||||
name := &t.InclusiveNamespaces.XMLName
|
||||
if !strings.HasPrefix(name.Local, "ec:") {
|
||||
name.Local = "ec:" + name.Local
|
||||
name.Space = ""
|
||||
}
|
||||
t.InclusiveNamespaces.NS = t.Algorithm
|
||||
}
|
||||
}
|
||||
|
||||
c14n := []string{
|
||||
fmt.Sprintf(`<ds:Reference URI="%s">`, r.URI),
|
||||
r.Transforms.C14N(),
|
||||
r.DigestMethod.C14N(),
|
||||
r.DigestValue.C14N(),
|
||||
"</ds:Reference>",
|
||||
}
|
||||
|
||||
return strings.Join(c14n, "")
|
||||
}
|
||||
|
||||
func NewReference(id string, val string) Reference {
|
||||
sum := sha256.Sum256([]byte(val))
|
||||
|
||||
return Reference{
|
||||
XMLName: xml.Name{Local: "ds:Reference"},
|
||||
URI: "#" + id,
|
||||
Transforms: Transforms{
|
||||
XMLName: xml.Name{Local: "ds:Transforms"},
|
||||
Transform: []Transform{
|
||||
Transform{
|
||||
XMLName: xml.Name{Local: "ds:Transform"},
|
||||
Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#",
|
||||
},
|
||||
},
|
||||
},
|
||||
DigestMethod: Method{
|
||||
XMLName: xml.Name{Local: "ds:DigestMethod"},
|
||||
Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256",
|
||||
},
|
||||
DigestValue: Value{
|
||||
XMLName: xml.Name{Local: "ds:DigestValue"},
|
||||
Value: base64.StdEncoding.EncodeToString(sum[:]),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type Transforms struct {
|
||||
XMLName xml.Name
|
||||
Transform []Transform
|
||||
}
|
||||
|
||||
func (t *Transforms) C14N() string {
|
||||
return mkns("ds", t, &t.XMLName)
|
||||
}
|
||||
|
||||
type Transform struct {
|
||||
XMLName xml.Name
|
||||
Algorithm string `xml:",attr"`
|
||||
InclusiveNamespaces *InclusiveNamespaces `xml:",omitempty"`
|
||||
}
|
||||
|
||||
type InclusiveNamespaces struct {
|
||||
XMLName xml.Name
|
||||
NS string `xml:"xmlns:ec,attr,omitempty"`
|
||||
PrefixList string `xml:",attr"`
|
||||
}
|
||||
|
||||
type X509Data struct {
|
||||
XMLName xml.Name
|
||||
X509Certificate string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
type KeyInfo struct {
|
||||
XMLName xml.Name
|
||||
NS string `xml:"xmlns:ds,attr,omitempty"`
|
||||
SecurityTokenReference *SecurityTokenReference `xml:",omitempty"`
|
||||
X509Data *X509Data `xml:",omitempty"`
|
||||
}
|
||||
|
||||
func (o *KeyInfo) C14N() string {
|
||||
names := []*xml.Name{
|
||||
&o.XMLName,
|
||||
}
|
||||
|
||||
if o.SecurityTokenReference != nil {
|
||||
names = append(names, &o.SecurityTokenReference.XMLName)
|
||||
}
|
||||
if o.X509Data != nil {
|
||||
names = append(names, &o.X509Data.XMLName)
|
||||
}
|
||||
|
||||
return mkns("ds", o, names...)
|
||||
}
|
||||
|
||||
type SecurityTokenReference struct {
|
||||
XMLName xml.Name `xml:"wsse:SecurityTokenReference"`
|
||||
WSSE11 string `xml:"xmlns:wsse11,attr,omitempty"`
|
||||
TokenType string `xml:"wsse11:TokenType,attr,omitempty"`
|
||||
Reference *SecurityReference `xml:",omitempty"`
|
||||
KeyIdentifier *KeyIdentifier `xml:",omitempty"`
|
||||
}
|
||||
|
||||
type SecurityReference struct {
|
||||
XMLName xml.Name `xml:"wsse:Reference"`
|
||||
URI string `xml:",attr"`
|
||||
ValueType string `xml:",attr"`
|
||||
}
|
||||
|
||||
type KeyIdentifier struct {
|
||||
XMLName xml.Name `xml:"wsse:KeyIdentifier"`
|
||||
ID string `xml:",innerxml"`
|
||||
ValueType string `xml:",attr"`
|
||||
}
|
||||
|
||||
type Issuer struct {
|
||||
XMLName xml.Name
|
||||
Format string `xml:",attr"`
|
||||
Value string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
func (i *Issuer) C14N() string {
|
||||
return mkns("saml2", i, &i.XMLName)
|
||||
}
|
||||
|
||||
type Assertion struct {
|
||||
XMLName xml.Name
|
||||
ID string `xml:",attr"`
|
||||
IssueInstant string `xml:",attr"`
|
||||
Version string `xml:",attr"`
|
||||
Issuer Issuer
|
||||
Signature Signature
|
||||
Subject Subject
|
||||
Conditions Conditions
|
||||
AuthnStatement AuthnStatement
|
||||
AttributeStatement AttributeStatement
|
||||
}
|
||||
|
||||
func (a *Assertion) C14N() string {
|
||||
start := `<saml2:Assertion xmlns:saml2="%s" ID="%s" IssueInstant="%s" Version="%s">`
|
||||
c14n := []string{
|
||||
fmt.Sprintf(start, a.XMLName.Space, a.ID, a.IssueInstant, a.Version),
|
||||
a.Issuer.C14N(),
|
||||
a.Signature.C14N(),
|
||||
a.Subject.C14N(),
|
||||
a.Conditions.C14N(),
|
||||
a.AuthnStatement.C14N(),
|
||||
a.AttributeStatement.C14N(),
|
||||
`</saml2:Assertion>`,
|
||||
}
|
||||
|
||||
return strings.Join(c14n, "")
|
||||
}
|
||||
|
||||
type NameID struct {
|
||||
XMLName xml.Name
|
||||
Format string `xml:",attr"`
|
||||
ID string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
type Subject struct {
|
||||
XMLName xml.Name
|
||||
NameID NameID
|
||||
SubjectConfirmation SubjectConfirmation
|
||||
}
|
||||
|
||||
func (s *Subject) C14N() string {
|
||||
data := &s.SubjectConfirmation.SubjectConfirmationData
|
||||
names := []*xml.Name{
|
||||
&s.XMLName,
|
||||
&s.NameID.XMLName,
|
||||
&s.SubjectConfirmation.XMLName,
|
||||
&data.XMLName,
|
||||
}
|
||||
if s.SubjectConfirmation.NameID != nil {
|
||||
names = append(names, &s.SubjectConfirmation.NameID.XMLName)
|
||||
}
|
||||
if data.KeyInfo != nil {
|
||||
data.NS = XSI
|
||||
data.Type = "saml2:KeyInfoConfirmationDataType"
|
||||
data.KeyInfo.XMLName = xml.Name{Local: "ds:KeyInfo"}
|
||||
data.KeyInfo.X509Data.XMLName = xml.Name{Local: "ds:X509Data"}
|
||||
data.KeyInfo.NS = DSIG
|
||||
}
|
||||
return mkns("saml2", s, names...)
|
||||
}
|
||||
|
||||
type SubjectConfirmationData struct {
|
||||
XMLName xml.Name
|
||||
NS string `xml:"xmlns:xsi,attr,omitempty"`
|
||||
Type string `xml:"xsi:type,attr,omitempty"`
|
||||
NotOnOrAfter string `xml:",attr,omitempty"`
|
||||
KeyInfo *KeyInfo
|
||||
}
|
||||
|
||||
type SubjectConfirmation struct {
|
||||
XMLName xml.Name
|
||||
Method string `xml:",attr"`
|
||||
NameID *NameID
|
||||
SubjectConfirmationData SubjectConfirmationData
|
||||
}
|
||||
|
||||
type Condition struct {
|
||||
Type string `xml:"xsi:type,attr,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Condition) GetCondition() *Condition {
|
||||
return c
|
||||
}
|
||||
|
||||
type BaseCondition interface {
|
||||
GetCondition() *Condition
|
||||
}
|
||||
|
||||
func init() {
|
||||
types.Add("BaseCondition", reflect.TypeOf((*Condition)(nil)).Elem())
|
||||
types.Add("del:DelegationRestrictionType", reflect.TypeOf((*DelegateRestriction)(nil)).Elem())
|
||||
types.Add("rsa:RenewRestrictionType", reflect.TypeOf((*RenewRestriction)(nil)).Elem())
|
||||
}
|
||||
|
||||
type Conditions struct {
|
||||
XMLName xml.Name
|
||||
NotBefore string `xml:",attr"`
|
||||
NotOnOrAfter string `xml:",attr"`
|
||||
ProxyRestriction *ProxyRestriction `xml:",omitempty"`
|
||||
Condition []BaseCondition `xml:",omitempty"`
|
||||
}
|
||||
|
||||
func (c *Conditions) C14N() string {
|
||||
names := []*xml.Name{
|
||||
&c.XMLName,
|
||||
}
|
||||
|
||||
if c.ProxyRestriction != nil {
|
||||
names = append(names, &c.ProxyRestriction.XMLName)
|
||||
}
|
||||
|
||||
for i := range c.Condition {
|
||||
switch r := c.Condition[i].(type) {
|
||||
case *DelegateRestriction:
|
||||
names = append(names, &r.XMLName, &r.Delegate.NameID.XMLName)
|
||||
r.NS = XSI
|
||||
r.Type = "del:DelegationRestrictionType"
|
||||
r.Delegate.NS = r.Delegate.XMLName.Space
|
||||
r.Delegate.XMLName = xml.Name{Local: "del:Delegate"}
|
||||
case *RenewRestriction:
|
||||
names = append(names, &r.XMLName)
|
||||
r.NS = XSI
|
||||
r.Type = "rsa:RenewRestrictionType"
|
||||
}
|
||||
}
|
||||
|
||||
return mkns("saml2", c, names...)
|
||||
}
|
||||
|
||||
type ProxyRestriction struct {
|
||||
XMLName xml.Name
|
||||
Count int32 `xml:",attr"`
|
||||
}
|
||||
|
||||
type RenewRestriction struct {
|
||||
XMLName xml.Name
|
||||
NS string `xml:"xmlns:xsi,attr,omitempty"`
|
||||
Count int32 `xml:",attr"`
|
||||
Condition
|
||||
}
|
||||
|
||||
type Delegate struct {
|
||||
XMLName xml.Name
|
||||
NS string `xml:"xmlns:del,attr,omitempty"`
|
||||
DelegationInstant string `xml:",attr"`
|
||||
NameID NameID
|
||||
}
|
||||
|
||||
type DelegateRestriction struct {
|
||||
XMLName xml.Name
|
||||
NS string `xml:"xmlns:xsi,attr,omitempty"`
|
||||
Condition
|
||||
Delegate Delegate
|
||||
}
|
||||
|
||||
type AuthnStatement struct {
|
||||
XMLName xml.Name
|
||||
AuthnInstant string `xml:",attr"`
|
||||
AuthnContext struct {
|
||||
XMLName xml.Name
|
||||
AuthnContextClassRef struct {
|
||||
XMLName xml.Name
|
||||
Value string `xml:",innerxml"`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AuthnStatement) C14N() string {
|
||||
return mkns("saml2", a, &a.XMLName, &a.AuthnContext.XMLName, &a.AuthnContext.AuthnContextClassRef.XMLName)
|
||||
}
|
||||
|
||||
type AttributeStatement struct {
|
||||
XMLName xml.Name
|
||||
Attribute []Attribute
|
||||
}
|
||||
|
||||
func (a *AttributeStatement) C14N() string {
|
||||
c14n := []string{"<saml2:AttributeStatement>"}
|
||||
for i := range a.Attribute {
|
||||
c14n = append(c14n, a.Attribute[i].C14N())
|
||||
}
|
||||
c14n = append(c14n, "</saml2:AttributeStatement>")
|
||||
return strings.Join(c14n, "")
|
||||
}
|
||||
|
||||
type AttributeValue struct {
|
||||
XMLName xml.Name
|
||||
Type string `xml:"type,attr"`
|
||||
Value string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
func (a *AttributeValue) C14N() string {
|
||||
return fmt.Sprintf(`<saml2:AttributeValue xmlns:xsi="%s" xsi:type="xs:string">%s</saml2:AttributeValue>`, XSI, a.Value)
|
||||
}
|
||||
|
||||
type Attribute struct {
|
||||
XMLName xml.Name
|
||||
FriendlyName string `xml:",attr"`
|
||||
Name string `xml:",attr"`
|
||||
NameFormat string `xml:",attr"`
|
||||
AttributeValue []AttributeValue
|
||||
}
|
||||
|
||||
func (a *Attribute) C14N() string {
|
||||
c14n := []string{
|
||||
fmt.Sprintf(`<saml2:Attribute FriendlyName="%s" Name="%s" NameFormat="%s">`, a.FriendlyName, a.Name, a.NameFormat),
|
||||
}
|
||||
|
||||
for i := range a.AttributeValue {
|
||||
c14n = append(c14n, a.AttributeValue[i].C14N())
|
||||
}
|
||||
|
||||
c14n = append(c14n, `</saml2:Attribute>`)
|
||||
|
||||
return strings.Join(c14n, "")
|
||||
}
|
||||
|
||||
type Lifetime struct {
|
||||
Created string `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd Created"`
|
||||
Expires string `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd Expires"`
|
||||
}
|
||||
|
||||
func (t *Lifetime) C14N() string {
|
||||
return fmt.Sprintf(`<Lifetime><wsu:Created>%s</wsu:Created><wsu:Expires>%s</wsu:Expires></Lifetime>`, t.Created, t.Expires)
|
||||
}
|
||||
|
||||
type Renewing struct {
|
||||
Allow bool `xml:",attr"`
|
||||
OK bool `xml:",attr"`
|
||||
}
|
||||
|
||||
type UseKey struct {
|
||||
Sig string `xml:",attr"`
|
||||
}
|
||||
|
||||
type Target struct {
|
||||
Token string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
type RequestSecurityToken struct {
|
||||
TokenType string `xml:",omitempty"`
|
||||
RequestType string `xml:",omitempty"`
|
||||
Lifetime *Lifetime `xml:",omitempty"`
|
||||
Renewing *Renewing `xml:",omitempty"`
|
||||
Delegatable bool `xml:",omitempty"`
|
||||
KeyType string `xml:",omitempty"`
|
||||
SignatureAlgorithm string `xml:",omitempty"`
|
||||
UseKey *UseKey `xml:",omitempty"`
|
||||
ActAs *Target `xml:",omitempty"`
|
||||
ValidateTarget *Target `xml:",omitempty"`
|
||||
RenewTarget *Target `xml:",omitempty"`
|
||||
}
|
||||
|
||||
func Unmarshal(data []byte, v interface{}) error {
|
||||
dec := xml.NewDecoder(bytes.NewReader(data))
|
||||
dec.TypeFunc = types.TypeFunc()
|
||||
return dec.Decode(v)
|
||||
}
|
||||
|
||||
// toString returns an XML encoded RequestSecurityToken.
|
||||
// When c14n is true, returns the canonicalized ActAs.Assertion which is required to sign the Issue request.
|
||||
// When c14n is false, returns the original content of the ActAs.Assertion.
|
||||
// The original content must be used within the request Body, as it has its own signature.
|
||||
func (r *RequestSecurityToken) toString(c14n bool) string {
|
||||
actas := ""
|
||||
if r.ActAs != nil {
|
||||
token := r.ActAs.Token
|
||||
if c14n {
|
||||
var a Assertion
|
||||
err := Unmarshal([]byte(r.ActAs.Token), &a)
|
||||
if err != nil {
|
||||
log.Printf("decode ActAs: %s", err)
|
||||
}
|
||||
token = a.C14N()
|
||||
}
|
||||
|
||||
actas = fmt.Sprintf(`<wst:ActAs xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200802">%s</wst:ActAs>`, token)
|
||||
}
|
||||
|
||||
body := []string{
|
||||
fmt.Sprintf(`<RequestSecurityToken xmlns="http://docs.oasis-open.org/ws-sx/ws-trust/200512">`),
|
||||
fmt.Sprintf(`<TokenType>%s</TokenType>`, r.TokenType),
|
||||
fmt.Sprintf(`<RequestType>%s</RequestType>`, r.RequestType),
|
||||
r.Lifetime.C14N(),
|
||||
}
|
||||
|
||||
if r.RenewTarget == nil {
|
||||
body = append(body,
|
||||
fmt.Sprintf(`<Renewing Allow="%t" OK="%t"></Renewing>`, r.Renewing.Allow, r.Renewing.OK),
|
||||
fmt.Sprintf(`<Delegatable>%t</Delegatable>`, r.Delegatable),
|
||||
actas,
|
||||
fmt.Sprintf(`<KeyType>%s</KeyType>`, r.KeyType),
|
||||
fmt.Sprintf(`<SignatureAlgorithm>%s</SignatureAlgorithm>`, r.SignatureAlgorithm),
|
||||
fmt.Sprintf(`<UseKey Sig="%s"></UseKey>`, r.UseKey.Sig))
|
||||
} else {
|
||||
token := r.RenewTarget.Token
|
||||
if c14n {
|
||||
var a Assertion
|
||||
err := Unmarshal([]byte(r.RenewTarget.Token), &a)
|
||||
if err != nil {
|
||||
log.Printf("decode Renew: %s", err)
|
||||
}
|
||||
token = a.C14N()
|
||||
}
|
||||
|
||||
body = append(body,
|
||||
fmt.Sprintf(`<UseKey Sig="%s"></UseKey>`, r.UseKey.Sig),
|
||||
fmt.Sprintf(`<RenewTarget>%s</RenewTarget>`, token))
|
||||
}
|
||||
|
||||
return strings.Join(append(body, `</RequestSecurityToken>`), "")
|
||||
}
|
||||
|
||||
func (r *RequestSecurityToken) C14N() string {
|
||||
return r.toString(true)
|
||||
}
|
||||
|
||||
func (r *RequestSecurityToken) String() string {
|
||||
return r.toString(false)
|
||||
}
|
||||
|
||||
type RequestSecurityTokenResponseCollection struct {
|
||||
RequestSecurityTokenResponse RequestSecurityTokenResponse
|
||||
}
|
||||
|
||||
type RequestSecurityTokenResponse struct {
|
||||
RequestedSecurityToken RequestedSecurityToken
|
||||
Lifetime *Lifetime `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 Lifetime"`
|
||||
}
|
||||
|
||||
type RequestedSecurityToken struct {
|
||||
Assertion string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
type RequestSecurityTokenBody struct {
|
||||
Req *RequestSecurityToken `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityToken,omitempty"`
|
||||
Res *RequestSecurityTokenResponseCollection `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityTokenResponseCollection,omitempty"`
|
||||
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
|
||||
}
|
||||
|
||||
func (b *RequestSecurityTokenBody) Fault() *soap.Fault { return b.Fault_ }
|
||||
|
||||
func (b *RequestSecurityTokenBody) RequestSecurityToken() *RequestSecurityToken { return b.Req }
|
||||
|
||||
func (r *RequestSecurityToken) Action() string {
|
||||
kind := path.Base(r.RequestType)
|
||||
return "http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/" + kind
|
||||
}
|
||||
|
||||
func Issue(ctx context.Context, r soap.RoundTripper, req *RequestSecurityToken) (*RequestSecurityTokenResponseCollection, error) {
|
||||
var reqBody, resBody RequestSecurityTokenBody
|
||||
|
||||
reqBody.Req = req
|
||||
|
||||
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resBody.Res, nil
|
||||
}
|
||||
|
||||
type RenewSecurityTokenBody struct {
|
||||
Req *RequestSecurityToken `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityToken,omitempty"`
|
||||
Res *RequestSecurityTokenResponse `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityTokenResponse,omitempty"`
|
||||
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
|
||||
}
|
||||
|
||||
func (b *RenewSecurityTokenBody) Fault() *soap.Fault { return b.Fault_ }
|
||||
|
||||
func (b *RenewSecurityTokenBody) RequestSecurityToken() *RequestSecurityToken { return b.Req }
|
||||
|
||||
func Renew(ctx context.Context, r soap.RoundTripper, req *RequestSecurityToken) (*RequestSecurityTokenResponse, error) {
|
||||
var reqBody, resBody RenewSecurityTokenBody
|
||||
|
||||
reqBody.Req = req
|
||||
|
||||
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resBody.Res, nil
|
||||
}
|
||||
|
||||
// Marshal panics if xml.Marshal returns an error
|
||||
func Marshal(val interface{}) string {
|
||||
b, err := xml.Marshal(val)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// mkns prepends the given namespace to xml.Name.Local and returns obj encoded as xml.
|
||||
// Note that the namespace is required when encoding, but the namespace prefix must not be
|
||||
// present when decoding as Go's decoding does not handle namespace prefix.
|
||||
func mkns(ns string, obj interface{}, name ...*xml.Name) string {
|
||||
ns = ns + ":"
|
||||
for i := range name {
|
||||
name[i].Space = ""
|
||||
if !strings.HasPrefix(name[i].Local, ns) {
|
||||
name[i].Local = ns + name[i].Local
|
||||
}
|
||||
}
|
||||
|
||||
return Marshal(obj)
|
||||
}
|
||||
220
vendor/github.com/vmware/govmomi/sts/signer.go
generated
vendored
Normal file
220
vendor/github.com/vmware/govmomi/sts/signer.go
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sts
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/vmware/govmomi/sts/internal"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/xml"
|
||||
)
|
||||
|
||||
// Signer implements the soap.Signer interface.
|
||||
type Signer struct {
|
||||
Token string // Token is a SAML token
|
||||
Certificate *tls.Certificate // Certificate is used to sign requests
|
||||
Lifetime struct {
|
||||
Created time.Time
|
||||
Expires time.Time
|
||||
}
|
||||
user *url.Userinfo // user contains the credentials for bearer token request
|
||||
keyID string // keyID is the Signature UseKey ID, which is referenced in both the soap body and header
|
||||
}
|
||||
|
||||
// signedEnvelope is similar to soap.Envelope, but with namespace and Body as innerxml
|
||||
type signedEnvelope struct {
|
||||
XMLName xml.Name `xml:"soap:Envelope"`
|
||||
NS string `xml:"xmlns:soap,attr"`
|
||||
Header soap.Header `xml:"soap:Header"`
|
||||
Body string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
// newID returns a unique Reference ID, with a leading underscore as required by STS.
|
||||
func newID() string {
|
||||
return "_" + uuid.New().String()
|
||||
}
|
||||
|
||||
func (s *Signer) setTokenReference(info *internal.KeyInfo) error {
|
||||
var token struct {
|
||||
ID string `xml:",attr"` // parse saml2:Assertion ID attribute
|
||||
InnerXML string `xml:",innerxml"` // no need to parse the entire token
|
||||
}
|
||||
if err := xml.Unmarshal([]byte(s.Token), &token); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info.SecurityTokenReference = &internal.SecurityTokenReference{
|
||||
WSSE11: "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd",
|
||||
TokenType: "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0",
|
||||
KeyIdentifier: &internal.KeyIdentifier{
|
||||
ID: token.ID,
|
||||
ValueType: "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID",
|
||||
},
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sign is a soap.Signer implementation which can be used to sign RequestSecurityToken and LoginByTokenBody requests.
|
||||
func (s *Signer) Sign(env soap.Envelope) ([]byte, error) {
|
||||
var key *rsa.PrivateKey
|
||||
hasKey := false
|
||||
if s.Certificate != nil {
|
||||
key, hasKey = s.Certificate.PrivateKey.(*rsa.PrivateKey)
|
||||
if !hasKey {
|
||||
return nil, errors.New("sts: rsa.PrivateKey is required")
|
||||
}
|
||||
}
|
||||
|
||||
created := time.Now().UTC()
|
||||
header := &internal.Security{
|
||||
WSU: internal.WSU,
|
||||
WSSE: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
|
||||
Timestamp: internal.Timestamp{
|
||||
NS: internal.WSU,
|
||||
ID: newID(),
|
||||
Created: created.Format(internal.Time),
|
||||
Expires: created.Add(time.Minute).Format(internal.Time), // If STS receives this request after this, it is assumed to have expired.
|
||||
},
|
||||
}
|
||||
env.Header.Security = header
|
||||
|
||||
info := internal.KeyInfo{XMLName: xml.Name{Local: "ds:KeyInfo"}}
|
||||
var c14n, body string
|
||||
type requestToken interface {
|
||||
RequestSecurityToken() *internal.RequestSecurityToken
|
||||
}
|
||||
|
||||
switch x := env.Body.(type) {
|
||||
case requestToken:
|
||||
if hasKey {
|
||||
// We need c14n for all requests, as its digest is included in the signature and must match on the server side.
|
||||
// We need the body in original form when using an ActAs or RenewTarget token, where the token and its signature are embedded in the body.
|
||||
req := x.RequestSecurityToken()
|
||||
c14n = req.C14N()
|
||||
body = req.String()
|
||||
id := newID()
|
||||
|
||||
info.SecurityTokenReference = &internal.SecurityTokenReference{
|
||||
Reference: &internal.SecurityReference{
|
||||
URI: "#" + id,
|
||||
ValueType: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3",
|
||||
},
|
||||
}
|
||||
|
||||
header.BinarySecurityToken = &internal.BinarySecurityToken{
|
||||
EncodingType: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary",
|
||||
ValueType: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3",
|
||||
ID: id,
|
||||
Value: base64.StdEncoding.EncodeToString(s.Certificate.Certificate[0]),
|
||||
}
|
||||
} else {
|
||||
header.UsernameToken = &internal.UsernameToken{
|
||||
Username: s.user.Username(),
|
||||
}
|
||||
header.UsernameToken.Password, _ = s.user.Password()
|
||||
}
|
||||
case *methods.LoginByTokenBody:
|
||||
header.Assertion = s.Token
|
||||
|
||||
if hasKey {
|
||||
if err := s.setTokenReference(&info); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c14n = internal.Marshal(x.Req)
|
||||
}
|
||||
default:
|
||||
// We can end up here via ssoadmin.SessionManager.Login().
|
||||
// No other known cases where a signed request is needed.
|
||||
header.Assertion = s.Token
|
||||
if hasKey {
|
||||
if err := s.setTokenReference(&info); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
type Req interface {
|
||||
C14N() string
|
||||
}
|
||||
c14n = env.Body.(Req).C14N()
|
||||
}
|
||||
}
|
||||
|
||||
if !hasKey {
|
||||
return xml.Marshal(env) // Bearer token without key to sign
|
||||
}
|
||||
|
||||
id := newID()
|
||||
tmpl := `<soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="%s" wsu:Id="%s">%s</soap:Body>`
|
||||
c14n = fmt.Sprintf(tmpl, internal.WSU, id, c14n)
|
||||
if body == "" {
|
||||
body = c14n
|
||||
} else {
|
||||
body = fmt.Sprintf(tmpl, internal.WSU, id, body)
|
||||
}
|
||||
|
||||
header.Signature = &internal.Signature{
|
||||
XMLName: xml.Name{Local: "ds:Signature"},
|
||||
NS: internal.DSIG,
|
||||
ID: s.keyID,
|
||||
KeyInfo: info,
|
||||
SignedInfo: internal.SignedInfo{
|
||||
XMLName: xml.Name{Local: "ds:SignedInfo"},
|
||||
NS: internal.DSIG,
|
||||
CanonicalizationMethod: internal.Method{
|
||||
XMLName: xml.Name{Local: "ds:CanonicalizationMethod"},
|
||||
Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#",
|
||||
},
|
||||
SignatureMethod: internal.Method{
|
||||
XMLName: xml.Name{Local: "ds:SignatureMethod"},
|
||||
Algorithm: internal.SHA256,
|
||||
},
|
||||
Reference: []internal.Reference{
|
||||
internal.NewReference(header.Timestamp.ID, header.Timestamp.C14N()),
|
||||
internal.NewReference(id, c14n),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
sum := sha256.Sum256([]byte(header.Signature.SignedInfo.C14N()))
|
||||
sig, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, sum[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
header.Signature.SignatureValue = internal.Value{
|
||||
XMLName: xml.Name{Local: "ds:SignatureValue"},
|
||||
Value: base64.StdEncoding.EncodeToString(sig),
|
||||
}
|
||||
|
||||
return xml.Marshal(signedEnvelope{
|
||||
NS: "http://schemas.xmlsoap.org/soap/envelope/",
|
||||
Header: *env.Header,
|
||||
Body: body,
|
||||
})
|
||||
}
|
||||
134
vendor/github.com/vmware/govmomi/sts/simulator/simulator.go
generated
vendored
Normal file
134
vendor/github.com/vmware/govmomi/sts/simulator/simulator.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/sts/internal"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
vim "github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// New creates an STS simulator and configures the simulator endpoint in the given settings.
|
||||
// The path returned is that of the settings "config.vpxd.sso.sts.uri" property.
|
||||
func New(u *url.URL, settings []vim.BaseOptionValue) (string, http.Handler) {
|
||||
for i := range settings {
|
||||
setting := settings[i].GetOptionValue()
|
||||
if setting.Key == "config.vpxd.sso.sts.uri" {
|
||||
endpoint, _ := url.Parse(setting.Value.(string))
|
||||
endpoint.Host = u.Host
|
||||
setting.Value = endpoint.String()
|
||||
settings[i] = setting
|
||||
return endpoint.Path, new(handler)
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
type handler struct{}
|
||||
|
||||
// ServeHTTP handles STS requests.
|
||||
func (s *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
action := r.Header.Get("SOAPAction")
|
||||
env := soap.Envelope{}
|
||||
now := time.Now()
|
||||
lifetime := &internal.Lifetime{
|
||||
Created: now.Format(internal.Time),
|
||||
Expires: now.Add(5 * time.Minute).Format(internal.Time),
|
||||
}
|
||||
|
||||
switch path.Base(action) {
|
||||
case "Issue":
|
||||
body := internal.RequestSecurityTokenBody{
|
||||
Res: &internal.RequestSecurityTokenResponseCollection{
|
||||
RequestSecurityTokenResponse: internal.RequestSecurityTokenResponse{
|
||||
RequestedSecurityToken: internal.RequestedSecurityToken{
|
||||
Assertion: token,
|
||||
},
|
||||
Lifetime: lifetime,
|
||||
},
|
||||
},
|
||||
}
|
||||
env.Body = body
|
||||
case "Renew":
|
||||
body := internal.RenewSecurityTokenBody{
|
||||
Res: &internal.RequestSecurityTokenResponse{
|
||||
RequestedSecurityToken: internal.RequestedSecurityToken{
|
||||
Assertion: token,
|
||||
},
|
||||
Lifetime: lifetime,
|
||||
},
|
||||
}
|
||||
env.Body = body
|
||||
default:
|
||||
log.Printf("sts: unsupported action=%s", action)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprint(w, internal.Marshal(env))
|
||||
}
|
||||
|
||||
// Currently simulator.SessionManager.LoginByToken() only checks for a non-empty Assertion.Subject.NameID field,
|
||||
// so the token below is returned by Issue and Renew requests for now.
|
||||
var token = `<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="_1881a9ba-4a76-4baa-839b-36e2cba10743" IssueInstant="2018-03-04T00:27:56.409Z" Version="2.0"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://office1-sfo2-dhcp221.eng.vmware.com/websso/SAML2/Metadata/vsphere.local</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#_1881a9ba-4a76-4baa-839b-36e2cba10743"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs xsi"/></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>l/0AzCGiPB69oTstUdrCkihBIDtwb83A93zAe10tG3k=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>EKHf14V0CHctwqXRlhYSYNyID5lNJLimbw57eUBm/QlAMLY7GJ1wth44oeQPSj3eMpJaXKHEYYtn
|
||||
fqMngciTrq4ZP2SS7KizxuBjcHChWGmcp+t0zn7+fTbp5sL8HfF3AfOwcyZxwj8n2S7E6Eee7zeC
|
||||
cjZpKKZ1QIEwASwpuMCs7vU9IuXsUguHAaN55Jpx3N5u7PlSo/NZE0TJZ+zNWP8m9H5shPDY272D
|
||||
Vnp3MGfoD+Dj6T4H8OVF6bMp6czbHsEHTthwPh+pBTzR8ppkyxPKWLkC7OWiOtZBKqLSMTchQyqn
|
||||
GNJdl72FBXHS8WXGtJjbwL+MKf+WujhqwdRbXw==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDxTCCAq2gAwIBAgIJAMYXe1r3pfByMA0GCSqGSIb3DQEBCwUAMIGqMQswCQYDVQQDDAJDQTEX
|
||||
MBUGCgmSJomT8ixkARkWB3ZzcGhlcmUxFTATBgoJkiaJk/IsZAEZFgVsb2NhbDELMAkGA1UEBhMC
|
||||
VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExLDAqBgNVBAoMI29mZmljZTEtc2ZvMi1kaGNwMjIxLmVu
|
||||
Zy52bXdhcmUuY29tMRswGQYDVQQLDBJWTXdhcmUgRW5naW5lZXJpbmcwHhcNMTgwMTExMjE1MjQ3
|
||||
WhcNMjgwMTA2MjIwMjMxWjAYMRYwFAYDVQQDDA1zc29zZXJ2ZXJTaWduMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAohfKdXEpiCB+EewJJKk98he/KeAK/1bZ2MjnLspwt3Nvv2uh2xoa
|
||||
1asP/TMAhxcztPxhqEZmi0W+nihF/yffY/AhQrGx9XynaOMUNarCNGVI2qBovi8gohT2pXlbKxgZ
|
||||
b8VZkVl41WYkDBfQrzoP0XU/sFeOoNIHcFQX/82NFAYtN/4aBZ9gDqhyPihv2RSNG4MnvxxgxtZI
|
||||
FPb3eyDt8poKOMjt8zG2JkJRQYiEOCLo/sKJEKXLZeWiqYsbk391/vIk2vaX3L3pgu8yYx/dLfxv
|
||||
X/mRYIOcVzpXWQCEPdCejQBwrmVeRaepW5cMhOVlMAAw+mEXYVVTaIi1pfN53wIDAQABo38wfTAL
|
||||
BgNVHQ8EBAMCBeAwLgYDVR0RBCcwJYIjb2ZmaWNlMS1zZm8yLWRoY3AyMjEuZW5nLnZtd2FyZS5j
|
||||
b20wHQYDVR0OBBYEFAtGcFg9jVO3aBjgd2K0iBFTAPNSMB8GA1UdIwQYMBaAFLpyqy2v1I7a3URK
|
||||
ohtSLAtqve5qMA0GCSqGSIb3DQEBCwUAA4IBAQB91dZHRFunBs+YvuOYFRlwJTZOPXzlSYurxC7h
|
||||
VeYv6LUGZnuTkp0KfVMsfHyaeDslM8+5F9Iug1jxmEmpeyoaY12zQmxQB6P8lN4jj1Aazj8qmDH6
|
||||
ClaSY4Pp0lOSp9ROVlnLi6sRsRphOg+4MS4UeXGgSFlMN1BWJmXcwCazbii8l/EzGx2QhlVjWMAz
|
||||
lPFQlWQ4FvV5vUCf8iE+UTin+6oJSXmFzip1NOBOGiIbClmpergZUchNiqTYTrpqblD/Qex5Bv9e
|
||||
+xAwuw8e0Lm0XICOcFmKvpotLKKiqMMsRqPoeTqnoSyKqvCGRo2hUs4Y4O6SqEd80+E5lbXImrSt</ds:X509Certificate><ds:X509Certificate>MIIEPzCCAyegAwIBAgIJANS+QleTVJNbMA0GCSqGSIb3DQEBCwUAMIGqMQswCQYDVQQDDAJDQTEX
|
||||
MBUGCgmSJomT8ixkARkWB3ZzcGhlcmUxFTATBgoJkiaJk/IsZAEZFgVsb2NhbDELMAkGA1UEBhMC
|
||||
VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExLDAqBgNVBAoMI29mZmljZTEtc2ZvMi1kaGNwMjIxLmVu
|
||||
Zy52bXdhcmUuY29tMRswGQYDVQQLDBJWTXdhcmUgRW5naW5lZXJpbmcwHhcNMTgwMTA4MjIwMjMx
|
||||
WhcNMjgwMTA2MjIwMjMxWjCBqjELMAkGA1UEAwwCQ0ExFzAVBgoJkiaJk/IsZAEZFgd2c3BoZXJl
|
||||
MRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh
|
||||
MSwwKgYDVQQKDCNvZmZpY2UxLXNmbzItZGhjcDIyMS5lbmcudm13YXJlLmNvbTEbMBkGA1UECwwS
|
||||
Vk13YXJlIEVuZ2luZWVyaW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxcN7rsoK
|
||||
CIapsEOYejPK38Qk7CUSPFcOmT7iF15UFlZDogHe1G/ZkYvcP0IvLvpemRiYuRpVGVuUZ9XOgeW6
|
||||
J5xpSuNRXMHSMDTUwLM9t/4NMAQxgWVlJjFmPVBIZiWaQgdCzEbCDcv/XaZeb6uJYlbmLKvopmwy
|
||||
oDfncGXRUuQIZFsVIUhUgOtbbp9UmvXyjo9ukWdVcTkKlKK7NZGaVa4JYy7q4cc6g5eRmD9qp16o
|
||||
vx8DageNAasTP6arnb5CyoGI4KPqJjaI7V4Z1KiOUs+Zj+VtC3XdpVthNtiJ+vgXccO8e7zYfP0y
|
||||
d1PCQ/GEZAlRabus5Iplu4/xC23NywIDAQABo2YwZDAdBgNVHQ4EFgQUunKrLa/UjtrdREqiG1Is
|
||||
C2q97mowHwYDVR0RBBgwFoEOZW1haWxAYWNtZS5jb22HBH8AAAEwDgYDVR0PAQH/BAQDAgEGMBIG
|
||||
A1UdEwEB/wQIMAYBAf8CAQAwDQYJKoZIhvcNAQELBQADggEBAC8bMIhFtlXnCF2fUixTXJ5HZFNY
|
||||
vbxa1eFjLFYuBsGBqhPEHkHkdKwgpfo1sd4t0L7JaGS9wsH6zyRUQs97subV5YUI6rvAPOBGDQTm
|
||||
RmCeqz3ODZq6JwZEnTTqZjvUVckmt/L/QaRUHAW27MU+SuN8rP0Nghf/gkOabsaWfyT2ADquko4e
|
||||
b7seYIlR5mJs+pxVBBsBB2nzxuaV5EjkgestxBqpGkxMnKEDhG6+VjqVxsZoEiNzdBNU7eM67Jc2
|
||||
2KU85jHKAao9LfMbwbHOA//1RStXXElyzPQvecq17ATvpw8AxCRu2KeKRwp3Pm2RiquDQFx8aiCe
|
||||
2Re4gkrEemA=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2:Subject><saml2:NameID Format="http://schemas.xmlsoap.org/claims/UPN">Administrator@VSPHERE.LOCAL</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData NotOnOrAfter="2018-03-04T00:27:01.401Z"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2018-03-04T00:22:01.401Z" NotOnOrAfter="2018-03-04T00:27:01.401Z"><saml2:ProxyRestriction Count="10"/></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2018-03-04T00:27:56.402Z"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement><saml2:AttributeStatement><saml2:Attribute FriendlyName="Groups" Name="http://rsa.com/schemas/attr-names/2009/01/GroupIdentity" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xsi:type="xs:string">vsphere.local\Users</saml2:AttributeValue><saml2:AttributeValue xsi:type="xs:string">vsphere.local\Administrators</saml2:AttributeValue><saml2:AttributeValue xsi:type="xs:string">vsphere.local\CAAdmins</saml2:AttributeValue><saml2:AttributeValue xsi:type="xs:string">vsphere.local\ComponentManager.Administrators</saml2:AttributeValue><saml2:AttributeValue xsi:type="xs:string">vsphere.local\SystemConfiguration.BashShellAdministrators</saml2:AttributeValue><saml2:AttributeValue xsi:type="xs:string">vsphere.local\SystemConfiguration.Administrators</saml2:AttributeValue><saml2:AttributeValue xsi:type="xs:string">vsphere.local\LicenseService.Administrators</saml2:AttributeValue><saml2:AttributeValue xsi:type="xs:string">vsphere.local\ActAsUsers</saml2:AttributeValue><saml2:AttributeValue xsi:type="xs:string">vsphere.local\Everyone</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="givenName" Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xsi:type="xs:string">Administrator</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="surname" Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xsi:type="xs:string">vsphere.local</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="Subject Type" Name="http://vmware.com/schemas/attr-names/2011/07/isSolution" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xsi:type="xs:string">false</saml2:AttributeValue></saml2:Attribute></saml2:AttributeStatement></saml2:Assertion>`
|
||||
Reference in New Issue
Block a user