mirror of
https://github.com/kubernetes/client-go.git
synced 2026-05-15 11:43:33 +00:00
Compare commits
38 Commits
v0.24.15
...
kubernetes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0853ea9489 | ||
|
|
e8ce35d265 | ||
|
|
b1ebb248d0 | ||
|
|
760de9bc08 | ||
|
|
269360b4be | ||
|
|
b2a410d660 | ||
|
|
0982054666 | ||
|
|
69ccf759fc | ||
|
|
13c6fb4c46 | ||
|
|
2a227f04f3 | ||
|
|
031a3824a2 | ||
|
|
b5c4615448 | ||
|
|
b261ffea31 | ||
|
|
ec52d278b2 | ||
|
|
4cbb4d746a | ||
|
|
2f0363f3bf | ||
|
|
54857ec767 | ||
|
|
78b0bb850a | ||
|
|
42398f6a79 | ||
|
|
1ba4b2858a | ||
|
|
d92e8497f7 | ||
|
|
91e3f9312a | ||
|
|
1f9a49df2c | ||
|
|
ec392585e9 | ||
|
|
d9588c19ff | ||
|
|
d1fa9c161c | ||
|
|
0caf586a65 | ||
|
|
16b0436fa2 | ||
|
|
9508caae84 | ||
|
|
25bffd9c45 | ||
|
|
df46f7f13b | ||
|
|
684c9f06e8 | ||
|
|
e356aa2e77 | ||
|
|
d8822e0597 | ||
|
|
e83269bc2b | ||
|
|
382c391988 | ||
|
|
eddc268ce3 | ||
|
|
63a56d7439 |
1056
Godeps/Godeps.json
generated
1056
Godeps/Godeps.json
generated
File diff suppressed because it is too large
Load Diff
@@ -183,7 +183,7 @@ func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (r
|
||||
}
|
||||
|
||||
// serverResources returns the supported resources for all groups and versions.
|
||||
func (d *DiscoveryClient) serverResources(failEarly bool) ([]*metav1.APIResourceList, error) {
|
||||
func (d *DiscoveryClient) serverResources() ([]*metav1.APIResourceList, error) {
|
||||
apiGroups, err := d.ServerGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -199,9 +199,6 @@ func (d *DiscoveryClient) serverResources(failEarly bool) ([]*metav1.APIResource
|
||||
if err != nil {
|
||||
// TODO: maybe restrict this to NotFound errors
|
||||
failedGroups[gv] = err
|
||||
if failEarly {
|
||||
return nil, &ErrGroupDiscoveryFailed{Groups: failedGroups}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -245,7 +242,7 @@ func IsGroupDiscoveryFailedError(err error) bool {
|
||||
}
|
||||
|
||||
// serverPreferredResources returns the supported resources with the version preferred by the server.
|
||||
func (d *DiscoveryClient) serverPreferredResources(failEarly bool) ([]*metav1.APIResourceList, error) {
|
||||
func (d *DiscoveryClient) serverPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||
serverGroupList, err := d.ServerGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -265,9 +262,6 @@ func (d *DiscoveryClient) serverPreferredResources(failEarly bool) ([]*metav1.AP
|
||||
if err != nil {
|
||||
// TODO: maybe restrict this to NotFound errors
|
||||
failedGroups[groupVersion] = err
|
||||
if failEarly {
|
||||
return nil, &ErrGroupDiscoveryFailed{Groups: failedGroups}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -312,9 +306,7 @@ func (d *DiscoveryClient) serverPreferredResources(failEarly bool) ([]*metav1.AP
|
||||
// ServerPreferredResources returns the supported resources with the version preferred by the
|
||||
// server.
|
||||
func (d *DiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||
return withRetries(defaultRetries, func(retryEarly bool) ([]*metav1.APIResourceList, error) {
|
||||
return d.serverPreferredResources(retryEarly)
|
||||
})
|
||||
return withRetries(defaultRetries, d.serverPreferredResources)
|
||||
}
|
||||
|
||||
// ServerPreferredNamespacedResources returns the supported namespaced resources with the
|
||||
@@ -391,12 +383,11 @@ func (d *DiscoveryClient) OpenAPISchema() (*spec.Swagger, error) {
|
||||
}
|
||||
|
||||
// withRetries retries the given recovery function in case the groups supported by the server change after ServerGroup() returns.
|
||||
func withRetries(maxRetries int, f func(failEarly bool) ([]*metav1.APIResourceList, error)) ([]*metav1.APIResourceList, error) {
|
||||
func withRetries(maxRetries int, f func() ([]*metav1.APIResourceList, error)) ([]*metav1.APIResourceList, error) {
|
||||
var result []*metav1.APIResourceList
|
||||
var err error
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
failEarly := i < maxRetries-1
|
||||
result, err = f(failEarly)
|
||||
result, err = f()
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.V
|
||||
for _, group := range groupResources {
|
||||
groupPriority = append(groupPriority, group.Group.Name)
|
||||
|
||||
// Make sure the preferred version comes first
|
||||
if len(group.Group.PreferredVersion.Version) != 0 {
|
||||
preferred := group.Group.PreferredVersion.Version
|
||||
if _, ok := group.VersionedResources[preferred]; ok {
|
||||
@@ -72,6 +73,21 @@ func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.V
|
||||
continue
|
||||
}
|
||||
|
||||
// Add non-preferred versions after the preferred version, in case there are resources that only exist in those versions
|
||||
if discoveryVersion.Version != group.Group.PreferredVersion.Version {
|
||||
resourcePriority = append(resourcePriority, schema.GroupVersionResource{
|
||||
Group: group.Group.Name,
|
||||
Version: discoveryVersion.Version,
|
||||
Resource: meta.AnyResource,
|
||||
})
|
||||
|
||||
kindPriority = append(kindPriority, schema.GroupVersionKind{
|
||||
Group: group.Group.Name,
|
||||
Version: discoveryVersion.Version,
|
||||
Kind: meta.AnyKind,
|
||||
})
|
||||
}
|
||||
|
||||
gv := schema.GroupVersion{Group: group.Group.Name, Version: discoveryVersion.Version}
|
||||
versionMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{gv}, versionInterfaces)
|
||||
|
||||
|
||||
@@ -67,6 +67,32 @@ func TestRESTMapper(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// This group tests finding and prioritizing resources that only exist in non-preferred versions
|
||||
{
|
||||
Group: metav1.APIGroup{
|
||||
Name: "unpreferred",
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{Version: "v1"},
|
||||
{Version: "v2beta1"},
|
||||
{Version: "v2alpha1"},
|
||||
},
|
||||
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1"},
|
||||
},
|
||||
VersionedResources: map[string][]metav1.APIResource{
|
||||
"v1": {
|
||||
{Name: "broccoli", Namespaced: true, Kind: "Broccoli"},
|
||||
},
|
||||
"v2beta1": {
|
||||
{Name: "broccoli", Namespaced: true, Kind: "Broccoli"},
|
||||
{Name: "peas", Namespaced: true, Kind: "Pea"},
|
||||
},
|
||||
"v2alpha1": {
|
||||
{Name: "broccoli", Namespaced: true, Kind: "Broccoli"},
|
||||
{Name: "peas", Namespaced: true, Kind: "Pea"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
restMapper := NewRESTMapper(resources, nil)
|
||||
@@ -123,6 +149,16 @@ func TestRESTMapper(t *testing.T) {
|
||||
Kind: "Job",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: schema.GroupVersionResource{
|
||||
Resource: "peas",
|
||||
},
|
||||
want: schema.GroupVersionKind{
|
||||
Group: "unpreferred",
|
||||
Version: "v2beta1",
|
||||
Kind: "Pea",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range kindTCs {
|
||||
|
||||
@@ -20,9 +20,12 @@ for client-go.
|
||||
- [**Work queues**](./workqueue): Create a hotloop-free controller with the
|
||||
rate-limited workqueue and the [informer framework][informer].
|
||||
- [**Third-party resources (deprecated)**](./third-party-resources-deprecated):
|
||||
Register a third-party resource type with the API, create/update/query this third-party
|
||||
type, and write a controller that drives the cluster state based on the changes to
|
||||
the third-party resources.
|
||||
- [**Custom Resource Definition (successor of TPR)**](https://git.k8s.io/apiextensions-apiserver/examples/client-go):
|
||||
Register a custom resource type with the API, create/update/query this custom
|
||||
type, and write a controller drives the cluster state based on the changes to
|
||||
type, and write a controller that drives the cluster state based on the changes to
|
||||
the custom resources.
|
||||
|
||||
[informer]: https://godoc.org/k8s.io/client-go/tools/cache#NewInformer
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# Custom Resource Example
|
||||
|
||||
**Note:** CustomResourceDefinition is the successor of the deprecated ThirdPartyResource.
|
||||
|
||||
For a client-go example using CustomResourceDefinitions, go to
|
||||
|
||||
[k8s.io/apiextensions-apiserver/examples/client-go](https://git.k8s.io/apiextentions-apiserver/examples/client-go).
|
||||
@@ -1 +0,0 @@
|
||||
797dc10a0ccd89bec0b29c41613025035ed23a0f
|
||||
@@ -615,7 +615,7 @@ type EmptyDirVolumeSource struct {
|
||||
// The default is nil which means that the limit is undefined.
|
||||
// More info: http://kubernetes.io/docs/user-guide/volumes#emptydir
|
||||
// +optional
|
||||
SizeLimit resource.Quantity
|
||||
SizeLimit *resource.Quantity
|
||||
}
|
||||
|
||||
// StorageMedium defines ways that storage can be allocated to a volume.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11488,7 +11488,7 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
_, _, _ = yysep2, yyq2, yy2arr2
|
||||
const yyr2 bool = false
|
||||
yyq2[0] = x.Medium != ""
|
||||
yyq2[1] = true
|
||||
yyq2[1] = x.SizeLimit != nil
|
||||
var yynn2 int
|
||||
if yyr2 || yy2arr2 {
|
||||
r.EncodeArrayStart(2)
|
||||
@@ -11520,15 +11520,18 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[1] {
|
||||
yy7 := &x.SizeLimit
|
||||
yym8 := z.EncBinary()
|
||||
_ = yym8
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(yy7) {
|
||||
} else if !yym8 && z.IsJSONHandle() {
|
||||
z.EncJSONMarshal(yy7)
|
||||
if x.SizeLimit == nil {
|
||||
r.EncodeNil()
|
||||
} else {
|
||||
z.EncFallback(yy7)
|
||||
yym7 := z.EncBinary()
|
||||
_ = yym7
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x.SizeLimit) {
|
||||
} else if !yym7 && z.IsJSONHandle() {
|
||||
z.EncJSONMarshal(x.SizeLimit)
|
||||
} else {
|
||||
z.EncFallback(x.SizeLimit)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r.EncodeNil()
|
||||
@@ -11538,15 +11541,18 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("sizeLimit"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yy9 := &x.SizeLimit
|
||||
yym10 := z.EncBinary()
|
||||
_ = yym10
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(yy9) {
|
||||
} else if !yym10 && z.IsJSONHandle() {
|
||||
z.EncJSONMarshal(yy9)
|
||||
if x.SizeLimit == nil {
|
||||
r.EncodeNil()
|
||||
} else {
|
||||
z.EncFallback(yy9)
|
||||
yym8 := z.EncBinary()
|
||||
_ = yym8
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x.SizeLimit) {
|
||||
} else if !yym8 && z.IsJSONHandle() {
|
||||
z.EncJSONMarshal(x.SizeLimit)
|
||||
} else {
|
||||
z.EncFallback(x.SizeLimit)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11620,17 +11626,21 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromMap(l int, d *codec1978.Decode
|
||||
}
|
||||
case "sizeLimit":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.SizeLimit = pkg3_resource.Quantity{}
|
||||
if x.SizeLimit != nil {
|
||||
x.SizeLimit = nil
|
||||
}
|
||||
} else {
|
||||
yyv5 := &x.SizeLimit
|
||||
if x.SizeLimit == nil {
|
||||
x.SizeLimit = new(pkg3_resource.Quantity)
|
||||
}
|
||||
yym6 := z.DecBinary()
|
||||
_ = yym6
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(yyv5) {
|
||||
} else if z.HasExtensions() && z.DecExt(x.SizeLimit) {
|
||||
} else if !yym6 && z.IsJSONHandle() {
|
||||
z.DecJSONUnmarshal(yyv5)
|
||||
z.DecJSONUnmarshal(x.SizeLimit)
|
||||
} else {
|
||||
z.DecFallback(yyv5, false)
|
||||
z.DecFallback(x.SizeLimit, false)
|
||||
}
|
||||
}
|
||||
default:
|
||||
@@ -11676,17 +11686,21 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Deco
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.SizeLimit = pkg3_resource.Quantity{}
|
||||
if x.SizeLimit != nil {
|
||||
x.SizeLimit = nil
|
||||
}
|
||||
} else {
|
||||
yyv9 := &x.SizeLimit
|
||||
if x.SizeLimit == nil {
|
||||
x.SizeLimit = new(pkg3_resource.Quantity)
|
||||
}
|
||||
yym10 := z.DecBinary()
|
||||
_ = yym10
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(yyv9) {
|
||||
} else if z.HasExtensions() && z.DecExt(x.SizeLimit) {
|
||||
} else if !yym10 && z.IsJSONHandle() {
|
||||
z.DecJSONUnmarshal(yyv9)
|
||||
z.DecJSONUnmarshal(x.SizeLimit)
|
||||
} else {
|
||||
z.DecFallback(yyv9, false)
|
||||
z.DecFallback(x.SizeLimit, false)
|
||||
}
|
||||
}
|
||||
for {
|
||||
|
||||
@@ -700,7 +700,7 @@ type EmptyDirVolumeSource struct {
|
||||
// The default is nil which means that the limit is undefined.
|
||||
// More info: http://kubernetes.io/docs/user-guide/volumes#emptydir
|
||||
// +optional
|
||||
SizeLimit resource.Quantity `json:"sizeLimit,omitempty" protobuf:"bytes,2,opt,name=sizeLimit"`
|
||||
SizeLimit *resource.Quantity `json:"sizeLimit,omitempty" protobuf:"bytes,2,opt,name=sizeLimit"`
|
||||
}
|
||||
|
||||
// Represents a Glusterfs mount that lasts the lifetime of a pod.
|
||||
|
||||
@@ -21,6 +21,7 @@ limitations under the License.
|
||||
package v1
|
||||
|
||||
import (
|
||||
resource "k8s.io/apimachinery/pkg/api/resource"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -1240,7 +1241,7 @@ func Convert_api_DownwardAPIVolumeSource_To_v1_DownwardAPIVolumeSource(in *api.D
|
||||
|
||||
func autoConvert_v1_EmptyDirVolumeSource_To_api_EmptyDirVolumeSource(in *EmptyDirVolumeSource, out *api.EmptyDirVolumeSource, s conversion.Scope) error {
|
||||
out.Medium = api.StorageMedium(in.Medium)
|
||||
out.SizeLimit = in.SizeLimit
|
||||
out.SizeLimit = (*resource.Quantity)(unsafe.Pointer(in.SizeLimit))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1251,7 +1252,7 @@ func Convert_v1_EmptyDirVolumeSource_To_api_EmptyDirVolumeSource(in *EmptyDirVol
|
||||
|
||||
func autoConvert_api_EmptyDirVolumeSource_To_v1_EmptyDirVolumeSource(in *api.EmptyDirVolumeSource, out *EmptyDirVolumeSource, s conversion.Scope) error {
|
||||
out.Medium = StorageMedium(in.Medium)
|
||||
out.SizeLimit = in.SizeLimit
|
||||
out.SizeLimit = (*resource.Quantity)(unsafe.Pointer(in.SizeLimit))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ limitations under the License.
|
||||
package v1
|
||||
|
||||
import (
|
||||
resource "k8s.io/apimachinery/pkg/api/resource"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -858,7 +859,11 @@ func DeepCopy_v1_EmptyDirVolumeSource(in interface{}, out interface{}, c *conver
|
||||
in := in.(*EmptyDirVolumeSource)
|
||||
out := out.(*EmptyDirVolumeSource)
|
||||
*out = *in
|
||||
out.SizeLimit = in.SizeLimit.DeepCopy()
|
||||
if in.SizeLimit != nil {
|
||||
in, out := &in.SizeLimit, &out.SizeLimit
|
||||
*out = new(resource.Quantity)
|
||||
**out = (*in).DeepCopy()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ limitations under the License.
|
||||
package api
|
||||
|
||||
import (
|
||||
resource "k8s.io/apimachinery/pkg/api/resource"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
fields "k8s.io/apimachinery/pkg/fields"
|
||||
@@ -860,7 +861,11 @@ func DeepCopy_api_EmptyDirVolumeSource(in interface{}, out interface{}, c *conve
|
||||
in := in.(*EmptyDirVolumeSource)
|
||||
out := out.(*EmptyDirVolumeSource)
|
||||
*out = *in
|
||||
out.SizeLimit = in.SizeLimit.DeepCopy()
|
||||
if in.SizeLimit != nil {
|
||||
in, out := &in.SizeLimit, &out.SizeLimit
|
||||
*out = new(resource.Quantity)
|
||||
**out = (*in).DeepCopy()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3314,89 +3314,88 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptorGenerated = []byte{
|
||||
// 1331 bytes of a gzipped FileDescriptorProto
|
||||
// 1323 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x57, 0x5b, 0x6f, 0x1b, 0x45,
|
||||
0x1b, 0xce, 0x3a, 0x4e, 0x9a, 0x6f, 0x9c, 0x26, 0xfd, 0xa6, 0x55, 0xeb, 0xa6, 0xd4, 0x8e, 0x56,
|
||||
0x08, 0xb5, 0x08, 0x76, 0xa9, 0x29, 0x88, 0x0a, 0x01, 0x8a, 0xcd, 0xa1, 0x15, 0x71, 0x0f, 0xd3,
|
||||
0x50, 0x21, 0x40, 0x82, 0xc9, 0x7a, 0xea, 0x0c, 0xf1, 0x1e, 0xb4, 0x33, 0xb6, 0x48, 0xa5, 0x4a,
|
||||
0xdc, 0x70, 0x87, 0x04, 0x37, 0xfc, 0x04, 0x24, 0xfe, 0x01, 0xd7, 0x20, 0x21, 0xf5, 0xb2, 0x97,
|
||||
0xe5, 0xc6, 0xa2, 0xee, 0x1d, 0x3f, 0x21, 0x12, 0x07, 0xcd, 0x61, 0x4f, 0x5e, 0x6f, 0x1a, 0x87,
|
||||
0xb4, 0x82, 0x3b, 0x7b, 0xe6, 0x7d, 0x9f, 0xe7, 0x3d, 0x3c, 0xf3, 0xce, 0x2c, 0x78, 0x6b, 0xfb,
|
||||
0x35, 0x66, 0x51, 0xdf, 0xde, 0xee, 0x6f, 0x92, 0xd0, 0x23, 0x9c, 0x30, 0x3b, 0xd8, 0xee, 0xda,
|
||||
0x38, 0xa0, 0xcc, 0xc6, 0x7d, 0xee, 0x33, 0x07, 0xf7, 0xa8, 0xd7, 0xb5, 0x07, 0x0d, 0xdc, 0x0b,
|
||||
0xb6, 0xf0, 0x05, 0xbb, 0x4b, 0x3c, 0x12, 0x62, 0x4e, 0x3a, 0x56, 0x10, 0xfa, 0xdc, 0x87, 0xb6,
|
||||
0x02, 0xb0, 0x12, 0x00, 0x2b, 0xd8, 0xee, 0x5a, 0x02, 0xc0, 0x4a, 0x01, 0x58, 0x11, 0xc0, 0xca,
|
||||
0x8b, 0x5d, 0xca, 0xb7, 0xfa, 0x9b, 0x96, 0xe3, 0xbb, 0x76, 0xd7, 0xef, 0xfa, 0xb6, 0xc4, 0xd9,
|
||||
0xec, 0xdf, 0x96, 0xff, 0xe4, 0x1f, 0xf9, 0x4b, 0xe1, 0xaf, 0x5c, 0xd4, 0x01, 0xe2, 0x80, 0xba,
|
||||
0xd8, 0xd9, 0xa2, 0x1e, 0x09, 0x77, 0xa2, 0x10, 0xed, 0x90, 0x30, 0xbf, 0x1f, 0x3a, 0x64, 0x3c,
|
||||
0xaa, 0x3d, 0xbd, 0x98, 0xed, 0x12, 0x8e, 0xed, 0x41, 0x2e, 0x97, 0x15, 0xbb, 0xc8, 0x2b, 0xec,
|
||||
0x7b, 0x9c, 0xba, 0x79, 0x9a, 0x57, 0x1f, 0xe7, 0xc0, 0x9c, 0x2d, 0xe2, 0xe2, 0x9c, 0xdf, 0xcb,
|
||||
0x45, 0x7e, 0x7d, 0x4e, 0x7b, 0x36, 0xf5, 0x38, 0xe3, 0x61, 0xce, 0xe9, 0x85, 0xc2, 0x56, 0x4d,
|
||||
0xca, 0xe5, 0xd2, 0x7e, 0x1b, 0x9b, 0x73, 0x35, 0xbf, 0x33, 0xc0, 0x99, 0x56, 0xe8, 0x33, 0x76,
|
||||
0x8b, 0x84, 0x8c, 0xfa, 0xde, 0xb5, 0xcd, 0xcf, 0x89, 0xc3, 0x11, 0xb9, 0x4d, 0x42, 0xe2, 0x39,
|
||||
0x04, 0xae, 0x82, 0xf2, 0x36, 0xf5, 0x3a, 0x55, 0x63, 0xd5, 0x38, 0xf7, 0xbf, 0xe6, 0xe2, 0xbd,
|
||||
0x61, 0x7d, 0x66, 0x34, 0xac, 0x97, 0xdf, 0xa7, 0x5e, 0x07, 0xc9, 0x1d, 0x61, 0xe1, 0x61, 0x97,
|
||||
0x54, 0x4b, 0x59, 0x8b, 0xab, 0xd8, 0x25, 0x48, 0xee, 0xc0, 0x06, 0x00, 0x38, 0xa0, 0x9a, 0xa0,
|
||||
0x3a, 0x2b, 0xed, 0xa0, 0xb6, 0x03, 0x6b, 0xd7, 0xaf, 0xe8, 0x1d, 0x94, 0xb2, 0x32, 0x1f, 0x95,
|
||||
0xc0, 0xa9, 0xcb, 0x7e, 0x48, 0xef, 0xf8, 0x1e, 0xc7, 0xbd, 0xeb, 0x7e, 0x67, 0x4d, 0xe7, 0x41,
|
||||
0x42, 0xf8, 0x19, 0x58, 0x10, 0x5d, 0xed, 0x60, 0x8e, 0x65, 0x5c, 0x95, 0xc6, 0x4b, 0x96, 0x56,
|
||||
0x66, 0xba, 0xc8, 0x89, 0x36, 0x85, 0xb5, 0x35, 0xb8, 0x60, 0xa9, 0xe4, 0xda, 0x84, 0xe3, 0x84,
|
||||
0x3f, 0x59, 0x43, 0x31, 0x2a, 0xf4, 0x40, 0x99, 0x05, 0xc4, 0x91, 0x39, 0x55, 0x1a, 0xeb, 0xd6,
|
||||
0x94, 0xba, 0xb7, 0x0a, 0x22, 0xbf, 0x19, 0x10, 0x27, 0xa9, 0x90, 0xf8, 0x87, 0x24, 0x0f, 0x1c,
|
||||
0x80, 0x79, 0xc6, 0x31, 0xef, 0x33, 0x59, 0x9d, 0x4a, 0xe3, 0xea, 0xa1, 0x31, 0x4a, 0xd4, 0xe6,
|
||||
0x92, 0xe6, 0x9c, 0x57, 0xff, 0x91, 0x66, 0x33, 0xbf, 0x99, 0x05, 0xab, 0x05, 0x9e, 0x2d, 0xdf,
|
||||
0xeb, 0x50, 0x4e, 0x7d, 0x0f, 0x5e, 0x06, 0x65, 0xbe, 0x13, 0x10, 0x2d, 0x81, 0x8b, 0x51, 0xf8,
|
||||
0x1b, 0x3b, 0x01, 0xd9, 0x1d, 0xd6, 0x9f, 0x7d, 0x9c, 0xbf, 0xb0, 0x43, 0x12, 0x01, 0xde, 0x8a,
|
||||
0xd3, 0x54, 0x62, 0x79, 0x33, 0x1b, 0xd6, 0xee, 0xb0, 0xbe, 0xa7, 0xee, 0xad, 0x18, 0x33, 0x9b,
|
||||
0x06, 0x1c, 0x00, 0xd8, 0xc3, 0x8c, 0x6f, 0x84, 0xd8, 0x63, 0x8a, 0x93, 0xba, 0x44, 0x97, 0xf2,
|
||||
0xf9, 0xfd, 0x49, 0x43, 0x78, 0x34, 0x57, 0x74, 0x3c, 0x70, 0x3d, 0x87, 0x86, 0x26, 0x30, 0xc0,
|
||||
0xe7, 0xc0, 0x7c, 0x48, 0x30, 0xf3, 0xbd, 0x6a, 0x59, 0xe6, 0x13, 0x97, 0x19, 0xc9, 0x55, 0xa4,
|
||||
0x77, 0xe1, 0x79, 0x70, 0xc4, 0x25, 0x8c, 0xe1, 0x2e, 0xa9, 0xce, 0x49, 0xc3, 0x65, 0x6d, 0x78,
|
||||
0xa4, 0xad, 0x96, 0x51, 0xb4, 0x6f, 0xfe, 0x6e, 0x80, 0x33, 0x05, 0x15, 0x5d, 0xa7, 0x8c, 0xc3,
|
||||
0x4f, 0x72, 0xda, 0xb7, 0xf6, 0x97, 0xa0, 0xf0, 0x96, 0xca, 0x3f, 0xa6, 0xb9, 0x17, 0xa2, 0x95,
|
||||
0x94, 0xee, 0x5d, 0x30, 0x47, 0x39, 0x71, 0x45, 0x7f, 0x66, 0xcf, 0x55, 0x1a, 0x97, 0x0f, 0x4b,
|
||||
0x86, 0xcd, 0xa3, 0x9a, 0x74, 0xee, 0x8a, 0x80, 0x47, 0x8a, 0xc5, 0xfc, 0xb3, 0x54, 0x98, 0xac,
|
||||
0x38, 0x1c, 0xf0, 0x6b, 0x03, 0x2c, 0xc9, 0xbf, 0x1b, 0x38, 0xec, 0x12, 0x31, 0x95, 0x74, 0xce,
|
||||
0xd3, 0x9f, 0xc8, 0x3d, 0x66, 0x5c, 0xf3, 0xa4, 0x0e, 0x6e, 0xe9, 0x66, 0x86, 0x0b, 0x8d, 0x71,
|
||||
0xc3, 0x0b, 0xa0, 0xe2, 0x52, 0x0f, 0x91, 0xa0, 0x47, 0x1d, 0xac, 0x34, 0x3c, 0xd7, 0x5c, 0x1e,
|
||||
0x0d, 0xeb, 0x95, 0x76, 0xb2, 0x8c, 0xd2, 0x36, 0xf0, 0x15, 0x50, 0x71, 0xf1, 0x17, 0xb1, 0xcb,
|
||||
0xac, 0x74, 0x39, 0xae, 0xf9, 0x2a, 0xed, 0x64, 0x0b, 0xa5, 0xed, 0xe0, 0x6d, 0x21, 0x18, 0x1e,
|
||||
0x52, 0x87, 0x55, 0xcb, 0xb2, 0x13, 0xaf, 0x4f, 0x9d, 0x70, 0x5b, 0xfa, 0xcb, 0x89, 0x93, 0x52,
|
||||
0x9b, 0xc4, 0x44, 0x11, 0xb8, 0xf9, 0x6b, 0x19, 0x9c, 0xdd, 0x73, 0x72, 0xc0, 0x77, 0x01, 0xf4,
|
||||
0x37, 0x19, 0x09, 0x07, 0xa4, 0xf3, 0x9e, 0xba, 0x3a, 0xc4, 0x0c, 0x17, 0x5d, 0x98, 0x6d, 0x9e,
|
||||
0x14, 0x47, 0xe5, 0x5a, 0x6e, 0x17, 0x4d, 0xf0, 0x80, 0x0e, 0x38, 0x2a, 0x0e, 0x90, 0xaa, 0x30,
|
||||
0xd5, 0xd7, 0xc5, 0x74, 0xa7, 0xf3, 0xff, 0xa3, 0x61, 0xfd, 0xe8, 0x7a, 0x1a, 0x04, 0x65, 0x31,
|
||||
0xe1, 0x1a, 0x58, 0x76, 0xfa, 0x61, 0x48, 0x3c, 0x3e, 0x56, 0xf1, 0x53, 0xba, 0x02, 0xcb, 0xad,
|
||||
0xec, 0x36, 0x1a, 0xb7, 0x17, 0x10, 0x1d, 0xc2, 0x68, 0x48, 0x3a, 0x31, 0x44, 0x39, 0x0b, 0xf1,
|
||||
0x76, 0x76, 0x1b, 0x8d, 0xdb, 0xc3, 0xbb, 0x60, 0x49, 0xa3, 0xea, 0x7a, 0x57, 0xe7, 0x64, 0x0f,
|
||||
0xdf, 0x38, 0x68, 0x0f, 0xd5, 0x0c, 0x8f, 0x55, 0xda, 0xca, 0x80, 0xa3, 0x31, 0x32, 0xf8, 0x95,
|
||||
0x01, 0x80, 0x13, 0x0d, 0x4a, 0x56, 0x9d, 0x97, 0xdc, 0x37, 0x0e, 0xeb, 0x24, 0xc7, 0x23, 0x38,
|
||||
0xb9, 0x41, 0xe3, 0x25, 0x86, 0x52, 0xc4, 0xe6, 0x1f, 0x25, 0x00, 0x12, 0x11, 0xc2, 0x8b, 0x99,
|
||||
0x5b, 0x64, 0x75, 0xec, 0x16, 0x39, 0xa6, 0x2d, 0xe5, 0x0b, 0x2f, 0x75, 0x63, 0x74, 0xc1, 0xbc,
|
||||
0x2f, 0x4f, 0xab, 0xd6, 0x4b, 0x6b, 0xea, 0x3c, 0xe2, 0xfb, 0x3d, 0x86, 0x6f, 0x02, 0x31, 0xa2,
|
||||
0xf5, 0x10, 0xd0, 0xf0, 0xf0, 0x53, 0x50, 0x0e, 0xfc, 0x4e, 0x74, 0xff, 0xae, 0x4d, 0x4d, 0x73,
|
||||
0xdd, 0xef, 0xb0, 0x0c, 0xc9, 0x82, 0xc8, 0x4e, 0xac, 0x22, 0x09, 0x0c, 0x7d, 0xb0, 0x10, 0xbd,
|
||||
0x60, 0xa5, 0xa2, 0x2a, 0x8d, 0x77, 0xa6, 0x26, 0x41, 0x1a, 0x20, 0x43, 0xb4, 0x28, 0x66, 0x79,
|
||||
0xb4, 0x83, 0x62, 0x12, 0xf3, 0xaf, 0x12, 0x58, 0x4c, 0x0b, 0xe8, 0xdf, 0xd1, 0x01, 0xa5, 0xe5,
|
||||
0x27, 0xdc, 0x01, 0x45, 0xf2, 0x14, 0x3a, 0xa0, 0x88, 0x8a, 0x3a, 0xf0, 0x7d, 0x09, 0xc0, 0xbc,
|
||||
0xfc, 0x20, 0x07, 0xf3, 0x5c, 0xde, 0x29, 0x4f, 0xe4, 0x32, 0x8b, 0xdf, 0x20, 0xfa, 0xde, 0xd2,
|
||||
0x5c, 0xe2, 0x11, 0xae, 0xa6, 0xfe, 0xd5, 0xe4, 0xb1, 0x1e, 0x1f, 0xe1, 0x76, 0xbc, 0x83, 0x52,
|
||||
0x56, 0x90, 0x80, 0x8a, 0xf2, 0xbe, 0x85, 0x7b, 0xfd, 0xe8, 0x41, 0xb5, 0xe7, 0x7b, 0xc3, 0x8a,
|
||||
0x92, 0xb7, 0x6e, 0xf4, 0xb1, 0xc7, 0x29, 0xdf, 0x49, 0x6e, 0xbb, 0x8d, 0x04, 0x0a, 0xa5, 0x71,
|
||||
0xcd, 0x1f, 0xc6, 0xeb, 0xa4, 0xf4, 0xfa, 0xdf, 0xa9, 0xd3, 0x16, 0x58, 0xd4, 0x43, 0xf8, 0x9f,
|
||||
0x14, 0xea, 0x84, 0x66, 0x59, 0x6c, 0xa5, 0xb0, 0x50, 0x06, 0xd9, 0xfc, 0xd9, 0x00, 0xc7, 0xc6,
|
||||
0x47, 0xcd, 0x58, 0xc8, 0xc6, 0xbe, 0x42, 0xbe, 0x03, 0xa0, 0x4a, 0x78, 0x6d, 0x40, 0x42, 0xdc,
|
||||
0x25, 0x2a, 0xf0, 0xd2, 0x81, 0x02, 0x8f, 0x9f, 0xcd, 0x1b, 0x39, 0x44, 0x34, 0x81, 0xc5, 0xfc,
|
||||
0x25, 0x9b, 0x84, 0xea, 0xf6, 0x41, 0x92, 0xb8, 0x0b, 0x8e, 0xeb, 0xea, 0x1c, 0x42, 0x16, 0x67,
|
||||
0x34, 0xd9, 0xf1, 0x56, 0x1e, 0x12, 0x4d, 0xe2, 0x31, 0x7f, 0x2c, 0x81, 0x13, 0x93, 0x46, 0x32,
|
||||
0x6c, 0xeb, 0x4f, 0x62, 0x95, 0xc5, 0xa5, 0xf4, 0x27, 0xf1, 0xee, 0xb0, 0x7e, 0x7e, 0xcf, 0x6f,
|
||||
0x9c, 0x08, 0x30, 0xf5, 0xfd, 0xfc, 0x21, 0xa8, 0x66, 0xaa, 0xf8, 0x01, 0xa7, 0x3d, 0x7a, 0x47,
|
||||
0xbd, 0xc4, 0xd4, 0x23, 0xf4, 0x99, 0xd1, 0xb0, 0x5e, 0xdd, 0x28, 0xb0, 0x41, 0x85, 0xde, 0xe2,
|
||||
0xc3, 0x69, 0x82, 0x0a, 0x0e, 0x26, 0xdf, 0x93, 0x53, 0x28, 0xe0, 0xa7, 0x7c, 0xe5, 0x94, 0x0a,
|
||||
0x0e, 0xb9, 0x72, 0x1f, 0x83, 0xd3, 0xd9, 0xc6, 0xe5, 0x4b, 0x77, 0x76, 0x34, 0xac, 0x9f, 0x6e,
|
||||
0x15, 0x19, 0xa1, 0x62, 0xff, 0x22, 0xf5, 0xcd, 0x3e, 0x1d, 0xf5, 0x35, 0xad, 0x7b, 0x0f, 0x6b,
|
||||
0x33, 0xf7, 0x1f, 0xd6, 0x66, 0x1e, 0x3c, 0xac, 0xcd, 0x7c, 0x39, 0xaa, 0x19, 0xf7, 0x46, 0x35,
|
||||
0xe3, 0xfe, 0xa8, 0x66, 0x3c, 0x18, 0xd5, 0x8c, 0xdf, 0x46, 0x35, 0xe3, 0xdb, 0x47, 0xb5, 0x99,
|
||||
0x8f, 0x16, 0xa2, 0x61, 0xf8, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4c, 0xa9, 0x91, 0xe9, 0xfe,
|
||||
0x13, 0x00, 0x00,
|
||||
0x14, 0xce, 0x3a, 0x4e, 0x1a, 0xc6, 0x69, 0x52, 0xa6, 0x55, 0xeb, 0xa6, 0xd4, 0x8e, 0x56, 0x08,
|
||||
0xb5, 0x08, 0x76, 0xa9, 0x29, 0x08, 0x84, 0x00, 0xc5, 0xe6, 0xd2, 0x8a, 0xb8, 0x97, 0x69, 0xa8,
|
||||
0x10, 0x20, 0xc1, 0x64, 0x3d, 0x75, 0x86, 0x78, 0x2f, 0xda, 0x19, 0x5b, 0xa4, 0x52, 0x25, 0x5e,
|
||||
0x78, 0x43, 0x82, 0x17, 0x7e, 0x02, 0x12, 0xff, 0x80, 0x67, 0x90, 0x90, 0xfa, 0xd8, 0xc7, 0xf2,
|
||||
0x62, 0x51, 0xf7, 0x8d, 0x9f, 0x50, 0x89, 0x8b, 0xe6, 0xb2, 0x37, 0xaf, 0xd7, 0xad, 0x43, 0x5a,
|
||||
0xc1, 0x9b, 0x3d, 0x73, 0xce, 0xf7, 0x9d, 0xcb, 0x37, 0x67, 0x66, 0xc1, 0xdb, 0xbb, 0xaf, 0x31,
|
||||
0x8b, 0xfa, 0xf6, 0x6e, 0x7f, 0x9b, 0x84, 0x1e, 0xe1, 0x84, 0xd9, 0xc1, 0x6e, 0xd7, 0xc6, 0x01,
|
||||
0x65, 0x36, 0xee, 0x73, 0x9f, 0x39, 0xb8, 0x47, 0xbd, 0xae, 0x3d, 0x68, 0xe0, 0x5e, 0xb0, 0x83,
|
||||
0xcf, 0xd9, 0x5d, 0xe2, 0x91, 0x10, 0x73, 0xd2, 0xb1, 0x82, 0xd0, 0xe7, 0x3e, 0xb4, 0x15, 0x80,
|
||||
0x95, 0x00, 0x58, 0xc1, 0x6e, 0xd7, 0x12, 0x00, 0x56, 0x0a, 0xc0, 0x8a, 0x00, 0xd6, 0x5e, 0xec,
|
||||
0x52, 0xbe, 0xd3, 0xdf, 0xb6, 0x1c, 0xdf, 0xb5, 0xbb, 0x7e, 0xd7, 0xb7, 0x25, 0xce, 0x76, 0xff,
|
||||
0x86, 0xfc, 0x27, 0xff, 0xc8, 0x5f, 0x0a, 0x7f, 0xed, 0xbc, 0x0e, 0x10, 0x07, 0xd4, 0xc5, 0xce,
|
||||
0x0e, 0xf5, 0x48, 0xb8, 0x17, 0x85, 0x68, 0x87, 0x84, 0xf9, 0xfd, 0xd0, 0x21, 0xe3, 0x51, 0x4d,
|
||||
0xf5, 0x62, 0xb6, 0x4b, 0x38, 0xb6, 0x07, 0xb9, 0x5c, 0xd6, 0xec, 0x22, 0xaf, 0xb0, 0xef, 0x71,
|
||||
0xea, 0xe6, 0x69, 0x5e, 0x7d, 0x98, 0x03, 0x73, 0x76, 0x88, 0x8b, 0x73, 0x7e, 0x2f, 0x17, 0xf9,
|
||||
0xf5, 0x39, 0xed, 0xd9, 0xd4, 0xe3, 0x8c, 0x87, 0x39, 0xa7, 0x17, 0x0a, 0x5b, 0x35, 0x21, 0x17,
|
||||
0xf3, 0x7b, 0x03, 0x9c, 0x6a, 0x85, 0x3e, 0x63, 0xd7, 0x49, 0xc8, 0xa8, 0xef, 0x5d, 0xde, 0xfe,
|
||||
0x82, 0x38, 0x1c, 0x91, 0x1b, 0x24, 0x24, 0x9e, 0x43, 0xe0, 0x3a, 0x28, 0xef, 0x52, 0xaf, 0x53,
|
||||
0x35, 0xd6, 0x8d, 0x33, 0x4f, 0x35, 0x97, 0x6f, 0x0f, 0xeb, 0x73, 0xa3, 0x61, 0xbd, 0xfc, 0x01,
|
||||
0xf5, 0x3a, 0x48, 0xee, 0x08, 0x0b, 0x0f, 0xbb, 0xa4, 0x5a, 0xca, 0x5a, 0x5c, 0xc2, 0x2e, 0x41,
|
||||
0x72, 0x07, 0x36, 0x00, 0xc0, 0x01, 0xd5, 0x04, 0xd5, 0x79, 0x69, 0x07, 0xb5, 0x1d, 0xd8, 0xb8,
|
||||
0x72, 0x51, 0xef, 0xa0, 0x94, 0x95, 0x79, 0xbf, 0x04, 0x4e, 0x5c, 0xf0, 0x43, 0x7a, 0xd3, 0xf7,
|
||||
0x38, 0xee, 0x5d, 0xf1, 0x3b, 0x1b, 0x5a, 0x24, 0x24, 0x84, 0x9f, 0x83, 0x25, 0xd1, 0x9a, 0x0e,
|
||||
0xe6, 0x58, 0xc6, 0x55, 0x69, 0xbc, 0x64, 0x69, 0x79, 0xa5, 0x2b, 0x95, 0x08, 0x4c, 0x58, 0x5b,
|
||||
0x83, 0x73, 0x96, 0x4a, 0xae, 0x4d, 0x38, 0x4e, 0xf8, 0x93, 0x35, 0x14, 0xa3, 0x42, 0x0f, 0x94,
|
||||
0x59, 0x40, 0x1c, 0x99, 0x53, 0xa5, 0xb1, 0x69, 0xcd, 0x28, 0x5e, 0xab, 0x20, 0xf2, 0x6b, 0x01,
|
||||
0x71, 0x92, 0x0a, 0x89, 0x7f, 0x48, 0xf2, 0xc0, 0x01, 0x58, 0x64, 0x1c, 0xf3, 0x3e, 0x93, 0xd5,
|
||||
0xa9, 0x34, 0x2e, 0x1d, 0x18, 0xa3, 0x44, 0x6d, 0xae, 0x68, 0xce, 0x45, 0xf5, 0x1f, 0x69, 0x36,
|
||||
0xf3, 0xdb, 0x79, 0xb0, 0x5e, 0xe0, 0xd9, 0xf2, 0xbd, 0x0e, 0xe5, 0xd4, 0xf7, 0xe0, 0x05, 0x50,
|
||||
0xe6, 0x7b, 0x01, 0xd1, 0x12, 0x38, 0x1f, 0x85, 0xbf, 0xb5, 0x17, 0x90, 0x07, 0xc3, 0xfa, 0xb3,
|
||||
0x0f, 0xf3, 0x17, 0x76, 0x48, 0x22, 0xc0, 0xeb, 0x71, 0x9a, 0x4a, 0x2c, 0x6f, 0x65, 0xc3, 0x7a,
|
||||
0x30, 0xac, 0x4f, 0x15, 0xaf, 0x15, 0x63, 0x66, 0xd3, 0x80, 0x03, 0x00, 0x7b, 0x98, 0xf1, 0xad,
|
||||
0x10, 0x7b, 0x4c, 0x71, 0x52, 0x97, 0xe8, 0x52, 0x3e, 0xff, 0x68, 0xd2, 0x10, 0x1e, 0xcd, 0x35,
|
||||
0x1d, 0x0f, 0xdc, 0xcc, 0xa1, 0xa1, 0x09, 0x0c, 0xf0, 0x39, 0xb0, 0x18, 0x12, 0xcc, 0x7c, 0xaf,
|
||||
0x5a, 0x96, 0xf9, 0xc4, 0x65, 0x46, 0x72, 0x15, 0xe9, 0x5d, 0x78, 0x16, 0x1c, 0x72, 0x09, 0x63,
|
||||
0xb8, 0x4b, 0xaa, 0x0b, 0xd2, 0x70, 0x55, 0x1b, 0x1e, 0x6a, 0xab, 0x65, 0x14, 0xed, 0x9b, 0x7f,
|
||||
0x18, 0xe0, 0x54, 0x41, 0x45, 0x37, 0x29, 0xe3, 0xf0, 0xd3, 0x9c, 0xf6, 0xad, 0x47, 0x4b, 0x50,
|
||||
0x78, 0x4b, 0xe5, 0x1f, 0xd1, 0xdc, 0x4b, 0xd1, 0x4a, 0x4a, 0xf7, 0x2e, 0x58, 0xa0, 0x9c, 0xb8,
|
||||
0xa2, 0x3f, 0xf3, 0x67, 0x2a, 0x8d, 0x0b, 0x07, 0x25, 0xc3, 0xe6, 0x61, 0x4d, 0xba, 0x70, 0x51,
|
||||
0xc0, 0x23, 0xc5, 0x62, 0xfe, 0x55, 0x2a, 0x4c, 0x56, 0x1c, 0x0e, 0xf8, 0x8d, 0x01, 0x56, 0xe4,
|
||||
0xdf, 0x2d, 0x1c, 0x76, 0x89, 0x98, 0x4a, 0x3a, 0xe7, 0xd9, 0x4f, 0xe4, 0x94, 0x19, 0xd7, 0x3c,
|
||||
0xae, 0x83, 0x5b, 0xb9, 0x96, 0xe1, 0x42, 0x63, 0xdc, 0xf0, 0x1c, 0xa8, 0xb8, 0xd4, 0x43, 0x24,
|
||||
0xe8, 0x51, 0x07, 0x2b, 0x0d, 0x2f, 0x34, 0x57, 0x47, 0xc3, 0x7a, 0xa5, 0x9d, 0x2c, 0xa3, 0xb4,
|
||||
0x0d, 0x7c, 0x05, 0x54, 0x5c, 0xfc, 0x65, 0xec, 0x32, 0x2f, 0x5d, 0x8e, 0x6a, 0xbe, 0x4a, 0x3b,
|
||||
0xd9, 0x42, 0x69, 0x3b, 0x78, 0x43, 0x08, 0x86, 0x87, 0xd4, 0x61, 0xd5, 0xb2, 0xec, 0xc4, 0x1b,
|
||||
0x33, 0x27, 0xdc, 0x96, 0xfe, 0x72, 0xe2, 0xa4, 0xd4, 0x26, 0x31, 0x51, 0x04, 0x6e, 0xfe, 0x56,
|
||||
0x06, 0xa7, 0xa7, 0x4e, 0x0e, 0xf8, 0x1e, 0x80, 0xfe, 0x36, 0x23, 0xe1, 0x80, 0x74, 0xde, 0x57,
|
||||
0x57, 0x87, 0x98, 0xe1, 0xa2, 0x0b, 0xf3, 0xcd, 0xe3, 0xe2, 0xa8, 0x5c, 0xce, 0xed, 0xa2, 0x09,
|
||||
0x1e, 0xd0, 0x01, 0x87, 0xc5, 0x01, 0x52, 0x15, 0xa6, 0xfa, 0xba, 0x98, 0xed, 0x74, 0x3e, 0x3d,
|
||||
0x1a, 0xd6, 0x0f, 0x6f, 0xa6, 0x41, 0x50, 0x16, 0x13, 0x6e, 0x80, 0x55, 0xa7, 0x1f, 0x86, 0xc4,
|
||||
0xe3, 0x63, 0x15, 0x3f, 0xa1, 0x2b, 0xb0, 0xda, 0xca, 0x6e, 0xa3, 0x71, 0x7b, 0x01, 0xd1, 0x21,
|
||||
0x8c, 0x86, 0xa4, 0x13, 0x43, 0x94, 0xb3, 0x10, 0xef, 0x64, 0xb7, 0xd1, 0xb8, 0x3d, 0xbc, 0x05,
|
||||
0x56, 0x34, 0xaa, 0xae, 0x77, 0x75, 0x41, 0xf6, 0xf0, 0xcd, 0xfd, 0xf6, 0x50, 0xcd, 0xf0, 0x58,
|
||||
0xa5, 0xad, 0x0c, 0x38, 0x1a, 0x23, 0x83, 0x5f, 0x1b, 0x00, 0x38, 0xd1, 0xa0, 0x64, 0xd5, 0x45,
|
||||
0xc9, 0x7d, 0xf5, 0xa0, 0x4e, 0x72, 0x3c, 0x82, 0x93, 0x1b, 0x34, 0x5e, 0x62, 0x28, 0x45, 0x6c,
|
||||
0xfe, 0x59, 0x02, 0x20, 0x11, 0x21, 0x3c, 0x9f, 0xb9, 0x45, 0xd6, 0xc7, 0x6e, 0x91, 0x23, 0xda,
|
||||
0x52, 0x3e, 0xd3, 0x52, 0x37, 0x46, 0x17, 0x2c, 0xfa, 0xf2, 0xb4, 0x6a, 0xbd, 0xb4, 0x66, 0xce,
|
||||
0x23, 0xbe, 0xdf, 0x63, 0xf8, 0x26, 0x10, 0x23, 0x5a, 0x0f, 0x01, 0x0d, 0x0f, 0x3f, 0x03, 0xe5,
|
||||
0xc0, 0xef, 0x44, 0xf7, 0xef, 0xc6, 0xcc, 0x34, 0x57, 0xfc, 0x0e, 0xcb, 0x90, 0x2c, 0x89, 0xec,
|
||||
0xc4, 0x2a, 0x92, 0xc0, 0xd0, 0x07, 0x4b, 0xd1, 0x33, 0x54, 0x2a, 0xaa, 0xd2, 0x78, 0x77, 0x66,
|
||||
0x12, 0xa4, 0x01, 0x32, 0x44, 0xcb, 0x62, 0x96, 0x47, 0x3b, 0x28, 0x26, 0x31, 0xff, 0x2e, 0x81,
|
||||
0xe5, 0xb4, 0x80, 0xfe, 0x1b, 0x1d, 0x50, 0x5a, 0x7e, 0xcc, 0x1d, 0x50, 0x24, 0x4f, 0xa0, 0x03,
|
||||
0x8a, 0xa8, 0xa8, 0x03, 0x3f, 0x94, 0x00, 0xcc, 0xcb, 0x0f, 0x72, 0xb0, 0xc8, 0xe5, 0x9d, 0xf2,
|
||||
0x58, 0x2e, 0xb3, 0xf8, 0x0d, 0xa2, 0xef, 0x2d, 0xcd, 0x25, 0x1e, 0xe1, 0x6a, 0xea, 0x5f, 0x4a,
|
||||
0x1e, 0xeb, 0xf1, 0x11, 0x6e, 0xc7, 0x3b, 0x28, 0x65, 0x05, 0x09, 0xa8, 0x28, 0xef, 0xeb, 0xb8,
|
||||
0xd7, 0x8f, 0x1e, 0x54, 0x53, 0xdf, 0x1b, 0x56, 0x94, 0xbc, 0x75, 0xb5, 0x8f, 0x3d, 0x4e, 0xf9,
|
||||
0x5e, 0x72, 0xdb, 0x6d, 0x25, 0x50, 0x28, 0x8d, 0x6b, 0xfe, 0x38, 0x5e, 0x27, 0xa5, 0xd7, 0xff,
|
||||
0x4f, 0x9d, 0x76, 0xc0, 0xb2, 0x1e, 0xc2, 0xff, 0xa6, 0x50, 0xc7, 0x34, 0xcb, 0x72, 0x2b, 0x85,
|
||||
0x85, 0x32, 0xc8, 0xe6, 0x2f, 0x06, 0x38, 0x32, 0x3e, 0x6a, 0xc6, 0x42, 0x36, 0x1e, 0x29, 0xe4,
|
||||
0x9b, 0x00, 0xaa, 0x84, 0x37, 0x06, 0x24, 0xc4, 0x5d, 0xa2, 0x02, 0x2f, 0xed, 0x2b, 0xf0, 0xf8,
|
||||
0xd9, 0xbc, 0x95, 0x43, 0x44, 0x13, 0x58, 0xcc, 0x5f, 0xb3, 0x49, 0xa8, 0x6e, 0xef, 0x27, 0x89,
|
||||
0x5b, 0xe0, 0xa8, 0xae, 0xce, 0x01, 0x64, 0x71, 0x4a, 0x93, 0x1d, 0x6d, 0xe5, 0x21, 0xd1, 0x24,
|
||||
0x1e, 0xf3, 0xa7, 0x12, 0x38, 0x36, 0x69, 0x24, 0xc3, 0xb6, 0xfe, 0x24, 0x56, 0x59, 0xbc, 0x9e,
|
||||
0xfe, 0x24, 0x7e, 0x30, 0xac, 0x9f, 0x9d, 0xfa, 0x8d, 0x13, 0x01, 0xa6, 0xbe, 0x9f, 0x3f, 0x02,
|
||||
0xd5, 0x4c, 0x15, 0x3f, 0xe4, 0xb4, 0x47, 0x6f, 0xaa, 0x97, 0x98, 0x7a, 0x84, 0x3e, 0x33, 0x1a,
|
||||
0xd6, 0xab, 0x5b, 0x05, 0x36, 0xa8, 0xd0, 0x5b, 0x7c, 0x38, 0x4d, 0x50, 0xc1, 0xfe, 0xe4, 0x7b,
|
||||
0x7c, 0x06, 0x05, 0xfc, 0x9c, 0xaf, 0x9c, 0x52, 0xc1, 0x01, 0x57, 0xee, 0x13, 0x70, 0x32, 0xdb,
|
||||
0xb8, 0x7c, 0xe9, 0x4e, 0x8f, 0x86, 0xf5, 0x93, 0xad, 0x22, 0x23, 0x54, 0xec, 0x5f, 0xa4, 0xbe,
|
||||
0xf9, 0x27, 0xa3, 0xbe, 0xa6, 0x75, 0xfb, 0x5e, 0x6d, 0xee, 0xce, 0xbd, 0xda, 0xdc, 0xdd, 0x7b,
|
||||
0xb5, 0xb9, 0xaf, 0x46, 0x35, 0xe3, 0xf6, 0xa8, 0x66, 0xdc, 0x19, 0xd5, 0x8c, 0xbb, 0xa3, 0x9a,
|
||||
0xf1, 0xfb, 0xa8, 0x66, 0x7c, 0x77, 0xbf, 0x36, 0xf7, 0xf1, 0x52, 0x34, 0x0c, 0xff, 0x09, 0x00,
|
||||
0x00, 0xff, 0xff, 0x88, 0x5a, 0x1f, 0xc3, 0xc3, 0x13, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import "k8s.io/apimachinery/pkg/runtime/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
|
||||
import "k8s.io/kubernetes/pkg/api/v1/generated.proto";
|
||||
import "k8s.io/kubernetes/pkg/apis/autoscaling/v1/generated.proto";
|
||||
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "v2alpha1";
|
||||
|
||||
@@ -84,6 +84,15 @@ func FileExists(filename string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func FileOrSymlinkExists(filename string) (bool, error) {
|
||||
if _, err := os.Lstat(filename); os.IsNotExist(err) {
|
||||
return false, nil
|
||||
} else if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ReadDirNoStat returns a string of files/directories contained
|
||||
// in dirname without calling lstat on them.
|
||||
func ReadDirNoStat(dirname string) ([]string, error) {
|
||||
|
||||
@@ -39,8 +39,8 @@ var (
|
||||
// them irrelevant. (Next we'll take it out, which may muck with
|
||||
// scripts consuming the kubectl version output - but most of
|
||||
// these should be looking at gitVersion already anyways.)
|
||||
gitMajor string = "" // major version, always numeric
|
||||
gitMinor string = "" // minor version, numeric possibly followed by "+"
|
||||
gitMajor string = "1" // major version, always numeric
|
||||
gitMinor string = "7" // minor version, numeric possibly followed by "+"
|
||||
|
||||
// semantic version, derived by build scripts (see
|
||||
// https://github.com/kubernetes/kubernetes/blob/master/docs/design/versioning.md
|
||||
@@ -51,7 +51,7 @@ var (
|
||||
// semantic version is a git hash, but the version itself is no
|
||||
// longer the direct output of "git describe", but a slight
|
||||
// translation to be semver compliant.
|
||||
gitVersion string = "v0.0.0-master+$Format:%h$"
|
||||
gitVersion string = "v1.7.7+$Format:%h$"
|
||||
gitCommit string = "$Format:%H$" // sha1 from git, output of $(git rev-parse HEAD)
|
||||
gitTreeState string = "not a git tree" // state of git tree, either "clean" or "dirty"
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ go_test(
|
||||
srcs = ["azure_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library"],
|
||||
deps = ["//vendor/github.com/Azure/go-autorest/autorest/adal:go_default_library"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
@@ -22,6 +22,7 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor/github.com/Azure/go-autorest/autorest:go_default_library",
|
||||
"//vendor/github.com/Azure/go-autorest/autorest/adal:go_default_library",
|
||||
"//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
"github.com/Azure/go-autorest/autorest/azure"
|
||||
"github.com/golang/glog"
|
||||
|
||||
@@ -137,7 +138,7 @@ func (r *azureRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
type azureToken struct {
|
||||
token azure.Token
|
||||
token adal.Token
|
||||
clientID string
|
||||
tenantID string
|
||||
apiserverID string
|
||||
@@ -234,7 +235,7 @@ func (ts *azureTokenSource) retrieveTokenFromCfg() (*azureToken, error) {
|
||||
}
|
||||
|
||||
return &azureToken{
|
||||
token: azure.Token{
|
||||
token: adal.Token{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: expiresIn,
|
||||
@@ -268,15 +269,15 @@ func (ts *azureTokenSource) storeTokenInCfg(token *azureToken) error {
|
||||
}
|
||||
|
||||
func (ts *azureTokenSource) refreshToken(token *azureToken) (*azureToken, error) {
|
||||
oauthConfig, err := azure.PublicCloud.OAuthConfigForTenant(token.tenantID)
|
||||
oauthConfig, err := adal.NewOAuthConfig(azure.PublicCloud.ActiveDirectoryEndpoint, token.tenantID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("building the OAuth configuration for token refresh: %v", err)
|
||||
}
|
||||
|
||||
callback := func(t azure.Token) error {
|
||||
callback := func(t adal.Token) error {
|
||||
return nil
|
||||
}
|
||||
spt, err := azure.NewServicePrincipalTokenFromManualToken(
|
||||
spt, err := adal.NewServicePrincipalTokenFromManualToken(
|
||||
*oauthConfig,
|
||||
token.clientID,
|
||||
token.apiserverID,
|
||||
@@ -324,12 +325,12 @@ func newAzureTokenSourceDeviceCode(environment azure.Environment, clientID strin
|
||||
}
|
||||
|
||||
func (ts *azureTokenSourceDeviceCode) Token() (*azureToken, error) {
|
||||
oauthConfig, err := ts.environment.OAuthConfigForTenant(ts.tenantID)
|
||||
oauthConfig, err := adal.NewOAuthConfig(ts.environment.ActiveDirectoryEndpoint, ts.tenantID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("building the OAuth configuration for device code authentication: %v", err)
|
||||
}
|
||||
client := &autorest.Client{}
|
||||
deviceCode, err := azure.InitiateDeviceAuth(client, *oauthConfig, ts.clientID, ts.apiserverID)
|
||||
deviceCode, err := adal.InitiateDeviceAuth(client, *oauthConfig, ts.clientID, ts.apiserverID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initialing the device code authentication: %v", err)
|
||||
}
|
||||
@@ -339,7 +340,7 @@ func (ts *azureTokenSourceDeviceCode) Token() (*azureToken, error) {
|
||||
return nil, fmt.Errorf("prompting the device code message: %v", err)
|
||||
}
|
||||
|
||||
token, err := azure.WaitForUserCompletion(client, deviceCode)
|
||||
token, err := adal.WaitForUserCompletion(client, deviceCode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("waiting for device code authentication to complete: %v", err)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/azure"
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
)
|
||||
|
||||
func TestAzureTokenSource(t *testing.T) {
|
||||
@@ -120,8 +120,8 @@ func token2Cfg(token *azureToken) map[string]string {
|
||||
return cfg
|
||||
}
|
||||
|
||||
func newFackeAzureToken(accessToken string, expiresOn string) azure.Token {
|
||||
return azure.Token{
|
||||
func newFackeAzureToken(accessToken string, expiresOn string) adal.Token {
|
||||
return adal.Token{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: "fake",
|
||||
ExpiresIn: "3600",
|
||||
|
||||
@@ -49,6 +49,7 @@ func getEventKey(event *v1.Event) string {
|
||||
event.InvolvedObject.Kind,
|
||||
event.InvolvedObject.Namespace,
|
||||
event.InvolvedObject.Name,
|
||||
event.InvolvedObject.FieldPath,
|
||||
string(event.InvolvedObject.UID),
|
||||
event.InvolvedObject.APIVersion,
|
||||
event.Type,
|
||||
|
||||
@@ -35,6 +35,7 @@ func makeObjectReference(kind, name, namespace string) v1.ObjectReference {
|
||||
Namespace: namespace,
|
||||
UID: "C934D34AFB20242",
|
||||
APIVersion: "version",
|
||||
FieldPath: "spec.containers{mycontainer}",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +172,10 @@ func TestEventCorrelator(t *testing.T) {
|
||||
duplicateEvent := makeEvent("duplicate", "me again", makeObjectReference("Pod", "my-pod", "my-ns"))
|
||||
uniqueEvent := makeEvent("unique", "snowflake", makeObjectReference("Pod", "my-pod", "my-ns"))
|
||||
similarEvent := makeEvent("similar", "similar message", makeObjectReference("Pod", "my-pod", "my-ns"))
|
||||
similarEvent.InvolvedObject.FieldPath = "spec.containers{container1}"
|
||||
aggregateEvent := makeEvent(similarEvent.Reason, EventAggregatorByReasonMessageFunc(&similarEvent), similarEvent.InvolvedObject)
|
||||
similarButDifferentContainerEvent := similarEvent
|
||||
similarButDifferentContainerEvent.InvolvedObject.FieldPath = "spec.containers{container2}"
|
||||
scenario := map[string]struct {
|
||||
previousEvents []v1.Event
|
||||
newEvent v1.Event
|
||||
@@ -214,6 +218,12 @@ func TestEventCorrelator(t *testing.T) {
|
||||
expectedEvent: setCount(aggregateEvent, 2),
|
||||
intervalSeconds: 5,
|
||||
},
|
||||
"events-from-different-containers-do-not-aggregate": {
|
||||
previousEvents: makeEvents(1, similarButDifferentContainerEvent),
|
||||
newEvent: similarEvent,
|
||||
expectedEvent: setCount(similarEvent, 1),
|
||||
intervalSeconds: 5,
|
||||
},
|
||||
"similar-events-whose-interval-is-greater-than-aggregate-interval-do-not-aggregate": {
|
||||
previousEvents: makeSimilarEvents(defaultAggregateMaxEvents-1, similarEvent, similarEvent.Message),
|
||||
newEvent: similarEvent,
|
||||
|
||||
15
vendor/cloud.google.com/go/AUTHORS
generated
vendored
15
vendor/cloud.google.com/go/AUTHORS
generated
vendored
@@ -1,15 +0,0 @@
|
||||
# This is the official list of cloud authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS files.
|
||||
# See the latter for an explanation.
|
||||
|
||||
# Names should be added to this file as:
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
Filippo Valsorda <hi@filippo.io>
|
||||
Google Inc.
|
||||
Ingo Oeser <nightlyone@googlemail.com>
|
||||
Palm Stone Games, Inc.
|
||||
Paweł Knap <pawelknap88@gmail.com>
|
||||
Péter Szilágyi <peterke@gmail.com>
|
||||
Tyler Treat <ttreat31@gmail.com>
|
||||
34
vendor/cloud.google.com/go/CONTRIBUTORS
generated
vendored
34
vendor/cloud.google.com/go/CONTRIBUTORS
generated
vendored
@@ -1,34 +0,0 @@
|
||||
# People who have agreed to one of the CLAs and can contribute patches.
|
||||
# The AUTHORS file lists the copyright holders; this file
|
||||
# lists people. For example, Google employees are listed here
|
||||
# but not in AUTHORS, because Google holds the copyright.
|
||||
#
|
||||
# https://developers.google.com/open-source/cla/individual
|
||||
# https://developers.google.com/open-source/cla/corporate
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name <email address>
|
||||
|
||||
# Keep the list alphabetically sorted.
|
||||
|
||||
Andreas Litt <andreas.litt@gmail.com>
|
||||
Andrew Gerrand <adg@golang.org>
|
||||
Brad Fitzpatrick <bradfitz@golang.org>
|
||||
Burcu Dogan <jbd@google.com>
|
||||
Dave Day <djd@golang.org>
|
||||
David Sansome <me@davidsansome.com>
|
||||
David Symonds <dsymonds@golang.org>
|
||||
Filippo Valsorda <hi@filippo.io>
|
||||
Glenn Lewis <gmlewis@google.com>
|
||||
Ingo Oeser <nightlyone@googlemail.com>
|
||||
Johan Euphrosine <proppy@google.com>
|
||||
Jonathan Amsterdam <jba@google.com>
|
||||
Luna Duclos <luna.duclos@palmstonegames.com>
|
||||
Michael McGreevy <mcgreevy@golang.org>
|
||||
Omar Jarjur <ojarjur@google.com>
|
||||
Paweł Knap <pawelknap88@gmail.com>
|
||||
Péter Szilágyi <peterke@gmail.com>
|
||||
Sarah Adams <shadams@google.com>
|
||||
Toby Burress <kurin@google.com>
|
||||
Tuo Shan <shantuo@google.com>
|
||||
Tyler Treat <ttreat31@gmail.com>
|
||||
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014 Google Inc.
|
||||
|
||||
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.
|
||||
438
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
438
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
@@ -1,438 +0,0 @@
|
||||
// Copyright 2014 Google 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 metadata provides access to Google Compute Engine (GCE)
|
||||
// metadata and API service accounts.
|
||||
//
|
||||
// This package is a wrapper around the GCE metadata service,
|
||||
// as documented at https://developers.google.com/compute/docs/metadata.
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
|
||||
"cloud.google.com/go/internal"
|
||||
)
|
||||
|
||||
const (
|
||||
// metadataIP is the documented metadata server IP address.
|
||||
metadataIP = "169.254.169.254"
|
||||
|
||||
// metadataHostEnv is the environment variable specifying the
|
||||
// GCE metadata hostname. If empty, the default value of
|
||||
// metadataIP ("169.254.169.254") is used instead.
|
||||
// This is variable name is not defined by any spec, as far as
|
||||
// I know; it was made up for the Go package.
|
||||
metadataHostEnv = "GCE_METADATA_HOST"
|
||||
)
|
||||
|
||||
type cachedValue struct {
|
||||
k string
|
||||
trim bool
|
||||
mu sync.Mutex
|
||||
v string
|
||||
}
|
||||
|
||||
var (
|
||||
projID = &cachedValue{k: "project/project-id", trim: true}
|
||||
projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
|
||||
instID = &cachedValue{k: "instance/id", trim: true}
|
||||
)
|
||||
|
||||
var (
|
||||
metaClient = &http.Client{
|
||||
Transport: &internal.Transport{
|
||||
Base: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 2 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
ResponseHeaderTimeout: 2 * time.Second,
|
||||
},
|
||||
},
|
||||
}
|
||||
subscribeClient = &http.Client{
|
||||
Transport: &internal.Transport{
|
||||
Base: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 2 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// NotDefinedError is returned when requested metadata is not defined.
|
||||
//
|
||||
// The underlying string is the suffix after "/computeMetadata/v1/".
|
||||
//
|
||||
// This error is not returned if the value is defined to be the empty
|
||||
// string.
|
||||
type NotDefinedError string
|
||||
|
||||
func (suffix NotDefinedError) Error() string {
|
||||
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
|
||||
}
|
||||
|
||||
// Get returns a value from the metadata service.
|
||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||
//
|
||||
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
||||
// 169.254.169.254 will be used instead.
|
||||
//
|
||||
// If the requested metadata is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
func Get(suffix string) (string, error) {
|
||||
val, _, err := getETag(metaClient, suffix)
|
||||
return val, err
|
||||
}
|
||||
|
||||
// getETag returns a value from the metadata service as well as the associated
|
||||
// ETag using the provided client. This func is otherwise equivalent to Get.
|
||||
func getETag(client *http.Client, suffix string) (value, etag string, err error) {
|
||||
// Using a fixed IP makes it very difficult to spoof the metadata service in
|
||||
// a container, which is an important use-case for local testing of cloud
|
||||
// deployments. To enable spoofing of the metadata service, the environment
|
||||
// variable GCE_METADATA_HOST is first inspected to decide where metadata
|
||||
// requests shall go.
|
||||
host := os.Getenv(metadataHostEnv)
|
||||
if host == "" {
|
||||
// Using 169.254.169.254 instead of "metadata" here because Go
|
||||
// binaries built with the "netgo" tag and without cgo won't
|
||||
// know the search suffix for "metadata" is
|
||||
// ".google.internal", and this IP address is documented as
|
||||
// being stable anyway.
|
||||
host = metadataIP
|
||||
}
|
||||
url := "http://" + host + "/computeMetadata/v1/" + suffix
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Metadata-Flavor", "Google")
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode == http.StatusNotFound {
|
||||
return "", "", NotDefinedError(suffix)
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return "", "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
|
||||
}
|
||||
all, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return string(all), res.Header.Get("Etag"), nil
|
||||
}
|
||||
|
||||
func getTrimmed(suffix string) (s string, err error) {
|
||||
s, err = Get(suffix)
|
||||
s = strings.TrimSpace(s)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *cachedValue) get() (v string, err error) {
|
||||
defer c.mu.Unlock()
|
||||
c.mu.Lock()
|
||||
if c.v != "" {
|
||||
return c.v, nil
|
||||
}
|
||||
if c.trim {
|
||||
v, err = getTrimmed(c.k)
|
||||
} else {
|
||||
v, err = Get(c.k)
|
||||
}
|
||||
if err == nil {
|
||||
c.v = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
onGCEOnce sync.Once
|
||||
onGCE bool
|
||||
)
|
||||
|
||||
// OnGCE reports whether this process is running on Google Compute Engine.
|
||||
func OnGCE() bool {
|
||||
onGCEOnce.Do(initOnGCE)
|
||||
return onGCE
|
||||
}
|
||||
|
||||
func initOnGCE() {
|
||||
onGCE = testOnGCE()
|
||||
}
|
||||
|
||||
func testOnGCE() bool {
|
||||
// The user explicitly said they're on GCE, so trust them.
|
||||
if os.Getenv(metadataHostEnv) != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
resc := make(chan bool, 2)
|
||||
|
||||
// Try two strategies in parallel.
|
||||
// See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/194
|
||||
go func() {
|
||||
res, err := ctxhttp.Get(ctx, metaClient, "http://"+metadataIP)
|
||||
if err != nil {
|
||||
resc <- false
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
resc <- res.Header.Get("Metadata-Flavor") == "Google"
|
||||
}()
|
||||
|
||||
go func() {
|
||||
addrs, err := net.LookupHost("metadata.google.internal")
|
||||
if err != nil || len(addrs) == 0 {
|
||||
resc <- false
|
||||
return
|
||||
}
|
||||
resc <- strsContains(addrs, metadataIP)
|
||||
}()
|
||||
|
||||
tryHarder := systemInfoSuggestsGCE()
|
||||
if tryHarder {
|
||||
res := <-resc
|
||||
if res {
|
||||
// The first strategy succeeded, so let's use it.
|
||||
return true
|
||||
}
|
||||
// Wait for either the DNS or metadata server probe to
|
||||
// contradict the other one and say we are running on
|
||||
// GCE. Give it a lot of time to do so, since the system
|
||||
// info already suggests we're running on a GCE BIOS.
|
||||
timer := time.NewTimer(5 * time.Second)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case res = <-resc:
|
||||
return res
|
||||
case <-timer.C:
|
||||
// Too slow. Who knows what this system is.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// There's no hint from the system info that we're running on
|
||||
// GCE, so use the first probe's result as truth, whether it's
|
||||
// true or false. The goal here is to optimize for speed for
|
||||
// users who are NOT running on GCE. We can't assume that
|
||||
// either a DNS lookup or an HTTP request to a blackholed IP
|
||||
// address is fast. Worst case this should return when the
|
||||
// metaClient's Transport.ResponseHeaderTimeout or
|
||||
// Transport.Dial.Timeout fires (in two seconds).
|
||||
return <-resc
|
||||
}
|
||||
|
||||
// systemInfoSuggestsGCE reports whether the local system (without
|
||||
// doing network requests) suggests that we're running on GCE. If this
|
||||
// returns true, testOnGCE tries a bit harder to reach its metadata
|
||||
// server.
|
||||
func systemInfoSuggestsGCE() bool {
|
||||
if runtime.GOOS != "linux" {
|
||||
// We don't have any non-Linux clues available, at least yet.
|
||||
return false
|
||||
}
|
||||
slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
|
||||
name := strings.TrimSpace(string(slurp))
|
||||
return name == "Google" || name == "Google Compute Engine"
|
||||
}
|
||||
|
||||
// Subscribe subscribes to a value from the metadata service.
|
||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||
// The suffix may contain query parameters.
|
||||
//
|
||||
// Subscribe calls fn with the latest metadata value indicated by the provided
|
||||
// suffix. If the metadata value is deleted, fn is called with the empty string
|
||||
// and ok false. Subscribe blocks until fn returns a non-nil error or the value
|
||||
// is deleted. Subscribe returns the error value returned from the last call to
|
||||
// fn, which may be nil when ok == false.
|
||||
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||
const failedSubscribeSleep = time.Second * 5
|
||||
|
||||
// First check to see if the metadata value exists at all.
|
||||
val, lastETag, err := getETag(subscribeClient, suffix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fn(val, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ok := true
|
||||
if strings.ContainsRune(suffix, '?') {
|
||||
suffix += "&wait_for_change=true&last_etag="
|
||||
} else {
|
||||
suffix += "?wait_for_change=true&last_etag="
|
||||
}
|
||||
for {
|
||||
val, etag, err := getETag(subscribeClient, suffix+url.QueryEscape(lastETag))
|
||||
if err != nil {
|
||||
if _, deleted := err.(NotDefinedError); !deleted {
|
||||
time.Sleep(failedSubscribeSleep)
|
||||
continue // Retry on other errors.
|
||||
}
|
||||
ok = false
|
||||
}
|
||||
lastETag = etag
|
||||
|
||||
if err := fn(val, ok); err != nil || !ok {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ProjectID returns the current instance's project ID string.
|
||||
func ProjectID() (string, error) { return projID.get() }
|
||||
|
||||
// NumericProjectID returns the current instance's numeric project ID.
|
||||
func NumericProjectID() (string, error) { return projNum.get() }
|
||||
|
||||
// InternalIP returns the instance's primary internal IP address.
|
||||
func InternalIP() (string, error) {
|
||||
return getTrimmed("instance/network-interfaces/0/ip")
|
||||
}
|
||||
|
||||
// ExternalIP returns the instance's primary external (public) IP address.
|
||||
func ExternalIP() (string, error) {
|
||||
return getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
|
||||
}
|
||||
|
||||
// Hostname returns the instance's hostname. This will be of the form
|
||||
// "<instanceID>.c.<projID>.internal".
|
||||
func Hostname() (string, error) {
|
||||
return getTrimmed("instance/hostname")
|
||||
}
|
||||
|
||||
// InstanceTags returns the list of user-defined instance tags,
|
||||
// assigned when initially creating a GCE instance.
|
||||
func InstanceTags() ([]string, error) {
|
||||
var s []string
|
||||
j, err := Get("instance/tags")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// InstanceID returns the current VM's numeric instance ID.
|
||||
func InstanceID() (string, error) {
|
||||
return instID.get()
|
||||
}
|
||||
|
||||
// InstanceName returns the current VM's instance ID string.
|
||||
func InstanceName() (string, error) {
|
||||
host, err := Hostname()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.Split(host, ".")[0], nil
|
||||
}
|
||||
|
||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||
func Zone() (string, error) {
|
||||
zone, err := getTrimmed("instance/zone")
|
||||
// zone is of the form "projects/<projNum>/zones/<zoneName>".
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return zone[strings.LastIndex(zone, "/")+1:], nil
|
||||
}
|
||||
|
||||
// InstanceAttributes returns the list of user-defined attributes,
|
||||
// assigned when initially creating a GCE VM instance. The value of an
|
||||
// attribute can be obtained with InstanceAttributeValue.
|
||||
func InstanceAttributes() ([]string, error) { return lines("instance/attributes/") }
|
||||
|
||||
// ProjectAttributes returns the list of user-defined attributes
|
||||
// applying to the project as a whole, not just this VM. The value of
|
||||
// an attribute can be obtained with ProjectAttributeValue.
|
||||
func ProjectAttributes() ([]string, error) { return lines("project/attributes/") }
|
||||
|
||||
func lines(suffix string) ([]string, error) {
|
||||
j, err := Get(suffix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := strings.Split(strings.TrimSpace(j), "\n")
|
||||
for i := range s {
|
||||
s[i] = strings.TrimSpace(s[i])
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// InstanceAttributeValue returns the value of the provided VM
|
||||
// instance attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// InstanceAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func InstanceAttributeValue(attr string) (string, error) {
|
||||
return Get("instance/attributes/" + attr)
|
||||
}
|
||||
|
||||
// ProjectAttributeValue returns the value of the provided
|
||||
// project attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// ProjectAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func ProjectAttributeValue(attr string) (string, error) {
|
||||
return Get("project/attributes/" + attr)
|
||||
}
|
||||
|
||||
// Scopes returns the service account scopes for the given account.
|
||||
// The account may be empty or the string "default" to use the instance's
|
||||
// main account.
|
||||
func Scopes(serviceAccount string) ([]string, error) {
|
||||
if serviceAccount == "" {
|
||||
serviceAccount = "default"
|
||||
}
|
||||
return lines("instance/service-accounts/" + serviceAccount + "/scopes")
|
||||
}
|
||||
|
||||
func strsContains(ss []string, s string) bool {
|
||||
for _, v := range ss {
|
||||
if v == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
64
vendor/cloud.google.com/go/internal/cloud.go
generated
vendored
64
vendor/cloud.google.com/go/internal/cloud.go
generated
vendored
@@ -1,64 +0,0 @@
|
||||
// Copyright 2014 Google 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 provides support for the cloud packages.
|
||||
//
|
||||
// Users should not import this package directly.
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const userAgent = "gcloud-golang/0.1"
|
||||
|
||||
// Transport is an http.RoundTripper that appends Google Cloud client's
|
||||
// user-agent to the original request's user-agent header.
|
||||
type Transport struct {
|
||||
// TODO(bradfitz): delete internal.Transport. It's too wrappy for what it does.
|
||||
// Do User-Agent some other way.
|
||||
|
||||
// Base is the actual http.RoundTripper
|
||||
// requests will use. It must not be nil.
|
||||
Base http.RoundTripper
|
||||
}
|
||||
|
||||
// RoundTrip appends a user-agent to the existing user-agent
|
||||
// header and delegates the request to the base http.RoundTripper.
|
||||
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req = cloneRequest(req)
|
||||
ua := req.Header.Get("User-Agent")
|
||||
if ua == "" {
|
||||
ua = userAgent
|
||||
} else {
|
||||
ua = fmt.Sprintf("%s %s", ua, userAgent)
|
||||
}
|
||||
req.Header.Set("User-Agent", ua)
|
||||
return t.Base.RoundTrip(req)
|
||||
}
|
||||
|
||||
// cloneRequest returns a clone of the provided *http.Request.
|
||||
// The clone is a shallow copy of the struct and its Header map.
|
||||
func cloneRequest(r *http.Request) *http.Request {
|
||||
// shallow copy of the struct
|
||||
r2 := new(http.Request)
|
||||
*r2 = *r
|
||||
// deep copy of the Header
|
||||
r2.Header = make(http.Header)
|
||||
for k, s := range r.Header {
|
||||
r2.Header[k] = s
|
||||
}
|
||||
return r2
|
||||
}
|
||||
191
vendor/github.com/Azure/go-autorest/LICENSE
generated
vendored
191
vendor/github.com/Azure/go-autorest/LICENSE
generated
vendored
@@ -1,191 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Microsoft Corporation
|
||||
|
||||
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.
|
||||
114
vendor/github.com/Azure/go-autorest/autorest/autorest.go
generated
vendored
114
vendor/github.com/Azure/go-autorest/autorest/autorest.go
generated
vendored
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
Package autorest implements an HTTP request pipeline suitable for use across multiple go-routines
|
||||
and provides the shared routines relied on by AutoRest (see https://github.com/Azure/autorest/)
|
||||
generated Go code.
|
||||
|
||||
The package breaks sending and responding to HTTP requests into three phases: Preparing, Sending,
|
||||
and Responding. A typical pattern is:
|
||||
|
||||
req, err := Prepare(&http.Request{},
|
||||
token.WithAuthorization())
|
||||
|
||||
resp, err := Send(req,
|
||||
WithLogging(logger),
|
||||
DoErrorIfStatusCode(http.StatusInternalServerError),
|
||||
DoCloseIfError(),
|
||||
DoRetryForAttempts(5, time.Second))
|
||||
|
||||
err = Respond(resp,
|
||||
ByClosing())
|
||||
|
||||
Each phase relies on decorators to modify and / or manage processing. Decorators may first modify
|
||||
and then pass the data along, pass the data first and then modify the result, or wrap themselves
|
||||
around passing the data (such as a logger might do). Decorators run in the order provided. For
|
||||
example, the following:
|
||||
|
||||
req, err := Prepare(&http.Request{},
|
||||
WithBaseURL("https://microsoft.com/"),
|
||||
WithPath("a"),
|
||||
WithPath("b"),
|
||||
WithPath("c"))
|
||||
|
||||
will set the URL to:
|
||||
|
||||
https://microsoft.com/a/b/c
|
||||
|
||||
Preparers and Responders may be shared and re-used (assuming the underlying decorators support
|
||||
sharing and re-use). Performant use is obtained by creating one or more Preparers and Responders
|
||||
shared among multiple go-routines, and a single Sender shared among multiple sending go-routines,
|
||||
all bound together by means of input / output channels.
|
||||
|
||||
Decorators hold their passed state within a closure (such as the path components in the example
|
||||
above). Be careful to share Preparers and Responders only in a context where such held state
|
||||
applies. For example, it may not make sense to share a Preparer that applies a query string from a
|
||||
fixed set of values. Similarly, sharing a Responder that reads the response body into a passed
|
||||
struct (e.g., ByUnmarshallingJson) is likely incorrect.
|
||||
|
||||
Lastly, the Swagger specification (https://swagger.io) that drives AutoRest
|
||||
(https://github.com/Azure/autorest/) precisely defines two date forms: date and date-time. The
|
||||
github.com/Azure/go-autorest/autorest/date package provides time.Time derivations to ensure
|
||||
correct parsing and formatting.
|
||||
|
||||
Errors raised by autorest objects and methods will conform to the autorest.Error interface.
|
||||
|
||||
See the included examples for more detail. For details on the suggested use of this package by
|
||||
generated clients, see the Client described below.
|
||||
*/
|
||||
package autorest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// HeaderLocation specifies the HTTP Location header.
|
||||
HeaderLocation = "Location"
|
||||
|
||||
// HeaderRetryAfter specifies the HTTP Retry-After header.
|
||||
HeaderRetryAfter = "Retry-After"
|
||||
)
|
||||
|
||||
// ResponseHasStatusCode returns true if the status code in the HTTP Response is in the passed set
|
||||
// and false otherwise.
|
||||
func ResponseHasStatusCode(resp *http.Response, codes ...int) bool {
|
||||
return containsInt(codes, resp.StatusCode)
|
||||
}
|
||||
|
||||
// GetLocation retrieves the URL from the Location header of the passed response.
|
||||
func GetLocation(resp *http.Response) string {
|
||||
return resp.Header.Get(HeaderLocation)
|
||||
}
|
||||
|
||||
// GetRetryAfter extracts the retry delay from the Retry-After header of the passed response. If
|
||||
// the header is absent or is malformed, it will return the supplied default delay time.Duration.
|
||||
func GetRetryAfter(resp *http.Response, defaultDelay time.Duration) time.Duration {
|
||||
retry := resp.Header.Get(HeaderRetryAfter)
|
||||
if retry == "" {
|
||||
return defaultDelay
|
||||
}
|
||||
|
||||
d, err := time.ParseDuration(retry + "s")
|
||||
if err != nil {
|
||||
return defaultDelay
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// NewPollingRequest allocates and returns a new http.Request to poll for the passed response.
|
||||
func NewPollingRequest(resp *http.Response, cancel <-chan struct{}) (*http.Request, error) {
|
||||
location := GetLocation(resp)
|
||||
if location == "" {
|
||||
return nil, NewErrorWithResponse("autorest", "NewPollingRequest", resp, "Location header missing from response that requires polling")
|
||||
}
|
||||
|
||||
req, err := Prepare(&http.Request{Cancel: cancel},
|
||||
AsGet(),
|
||||
WithBaseURL(location))
|
||||
if err != nil {
|
||||
return nil, NewErrorWithError(err, "autorest", "NewPollingRequest", nil, "Failure creating poll request to %s", location)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
307
vendor/github.com/Azure/go-autorest/autorest/azure/async.go
generated
vendored
307
vendor/github.com/Azure/go-autorest/autorest/azure/async.go
generated
vendored
@@ -1,307 +0,0 @@
|
||||
package azure
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/date"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
headerAsyncOperation = "Azure-AsyncOperation"
|
||||
)
|
||||
|
||||
const (
|
||||
methodDelete = "DELETE"
|
||||
methodPatch = "PATCH"
|
||||
methodPost = "POST"
|
||||
methodPut = "PUT"
|
||||
methodGet = "GET"
|
||||
|
||||
operationInProgress string = "InProgress"
|
||||
operationCanceled string = "Canceled"
|
||||
operationFailed string = "Failed"
|
||||
operationSucceeded string = "Succeeded"
|
||||
)
|
||||
|
||||
// DoPollForAsynchronous returns a SendDecorator that polls if the http.Response is for an Azure
|
||||
// long-running operation. It will delay between requests for the duration specified in the
|
||||
// RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled by
|
||||
// closing the optional channel on the http.Request.
|
||||
func DoPollForAsynchronous(delay time.Duration) autorest.SendDecorator {
|
||||
return func(s autorest.Sender) autorest.Sender {
|
||||
return autorest.SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
|
||||
resp, err = s.Do(r)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
pollingCodes := []int{http.StatusAccepted, http.StatusCreated, http.StatusOK}
|
||||
if !autorest.ResponseHasStatusCode(resp, pollingCodes...) {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
ps := pollingState{}
|
||||
for err == nil {
|
||||
err = updatePollingState(resp, &ps)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if ps.hasTerminated() {
|
||||
if !ps.hasSucceeded() {
|
||||
err = ps
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
r, err = newPollingRequest(resp, ps)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
delay = autorest.GetRetryAfter(resp, delay)
|
||||
resp, err = autorest.SendWithSender(s, r,
|
||||
autorest.AfterDelay(delay))
|
||||
}
|
||||
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func getAsyncOperation(resp *http.Response) string {
|
||||
return resp.Header.Get(http.CanonicalHeaderKey(headerAsyncOperation))
|
||||
}
|
||||
|
||||
func hasSucceeded(state string) bool {
|
||||
return state == operationSucceeded
|
||||
}
|
||||
|
||||
func hasTerminated(state string) bool {
|
||||
switch state {
|
||||
case operationCanceled, operationFailed, operationSucceeded:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func hasFailed(state string) bool {
|
||||
return state == operationFailed
|
||||
}
|
||||
|
||||
type provisioningTracker interface {
|
||||
state() string
|
||||
hasSucceeded() bool
|
||||
hasTerminated() bool
|
||||
}
|
||||
|
||||
type operationResource struct {
|
||||
// Note:
|
||||
// The specification states services should return the "id" field. However some return it as
|
||||
// "operationId".
|
||||
ID string `json:"id"`
|
||||
OperationID string `json:"operationId"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Properties map[string]interface{} `json:"properties"`
|
||||
OperationError ServiceError `json:"error"`
|
||||
StartTime date.Time `json:"startTime"`
|
||||
EndTime date.Time `json:"endTime"`
|
||||
PercentComplete float64 `json:"percentComplete"`
|
||||
}
|
||||
|
||||
func (or operationResource) state() string {
|
||||
return or.Status
|
||||
}
|
||||
|
||||
func (or operationResource) hasSucceeded() bool {
|
||||
return hasSucceeded(or.state())
|
||||
}
|
||||
|
||||
func (or operationResource) hasTerminated() bool {
|
||||
return hasTerminated(or.state())
|
||||
}
|
||||
|
||||
type provisioningProperties struct {
|
||||
ProvisioningState string `json:"provisioningState"`
|
||||
}
|
||||
|
||||
type provisioningStatus struct {
|
||||
Properties provisioningProperties `json:"properties,omitempty"`
|
||||
ProvisioningError ServiceError `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (ps provisioningStatus) state() string {
|
||||
return ps.Properties.ProvisioningState
|
||||
}
|
||||
|
||||
func (ps provisioningStatus) hasSucceeded() bool {
|
||||
return hasSucceeded(ps.state())
|
||||
}
|
||||
|
||||
func (ps provisioningStatus) hasTerminated() bool {
|
||||
return hasTerminated(ps.state())
|
||||
}
|
||||
|
||||
func (ps provisioningStatus) hasProvisioningError() bool {
|
||||
return ps.ProvisioningError != ServiceError{}
|
||||
}
|
||||
|
||||
type pollingResponseFormat string
|
||||
|
||||
const (
|
||||
usesOperationResponse pollingResponseFormat = "OperationResponse"
|
||||
usesProvisioningStatus pollingResponseFormat = "ProvisioningStatus"
|
||||
formatIsUnknown pollingResponseFormat = ""
|
||||
)
|
||||
|
||||
type pollingState struct {
|
||||
responseFormat pollingResponseFormat
|
||||
uri string
|
||||
state string
|
||||
code string
|
||||
message string
|
||||
}
|
||||
|
||||
func (ps pollingState) hasSucceeded() bool {
|
||||
return hasSucceeded(ps.state)
|
||||
}
|
||||
|
||||
func (ps pollingState) hasTerminated() bool {
|
||||
return hasTerminated(ps.state)
|
||||
}
|
||||
|
||||
func (ps pollingState) hasFailed() bool {
|
||||
return hasFailed(ps.state)
|
||||
}
|
||||
|
||||
func (ps pollingState) Error() string {
|
||||
return fmt.Sprintf("Long running operation terminated with status '%s': Code=%q Message=%q", ps.state, ps.code, ps.message)
|
||||
}
|
||||
|
||||
// updatePollingState maps the operation status -- retrieved from either a provisioningState
|
||||
// field, the status field of an OperationResource, or inferred from the HTTP status code --
|
||||
// into a well-known states. Since the process begins from the initial request, the state
|
||||
// always comes from either a the provisioningState returned or is inferred from the HTTP
|
||||
// status code. Subsequent requests will read an Azure OperationResource object if the
|
||||
// service initially returned the Azure-AsyncOperation header. The responseFormat field notes
|
||||
// the expected response format.
|
||||
func updatePollingState(resp *http.Response, ps *pollingState) error {
|
||||
// Determine the response shape
|
||||
// -- The first response will always be a provisioningStatus response; only the polling requests,
|
||||
// depending on the header returned, may be something otherwise.
|
||||
var pt provisioningTracker
|
||||
if ps.responseFormat == usesOperationResponse {
|
||||
pt = &operationResource{}
|
||||
} else {
|
||||
pt = &provisioningStatus{}
|
||||
}
|
||||
|
||||
// If this is the first request (that is, the polling response shape is unknown), determine how
|
||||
// to poll and what to expect
|
||||
if ps.responseFormat == formatIsUnknown {
|
||||
req := resp.Request
|
||||
if req == nil {
|
||||
return autorest.NewError("azure", "updatePollingState", "Azure Polling Error - Original HTTP request is missing")
|
||||
}
|
||||
|
||||
// Prefer the Azure-AsyncOperation header
|
||||
ps.uri = getAsyncOperation(resp)
|
||||
if ps.uri != "" {
|
||||
ps.responseFormat = usesOperationResponse
|
||||
} else {
|
||||
ps.responseFormat = usesProvisioningStatus
|
||||
}
|
||||
|
||||
// Else, use the Location header
|
||||
if ps.uri == "" {
|
||||
ps.uri = autorest.GetLocation(resp)
|
||||
}
|
||||
|
||||
// Lastly, requests against an existing resource, use the last request URI
|
||||
if ps.uri == "" {
|
||||
m := strings.ToUpper(req.Method)
|
||||
if m == methodPatch || m == methodPut || m == methodGet {
|
||||
ps.uri = req.URL.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read and interpret the response (saving the Body in case no polling is necessary)
|
||||
b := &bytes.Buffer{}
|
||||
err := autorest.Respond(resp,
|
||||
autorest.ByCopying(b),
|
||||
autorest.ByUnmarshallingJSON(pt),
|
||||
autorest.ByClosing())
|
||||
resp.Body = ioutil.NopCloser(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Interpret the results
|
||||
// -- Terminal states apply regardless
|
||||
// -- Unknown states are per-service inprogress states
|
||||
// -- Otherwise, infer state from HTTP status code
|
||||
if pt.hasTerminated() {
|
||||
ps.state = pt.state()
|
||||
} else if pt.state() != "" {
|
||||
ps.state = operationInProgress
|
||||
} else {
|
||||
switch resp.StatusCode {
|
||||
case http.StatusAccepted:
|
||||
ps.state = operationInProgress
|
||||
|
||||
case http.StatusNoContent, http.StatusCreated, http.StatusOK:
|
||||
ps.state = operationSucceeded
|
||||
|
||||
default:
|
||||
ps.state = operationFailed
|
||||
}
|
||||
}
|
||||
|
||||
if ps.state == operationInProgress && ps.uri == "" {
|
||||
return autorest.NewError("azure", "updatePollingState", "Azure Polling Error - Unable to obtain polling URI for %s %s", resp.Request.Method, resp.Request.URL)
|
||||
}
|
||||
|
||||
// For failed operation, check for error code and message in
|
||||
// -- Operation resource
|
||||
// -- Response
|
||||
// -- Otherwise, Unknown
|
||||
if ps.hasFailed() {
|
||||
if ps.responseFormat == usesOperationResponse {
|
||||
or := pt.(*operationResource)
|
||||
ps.code = or.OperationError.Code
|
||||
ps.message = or.OperationError.Message
|
||||
} else {
|
||||
p := pt.(*provisioningStatus)
|
||||
if p.hasProvisioningError() {
|
||||
ps.code = p.ProvisioningError.Code
|
||||
ps.message = p.ProvisioningError.Message
|
||||
} else {
|
||||
ps.code = "Unknown"
|
||||
ps.message = "None"
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newPollingRequest(resp *http.Response, ps pollingState) (*http.Request, error) {
|
||||
req := resp.Request
|
||||
if req == nil {
|
||||
return nil, autorest.NewError("azure", "newPollingRequest", "Azure Polling Error - Original HTTP request is missing")
|
||||
}
|
||||
|
||||
reqPoll, err := autorest.Prepare(&http.Request{Cancel: req.Cancel},
|
||||
autorest.AsGet(),
|
||||
autorest.WithBaseURL(ps.uri))
|
||||
if err != nil {
|
||||
return nil, autorest.NewErrorWithError(err, "azure", "newPollingRequest", nil, "Failure creating poll request to %s", ps.uri)
|
||||
}
|
||||
|
||||
return reqPoll, nil
|
||||
}
|
||||
180
vendor/github.com/Azure/go-autorest/autorest/azure/azure.go
generated
vendored
180
vendor/github.com/Azure/go-autorest/autorest/azure/azure.go
generated
vendored
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
Package azure provides Azure-specific implementations used with AutoRest.
|
||||
|
||||
See the included examples for more detail.
|
||||
*/
|
||||
package azure
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
)
|
||||
|
||||
const (
|
||||
// HeaderClientID is the Azure extension header to set a user-specified request ID.
|
||||
HeaderClientID = "x-ms-client-request-id"
|
||||
|
||||
// HeaderReturnClientID is the Azure extension header to set if the user-specified request ID
|
||||
// should be included in the response.
|
||||
HeaderReturnClientID = "x-ms-return-client-request-id"
|
||||
|
||||
// HeaderRequestID is the Azure extension header of the service generated request ID returned
|
||||
// in the response.
|
||||
HeaderRequestID = "x-ms-request-id"
|
||||
)
|
||||
|
||||
// ServiceError encapsulates the error response from an Azure service.
|
||||
type ServiceError struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Details *[]interface{} `json:"details"`
|
||||
}
|
||||
|
||||
func (se ServiceError) Error() string {
|
||||
if se.Details != nil {
|
||||
d, err := json.Marshal(*(se.Details))
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Code=%q Message=%q Details=%v", se.Code, se.Message, *se.Details)
|
||||
}
|
||||
return fmt.Sprintf("Code=%q Message=%q Details=%v", se.Code, se.Message, string(d))
|
||||
}
|
||||
return fmt.Sprintf("Code=%q Message=%q", se.Code, se.Message)
|
||||
}
|
||||
|
||||
// RequestError describes an error response returned by Azure service.
|
||||
type RequestError struct {
|
||||
autorest.DetailedError
|
||||
|
||||
// The error returned by the Azure service.
|
||||
ServiceError *ServiceError `json:"error"`
|
||||
|
||||
// The request id (from the x-ms-request-id-header) of the request.
|
||||
RequestID string
|
||||
}
|
||||
|
||||
// Error returns a human-friendly error message from service error.
|
||||
func (e RequestError) Error() string {
|
||||
return fmt.Sprintf("autorest/azure: Service returned an error. Status=%v %v",
|
||||
e.StatusCode, e.ServiceError)
|
||||
}
|
||||
|
||||
// IsAzureError returns true if the passed error is an Azure Service error; false otherwise.
|
||||
func IsAzureError(e error) bool {
|
||||
_, ok := e.(*RequestError)
|
||||
return ok
|
||||
}
|
||||
|
||||
// NewErrorWithError creates a new Error conforming object from the
|
||||
// passed packageType, method, statusCode of the given resp (UndefinedStatusCode
|
||||
// if resp is nil), message, and original error. message is treated as a format
|
||||
// string to which the optional args apply.
|
||||
func NewErrorWithError(original error, packageType string, method string, resp *http.Response, message string, args ...interface{}) RequestError {
|
||||
if v, ok := original.(*RequestError); ok {
|
||||
return *v
|
||||
}
|
||||
|
||||
statusCode := autorest.UndefinedStatusCode
|
||||
if resp != nil {
|
||||
statusCode = resp.StatusCode
|
||||
}
|
||||
return RequestError{
|
||||
DetailedError: autorest.DetailedError{
|
||||
Original: original,
|
||||
PackageType: packageType,
|
||||
Method: method,
|
||||
StatusCode: statusCode,
|
||||
Message: fmt.Sprintf(message, args...),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// WithReturningClientID returns a PrepareDecorator that adds an HTTP extension header of
|
||||
// x-ms-client-request-id whose value is the passed, undecorated UUID (e.g.,
|
||||
// "0F39878C-5F76-4DB8-A25D-61D2C193C3CA"). It also sets the x-ms-return-client-request-id
|
||||
// header to true such that UUID accompanies the http.Response.
|
||||
func WithReturningClientID(uuid string) autorest.PrepareDecorator {
|
||||
preparer := autorest.CreatePreparer(
|
||||
WithClientID(uuid),
|
||||
WithReturnClientID(true))
|
||||
|
||||
return func(p autorest.Preparer) autorest.Preparer {
|
||||
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
return preparer.Prepare(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithClientID returns a PrepareDecorator that adds an HTTP extension header of
|
||||
// x-ms-client-request-id whose value is passed, undecorated UUID (e.g.,
|
||||
// "0F39878C-5F76-4DB8-A25D-61D2C193C3CA").
|
||||
func WithClientID(uuid string) autorest.PrepareDecorator {
|
||||
return autorest.WithHeader(HeaderClientID, uuid)
|
||||
}
|
||||
|
||||
// WithReturnClientID returns a PrepareDecorator that adds an HTTP extension header of
|
||||
// x-ms-return-client-request-id whose boolean value indicates if the value of the
|
||||
// x-ms-client-request-id header should be included in the http.Response.
|
||||
func WithReturnClientID(b bool) autorest.PrepareDecorator {
|
||||
return autorest.WithHeader(HeaderReturnClientID, strconv.FormatBool(b))
|
||||
}
|
||||
|
||||
// ExtractClientID extracts the client identifier from the x-ms-client-request-id header set on the
|
||||
// http.Request sent to the service (and returned in the http.Response)
|
||||
func ExtractClientID(resp *http.Response) string {
|
||||
return autorest.ExtractHeaderValue(HeaderClientID, resp)
|
||||
}
|
||||
|
||||
// ExtractRequestID extracts the Azure server generated request identifier from the
|
||||
// x-ms-request-id header.
|
||||
func ExtractRequestID(resp *http.Response) string {
|
||||
return autorest.ExtractHeaderValue(HeaderRequestID, resp)
|
||||
}
|
||||
|
||||
// WithErrorUnlessStatusCode returns a RespondDecorator that emits an
|
||||
// azure.RequestError by reading the response body unless the response HTTP status code
|
||||
// is among the set passed.
|
||||
//
|
||||
// If there is a chance service may return responses other than the Azure error
|
||||
// format and the response cannot be parsed into an error, a decoding error will
|
||||
// be returned containing the response body. In any case, the Responder will
|
||||
// return an error if the status code is not satisfied.
|
||||
//
|
||||
// If this Responder returns an error, the response body will be replaced with
|
||||
// an in-memory reader, which needs no further closing.
|
||||
func WithErrorUnlessStatusCode(codes ...int) autorest.RespondDecorator {
|
||||
return func(r autorest.Responder) autorest.Responder {
|
||||
return autorest.ResponderFunc(func(resp *http.Response) error {
|
||||
err := r.Respond(resp)
|
||||
if err == nil && !autorest.ResponseHasStatusCode(resp, codes...) {
|
||||
var e RequestError
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Copy and replace the Body in case it does not contain an error object.
|
||||
// This will leave the Body available to the caller.
|
||||
b, decodeErr := autorest.CopyAndDecode(autorest.EncodedAsJSON, resp.Body, &e)
|
||||
resp.Body = ioutil.NopCloser(&b)
|
||||
if decodeErr != nil {
|
||||
return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b.String(), decodeErr)
|
||||
} else if e.ServiceError == nil {
|
||||
e.ServiceError = &ServiceError{Code: "Unknown", Message: "Unknown service error"}
|
||||
}
|
||||
|
||||
e.RequestID = ExtractRequestID(resp)
|
||||
if e.StatusCode == nil {
|
||||
e.StatusCode = resp.StatusCode
|
||||
}
|
||||
err = &e
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
13
vendor/github.com/Azure/go-autorest/autorest/azure/config.go
generated
vendored
13
vendor/github.com/Azure/go-autorest/autorest/azure/config.go
generated
vendored
@@ -1,13 +0,0 @@
|
||||
package azure
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// OAuthConfig represents the endpoints needed
|
||||
// in OAuth operations
|
||||
type OAuthConfig struct {
|
||||
AuthorizeEndpoint url.URL
|
||||
TokenEndpoint url.URL
|
||||
DeviceCodeEndpoint url.URL
|
||||
}
|
||||
193
vendor/github.com/Azure/go-autorest/autorest/azure/devicetoken.go
generated
vendored
193
vendor/github.com/Azure/go-autorest/autorest/azure/devicetoken.go
generated
vendored
@@ -1,193 +0,0 @@
|
||||
package azure
|
||||
|
||||
/*
|
||||
This file is largely based on rjw57/oauth2device's code, with the follow differences:
|
||||
* scope -> resource, and only allow a single one
|
||||
* receive "Message" in the DeviceCode struct and show it to users as the prompt
|
||||
* azure-xplat-cli has the following behavior that this emulates:
|
||||
- does not send client_secret during the token exchange
|
||||
- sends resource again in the token exchange request
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
)
|
||||
|
||||
const (
|
||||
logPrefix = "autorest/azure/devicetoken:"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrDeviceGeneric represents an unknown error from the token endpoint when using device flow
|
||||
ErrDeviceGeneric = fmt.Errorf("%s Error while retrieving OAuth token: Unknown Error", logPrefix)
|
||||
|
||||
// ErrDeviceAccessDenied represents an access denied error from the token endpoint when using device flow
|
||||
ErrDeviceAccessDenied = fmt.Errorf("%s Error while retrieving OAuth token: Access Denied", logPrefix)
|
||||
|
||||
// ErrDeviceAuthorizationPending represents the server waiting on the user to complete the device flow
|
||||
ErrDeviceAuthorizationPending = fmt.Errorf("%s Error while retrieving OAuth token: Authorization Pending", logPrefix)
|
||||
|
||||
// ErrDeviceCodeExpired represents the server timing out and expiring the code during device flow
|
||||
ErrDeviceCodeExpired = fmt.Errorf("%s Error while retrieving OAuth token: Code Expired", logPrefix)
|
||||
|
||||
// ErrDeviceSlowDown represents the service telling us we're polling too often during device flow
|
||||
ErrDeviceSlowDown = fmt.Errorf("%s Error while retrieving OAuth token: Slow Down", logPrefix)
|
||||
|
||||
errCodeSendingFails = "Error occurred while sending request for Device Authorization Code"
|
||||
errCodeHandlingFails = "Error occurred while handling response from the Device Endpoint"
|
||||
errTokenSendingFails = "Error occurred while sending request with device code for a token"
|
||||
errTokenHandlingFails = "Error occurred while handling response from the Token Endpoint (during device flow)"
|
||||
)
|
||||
|
||||
// DeviceCode is the object returned by the device auth endpoint
|
||||
// It contains information to instruct the user to complete the auth flow
|
||||
type DeviceCode struct {
|
||||
DeviceCode *string `json:"device_code,omitempty"`
|
||||
UserCode *string `json:"user_code,omitempty"`
|
||||
VerificationURL *string `json:"verification_url,omitempty"`
|
||||
ExpiresIn *int64 `json:"expires_in,string,omitempty"`
|
||||
Interval *int64 `json:"interval,string,omitempty"`
|
||||
|
||||
Message *string `json:"message"` // Azure specific
|
||||
Resource string // store the following, stored when initiating, used when exchanging
|
||||
OAuthConfig OAuthConfig
|
||||
ClientID string
|
||||
}
|
||||
|
||||
// TokenError is the object returned by the token exchange endpoint
|
||||
// when something is amiss
|
||||
type TokenError struct {
|
||||
Error *string `json:"error,omitempty"`
|
||||
ErrorCodes []int `json:"error_codes,omitempty"`
|
||||
ErrorDescription *string `json:"error_description,omitempty"`
|
||||
Timestamp *string `json:"timestamp,omitempty"`
|
||||
TraceID *string `json:"trace_id,omitempty"`
|
||||
}
|
||||
|
||||
// DeviceToken is the object return by the token exchange endpoint
|
||||
// It can either look like a Token or an ErrorToken, so put both here
|
||||
// and check for presence of "Error" to know if we are in error state
|
||||
type deviceToken struct {
|
||||
Token
|
||||
TokenError
|
||||
}
|
||||
|
||||
// InitiateDeviceAuth initiates a device auth flow. It returns a DeviceCode
|
||||
// that can be used with CheckForUserCompletion or WaitForUserCompletion.
|
||||
func InitiateDeviceAuth(client *autorest.Client, oauthConfig OAuthConfig, clientID, resource string) (*DeviceCode, error) {
|
||||
req, _ := autorest.Prepare(
|
||||
&http.Request{},
|
||||
autorest.AsPost(),
|
||||
autorest.AsFormURLEncoded(),
|
||||
autorest.WithBaseURL(oauthConfig.DeviceCodeEndpoint.String()),
|
||||
autorest.WithFormData(url.Values{
|
||||
"client_id": []string{clientID},
|
||||
"resource": []string{resource},
|
||||
}),
|
||||
)
|
||||
|
||||
resp, err := autorest.SendWithSender(client, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeSendingFails, err)
|
||||
}
|
||||
|
||||
var code DeviceCode
|
||||
err = autorest.Respond(
|
||||
resp,
|
||||
autorest.WithErrorUnlessStatusCode(http.StatusOK),
|
||||
autorest.ByUnmarshallingJSON(&code),
|
||||
autorest.ByClosing())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeHandlingFails, err)
|
||||
}
|
||||
|
||||
code.ClientID = clientID
|
||||
code.Resource = resource
|
||||
code.OAuthConfig = oauthConfig
|
||||
|
||||
return &code, nil
|
||||
}
|
||||
|
||||
// CheckForUserCompletion takes a DeviceCode and checks with the Azure AD OAuth endpoint
|
||||
// to see if the device flow has: been completed, timed out, or otherwise failed
|
||||
func CheckForUserCompletion(client *autorest.Client, code *DeviceCode) (*Token, error) {
|
||||
req, _ := autorest.Prepare(
|
||||
&http.Request{},
|
||||
autorest.AsPost(),
|
||||
autorest.AsFormURLEncoded(),
|
||||
autorest.WithBaseURL(code.OAuthConfig.TokenEndpoint.String()),
|
||||
autorest.WithFormData(url.Values{
|
||||
"client_id": []string{code.ClientID},
|
||||
"code": []string{*code.DeviceCode},
|
||||
"grant_type": []string{OAuthGrantTypeDeviceCode},
|
||||
"resource": []string{code.Resource},
|
||||
}),
|
||||
)
|
||||
|
||||
resp, err := autorest.SendWithSender(client, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenSendingFails, err)
|
||||
}
|
||||
|
||||
var token deviceToken
|
||||
err = autorest.Respond(
|
||||
resp,
|
||||
autorest.WithErrorUnlessStatusCode(http.StatusOK, http.StatusBadRequest),
|
||||
autorest.ByUnmarshallingJSON(&token),
|
||||
autorest.ByClosing())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenHandlingFails, err)
|
||||
}
|
||||
|
||||
if token.Error == nil {
|
||||
return &token.Token, nil
|
||||
}
|
||||
|
||||
switch *token.Error {
|
||||
case "authorization_pending":
|
||||
return nil, ErrDeviceAuthorizationPending
|
||||
case "slow_down":
|
||||
return nil, ErrDeviceSlowDown
|
||||
case "access_denied":
|
||||
return nil, ErrDeviceAccessDenied
|
||||
case "code_expired":
|
||||
return nil, ErrDeviceCodeExpired
|
||||
default:
|
||||
return nil, ErrDeviceGeneric
|
||||
}
|
||||
}
|
||||
|
||||
// WaitForUserCompletion calls CheckForUserCompletion repeatedly until a token is granted or an error state occurs.
|
||||
// This prevents the user from looping and checking against 'ErrDeviceAuthorizationPending'.
|
||||
func WaitForUserCompletion(client *autorest.Client, code *DeviceCode) (*Token, error) {
|
||||
intervalDuration := time.Duration(*code.Interval) * time.Second
|
||||
waitDuration := intervalDuration
|
||||
|
||||
for {
|
||||
token, err := CheckForUserCompletion(client, code)
|
||||
|
||||
if err == nil {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
switch err {
|
||||
case ErrDeviceSlowDown:
|
||||
waitDuration += waitDuration
|
||||
case ErrDeviceAuthorizationPending:
|
||||
// noop
|
||||
default: // everything else is "fatal" to us
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if waitDuration > (intervalDuration * 3) {
|
||||
return nil, fmt.Errorf("%s Error waiting for user to complete device flow. Server told us to slow_down too much", logPrefix)
|
||||
}
|
||||
|
||||
time.Sleep(waitDuration)
|
||||
}
|
||||
}
|
||||
162
vendor/github.com/Azure/go-autorest/autorest/azure/environments.go
generated
vendored
162
vendor/github.com/Azure/go-autorest/autorest/azure/environments.go
generated
vendored
@@ -1,162 +0,0 @@
|
||||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
activeDirectoryAPIVersion = "1.0"
|
||||
)
|
||||
|
||||
var environments = map[string]Environment{
|
||||
"AZURECHINACLOUD": ChinaCloud,
|
||||
"AZUREGERMANCLOUD": GermanCloud,
|
||||
"AZUREPUBLICCLOUD": PublicCloud,
|
||||
"AZUREUSGOVERNMENTCLOUD": USGovernmentCloud,
|
||||
}
|
||||
|
||||
// Environment represents a set of endpoints for each of Azure's Clouds.
|
||||
type Environment struct {
|
||||
Name string `json:"name"`
|
||||
ManagementPortalURL string `json:"managementPortalURL"`
|
||||
PublishSettingsURL string `json:"publishSettingsURL"`
|
||||
ServiceManagementEndpoint string `json:"serviceManagementEndpoint"`
|
||||
ResourceManagerEndpoint string `json:"resourceManagerEndpoint"`
|
||||
ActiveDirectoryEndpoint string `json:"activeDirectoryEndpoint"`
|
||||
GalleryEndpoint string `json:"galleryEndpoint"`
|
||||
KeyVaultEndpoint string `json:"keyVaultEndpoint"`
|
||||
GraphEndpoint string `json:"graphEndpoint"`
|
||||
StorageEndpointSuffix string `json:"storageEndpointSuffix"`
|
||||
SQLDatabaseDNSSuffix string `json:"sqlDatabaseDNSSuffix"`
|
||||
TrafficManagerDNSSuffix string `json:"trafficManagerDNSSuffix"`
|
||||
KeyVaultDNSSuffix string `json:"keyVaultDNSSuffix"`
|
||||
ServiceBusEndpointSuffix string `json:"serviceBusEndpointSuffix"`
|
||||
ServiceManagementVMDNSSuffix string `json:"serviceManagementVMDNSSuffix"`
|
||||
ResourceManagerVMDNSSuffix string `json:"resourceManagerVMDNSSuffix"`
|
||||
}
|
||||
|
||||
var (
|
||||
// PublicCloud is the default public Azure cloud environment
|
||||
PublicCloud = Environment{
|
||||
Name: "AzurePublicCloud",
|
||||
ManagementPortalURL: "https://manage.windowsazure.com/",
|
||||
PublishSettingsURL: "https://manage.windowsazure.com/publishsettings/index",
|
||||
ServiceManagementEndpoint: "https://management.core.windows.net/",
|
||||
ResourceManagerEndpoint: "https://management.azure.com/",
|
||||
ActiveDirectoryEndpoint: "https://login.microsoftonline.com/",
|
||||
GalleryEndpoint: "https://gallery.azure.com/",
|
||||
KeyVaultEndpoint: "https://vault.azure.net/",
|
||||
GraphEndpoint: "https://graph.windows.net/",
|
||||
StorageEndpointSuffix: "core.windows.net",
|
||||
SQLDatabaseDNSSuffix: "database.windows.net",
|
||||
TrafficManagerDNSSuffix: "trafficmanager.net",
|
||||
KeyVaultDNSSuffix: "vault.azure.net",
|
||||
ServiceBusEndpointSuffix: "servicebus.azure.com",
|
||||
ServiceManagementVMDNSSuffix: "cloudapp.net",
|
||||
ResourceManagerVMDNSSuffix: "cloudapp.azure.com",
|
||||
}
|
||||
|
||||
// USGovernmentCloud is the cloud environment for the US Government
|
||||
USGovernmentCloud = Environment{
|
||||
Name: "AzureUSGovernmentCloud",
|
||||
ManagementPortalURL: "https://manage.windowsazure.us/",
|
||||
PublishSettingsURL: "https://manage.windowsazure.us/publishsettings/index",
|
||||
ServiceManagementEndpoint: "https://management.core.usgovcloudapi.net/",
|
||||
ResourceManagerEndpoint: "https://management.usgovcloudapi.net/",
|
||||
ActiveDirectoryEndpoint: "https://login.microsoftonline.com/",
|
||||
GalleryEndpoint: "https://gallery.usgovcloudapi.net/",
|
||||
KeyVaultEndpoint: "https://vault.usgovcloudapi.net/",
|
||||
GraphEndpoint: "https://graph.usgovcloudapi.net/",
|
||||
StorageEndpointSuffix: "core.usgovcloudapi.net",
|
||||
SQLDatabaseDNSSuffix: "database.usgovcloudapi.net",
|
||||
TrafficManagerDNSSuffix: "usgovtrafficmanager.net",
|
||||
KeyVaultDNSSuffix: "vault.usgovcloudapi.net",
|
||||
ServiceBusEndpointSuffix: "servicebus.usgovcloudapi.net",
|
||||
ServiceManagementVMDNSSuffix: "usgovcloudapp.net",
|
||||
ResourceManagerVMDNSSuffix: "cloudapp.windowsazure.us",
|
||||
}
|
||||
|
||||
// ChinaCloud is the cloud environment operated in China
|
||||
ChinaCloud = Environment{
|
||||
Name: "AzureChinaCloud",
|
||||
ManagementPortalURL: "https://manage.chinacloudapi.com/",
|
||||
PublishSettingsURL: "https://manage.chinacloudapi.com/publishsettings/index",
|
||||
ServiceManagementEndpoint: "https://management.core.chinacloudapi.cn/",
|
||||
ResourceManagerEndpoint: "https://management.chinacloudapi.cn/",
|
||||
ActiveDirectoryEndpoint: "https://login.chinacloudapi.cn/?api-version=1.0",
|
||||
GalleryEndpoint: "https://gallery.chinacloudapi.cn/",
|
||||
KeyVaultEndpoint: "https://vault.azure.cn/",
|
||||
GraphEndpoint: "https://graph.chinacloudapi.cn/",
|
||||
StorageEndpointSuffix: "core.chinacloudapi.cn",
|
||||
SQLDatabaseDNSSuffix: "database.chinacloudapi.cn",
|
||||
TrafficManagerDNSSuffix: "trafficmanager.cn",
|
||||
KeyVaultDNSSuffix: "vault.azure.cn",
|
||||
ServiceBusEndpointSuffix: "servicebus.chinacloudapi.net",
|
||||
ServiceManagementVMDNSSuffix: "chinacloudapp.cn",
|
||||
ResourceManagerVMDNSSuffix: "cloudapp.azure.cn",
|
||||
}
|
||||
|
||||
// GermanCloud is the cloud environment operated in Germany
|
||||
GermanCloud = Environment{
|
||||
Name: "AzureGermanCloud",
|
||||
ManagementPortalURL: "http://portal.microsoftazure.de/",
|
||||
PublishSettingsURL: "https://manage.microsoftazure.de/publishsettings/index",
|
||||
ServiceManagementEndpoint: "https://management.core.cloudapi.de/",
|
||||
ResourceManagerEndpoint: "https://management.microsoftazure.de/",
|
||||
ActiveDirectoryEndpoint: "https://login.microsoftonline.de/",
|
||||
GalleryEndpoint: "https://gallery.cloudapi.de/",
|
||||
KeyVaultEndpoint: "https://vault.microsoftazure.de/",
|
||||
GraphEndpoint: "https://graph.cloudapi.de/",
|
||||
StorageEndpointSuffix: "core.cloudapi.de",
|
||||
SQLDatabaseDNSSuffix: "database.cloudapi.de",
|
||||
TrafficManagerDNSSuffix: "azuretrafficmanager.de",
|
||||
KeyVaultDNSSuffix: "vault.microsoftazure.de",
|
||||
ServiceBusEndpointSuffix: "servicebus.cloudapi.de",
|
||||
ServiceManagementVMDNSSuffix: "azurecloudapp.de",
|
||||
ResourceManagerVMDNSSuffix: "cloudapp.microsoftazure.de",
|
||||
}
|
||||
)
|
||||
|
||||
// EnvironmentFromName returns an Environment based on the common name specified
|
||||
func EnvironmentFromName(name string) (Environment, error) {
|
||||
name = strings.ToUpper(name)
|
||||
env, ok := environments[name]
|
||||
if !ok {
|
||||
return env, fmt.Errorf("autorest/azure: There is no cloud environment matching the name %q", name)
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
||||
// OAuthConfigForTenant returns an OAuthConfig with tenant specific urls
|
||||
func (env Environment) OAuthConfigForTenant(tenantID string) (*OAuthConfig, error) {
|
||||
return OAuthConfigForTenant(env.ActiveDirectoryEndpoint, tenantID)
|
||||
}
|
||||
|
||||
// OAuthConfigForTenant returns an OAuthConfig with tenant specific urls for target cloud auth endpoint
|
||||
func OAuthConfigForTenant(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) {
|
||||
template := "%s/oauth2/%s?api-version=%s"
|
||||
u, err := url.Parse(activeDirectoryEndpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authorizeURL, err := u.Parse(fmt.Sprintf(template, tenantID, "authorize", activeDirectoryAPIVersion))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenURL, err := u.Parse(fmt.Sprintf(template, tenantID, "token", activeDirectoryAPIVersion))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deviceCodeURL, err := u.Parse(fmt.Sprintf(template, tenantID, "devicecode", activeDirectoryAPIVersion))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &OAuthConfig{
|
||||
AuthorizeEndpoint: *authorizeURL,
|
||||
TokenEndpoint: *tokenURL,
|
||||
DeviceCodeEndpoint: *deviceCodeURL,
|
||||
}, nil
|
||||
}
|
||||
59
vendor/github.com/Azure/go-autorest/autorest/azure/persist.go
generated
vendored
59
vendor/github.com/Azure/go-autorest/autorest/azure/persist.go
generated
vendored
@@ -1,59 +0,0 @@
|
||||
package azure
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// LoadToken restores a Token object from a file located at 'path'.
|
||||
func LoadToken(path string) (*Token, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open file (%s) while loading token: %v", path, err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var token Token
|
||||
|
||||
dec := json.NewDecoder(file)
|
||||
if err = dec.Decode(&token); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode contents of file (%s) into Token representation: %v", path, err)
|
||||
}
|
||||
return &token, nil
|
||||
}
|
||||
|
||||
// SaveToken persists an oauth token at the given location on disk.
|
||||
// It moves the new file into place so it can safely be used to replace an existing file
|
||||
// that maybe accessed by multiple processes.
|
||||
func SaveToken(path string, mode os.FileMode, token Token) error {
|
||||
dir := filepath.Dir(path)
|
||||
err := os.MkdirAll(dir, os.ModePerm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create directory (%s) to store token in: %v", dir, err)
|
||||
}
|
||||
|
||||
newFile, err := ioutil.TempFile(dir, "token")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create the temp file to write the token: %v", err)
|
||||
}
|
||||
tempPath := newFile.Name()
|
||||
|
||||
if err := json.NewEncoder(newFile).Encode(token); err != nil {
|
||||
return fmt.Errorf("failed to encode token to file (%s) while saving token: %v", tempPath, err)
|
||||
}
|
||||
if err := newFile.Close(); err != nil {
|
||||
return fmt.Errorf("failed to close temp file %s: %v", tempPath, err)
|
||||
}
|
||||
|
||||
// Atomic replace to avoid multi-writer file corruptions
|
||||
if err := os.Rename(tempPath, path); err != nil {
|
||||
return fmt.Errorf("failed to move temporary token to desired output location. src=%s dst=%s: %v", tempPath, path, err)
|
||||
}
|
||||
if err := os.Chmod(path, mode); err != nil {
|
||||
return fmt.Errorf("failed to chmod the token file %s: %v", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
363
vendor/github.com/Azure/go-autorest/autorest/azure/token.go
generated
vendored
363
vendor/github.com/Azure/go-autorest/autorest/azure/token.go
generated
vendored
@@ -1,363 +0,0 @@
|
||||
package azure
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultRefresh = 5 * time.Minute
|
||||
tokenBaseDate = "1970-01-01T00:00:00Z"
|
||||
|
||||
// OAuthGrantTypeDeviceCode is the "grant_type" identifier used in device flow
|
||||
OAuthGrantTypeDeviceCode = "device_code"
|
||||
|
||||
// OAuthGrantTypeClientCredentials is the "grant_type" identifier used in credential flows
|
||||
OAuthGrantTypeClientCredentials = "client_credentials"
|
||||
|
||||
// OAuthGrantTypeRefreshToken is the "grant_type" identifier used in refresh token flows
|
||||
OAuthGrantTypeRefreshToken = "refresh_token"
|
||||
)
|
||||
|
||||
var expirationBase time.Time
|
||||
|
||||
func init() {
|
||||
expirationBase, _ = time.Parse(time.RFC3339, tokenBaseDate)
|
||||
}
|
||||
|
||||
// TokenRefreshCallback is the type representing callbacks that will be called after
|
||||
// a successful token refresh
|
||||
type TokenRefreshCallback func(Token) error
|
||||
|
||||
// Token encapsulates the access token used to authorize Azure requests.
|
||||
type Token struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
|
||||
ExpiresIn string `json:"expires_in"`
|
||||
ExpiresOn string `json:"expires_on"`
|
||||
NotBefore string `json:"not_before"`
|
||||
|
||||
Resource string `json:"resource"`
|
||||
Type string `json:"token_type"`
|
||||
}
|
||||
|
||||
// Expires returns the time.Time when the Token expires.
|
||||
func (t Token) Expires() time.Time {
|
||||
s, err := strconv.Atoi(t.ExpiresOn)
|
||||
if err != nil {
|
||||
s = -3600
|
||||
}
|
||||
return expirationBase.Add(time.Duration(s) * time.Second).UTC()
|
||||
}
|
||||
|
||||
// IsExpired returns true if the Token is expired, false otherwise.
|
||||
func (t Token) IsExpired() bool {
|
||||
return t.WillExpireIn(0)
|
||||
}
|
||||
|
||||
// WillExpireIn returns true if the Token will expire after the passed time.Duration interval
|
||||
// from now, false otherwise.
|
||||
func (t Token) WillExpireIn(d time.Duration) bool {
|
||||
return !t.Expires().After(time.Now().Add(d))
|
||||
}
|
||||
|
||||
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
|
||||
// value is "Bearer " followed by the AccessToken of the Token.
|
||||
func (t *Token) WithAuthorization() autorest.PrepareDecorator {
|
||||
return func(p autorest.Preparer) autorest.Preparer {
|
||||
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
return (autorest.WithBearerAuthorization(t.AccessToken)(p)).Prepare(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ServicePrincipalNoSecret represents a secret type that contains no secret
|
||||
// meaning it is not valid for fetching a fresh token. This is used by Manual
|
||||
type ServicePrincipalNoSecret struct {
|
||||
}
|
||||
|
||||
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret
|
||||
// It only returns an error for the ServicePrincipalNoSecret type
|
||||
func (noSecret *ServicePrincipalNoSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||
return fmt.Errorf("Manually created ServicePrincipalToken does not contain secret material to retrieve a new access token")
|
||||
}
|
||||
|
||||
// ServicePrincipalSecret is an interface that allows various secret mechanism to fill the form
|
||||
// that is submitted when acquiring an oAuth token.
|
||||
type ServicePrincipalSecret interface {
|
||||
SetAuthenticationValues(spt *ServicePrincipalToken, values *url.Values) error
|
||||
}
|
||||
|
||||
// ServicePrincipalTokenSecret implements ServicePrincipalSecret for client_secret type authorization.
|
||||
type ServicePrincipalTokenSecret struct {
|
||||
ClientSecret string
|
||||
}
|
||||
|
||||
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||
// It will populate the form submitted during oAuth Token Acquisition using the client_secret.
|
||||
func (tokenSecret *ServicePrincipalTokenSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||
v.Set("client_secret", tokenSecret.ClientSecret)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServicePrincipalCertificateSecret implements ServicePrincipalSecret for generic RSA cert auth with signed JWTs.
|
||||
type ServicePrincipalCertificateSecret struct {
|
||||
Certificate *x509.Certificate
|
||||
PrivateKey *rsa.PrivateKey
|
||||
}
|
||||
|
||||
// SignJwt returns the JWT signed with the certificate's private key.
|
||||
func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalToken) (string, error) {
|
||||
hasher := sha1.New()
|
||||
_, err := hasher.Write(secret.Certificate.Raw)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
thumbprint := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
|
||||
|
||||
// The jti (JWT ID) claim provides a unique identifier for the JWT.
|
||||
jti := make([]byte, 20)
|
||||
_, err = rand.Read(jti)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
token := jwt.New(jwt.SigningMethodRS256)
|
||||
token.Header["x5t"] = thumbprint
|
||||
token.Claims = jwt.MapClaims{
|
||||
"aud": spt.oauthConfig.TokenEndpoint.String(),
|
||||
"iss": spt.clientID,
|
||||
"sub": spt.clientID,
|
||||
"jti": base64.URLEncoding.EncodeToString(jti),
|
||||
"nbf": time.Now().Unix(),
|
||||
"exp": time.Now().Add(time.Hour * 24).Unix(),
|
||||
}
|
||||
|
||||
signedString, err := token.SignedString(secret.PrivateKey)
|
||||
return signedString, err
|
||||
}
|
||||
|
||||
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||
// It will populate the form submitted during oAuth Token Acquisition using a JWT signed with a certificate.
|
||||
func (secret *ServicePrincipalCertificateSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||
jwt, err := secret.SignJwt(spt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.Set("client_assertion", jwt)
|
||||
v.Set("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServicePrincipalToken encapsulates a Token created for a Service Principal.
|
||||
type ServicePrincipalToken struct {
|
||||
Token
|
||||
|
||||
secret ServicePrincipalSecret
|
||||
oauthConfig OAuthConfig
|
||||
clientID string
|
||||
resource string
|
||||
autoRefresh bool
|
||||
refreshWithin time.Duration
|
||||
sender autorest.Sender
|
||||
|
||||
refreshCallbacks []TokenRefreshCallback
|
||||
}
|
||||
|
||||
// NewServicePrincipalTokenWithSecret create a ServicePrincipalToken using the supplied ServicePrincipalSecret implementation.
|
||||
func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, resource string, secret ServicePrincipalSecret, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
spt := &ServicePrincipalToken{
|
||||
oauthConfig: oauthConfig,
|
||||
secret: secret,
|
||||
clientID: id,
|
||||
resource: resource,
|
||||
autoRefresh: true,
|
||||
refreshWithin: defaultRefresh,
|
||||
sender: &http.Client{},
|
||||
refreshCallbacks: callbacks,
|
||||
}
|
||||
return spt, nil
|
||||
}
|
||||
|
||||
// NewServicePrincipalTokenFromManualToken creates a ServicePrincipalToken using the supplied token
|
||||
func NewServicePrincipalTokenFromManualToken(oauthConfig OAuthConfig, clientID string, resource string, token Token, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
spt, err := NewServicePrincipalTokenWithSecret(
|
||||
oauthConfig,
|
||||
clientID,
|
||||
resource,
|
||||
&ServicePrincipalNoSecret{},
|
||||
callbacks...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spt.Token = token
|
||||
|
||||
return spt, nil
|
||||
}
|
||||
|
||||
// NewServicePrincipalToken creates a ServicePrincipalToken from the supplied Service Principal
|
||||
// credentials scoped to the named resource.
|
||||
func NewServicePrincipalToken(oauthConfig OAuthConfig, clientID string, secret string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
return NewServicePrincipalTokenWithSecret(
|
||||
oauthConfig,
|
||||
clientID,
|
||||
resource,
|
||||
&ServicePrincipalTokenSecret{
|
||||
ClientSecret: secret,
|
||||
},
|
||||
callbacks...,
|
||||
)
|
||||
}
|
||||
|
||||
// NewServicePrincipalTokenFromCertificate create a ServicePrincipalToken from the supplied pkcs12 bytes.
|
||||
func NewServicePrincipalTokenFromCertificate(oauthConfig OAuthConfig, clientID string, certificate *x509.Certificate, privateKey *rsa.PrivateKey, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
return NewServicePrincipalTokenWithSecret(
|
||||
oauthConfig,
|
||||
clientID,
|
||||
resource,
|
||||
&ServicePrincipalCertificateSecret{
|
||||
PrivateKey: privateKey,
|
||||
Certificate: certificate,
|
||||
},
|
||||
callbacks...,
|
||||
)
|
||||
}
|
||||
|
||||
// EnsureFresh will refresh the token if it will expire within the refresh window (as set by
|
||||
// RefreshWithin).
|
||||
func (spt *ServicePrincipalToken) EnsureFresh() error {
|
||||
if spt.WillExpireIn(spt.refreshWithin) {
|
||||
return spt.Refresh()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InvokeRefreshCallbacks calls any TokenRefreshCallbacks that were added to the SPT during initialization
|
||||
func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error {
|
||||
if spt.refreshCallbacks != nil {
|
||||
for _, callback := range spt.refreshCallbacks {
|
||||
err := callback(spt.Token)
|
||||
if err != nil {
|
||||
return autorest.NewErrorWithError(err,
|
||||
"azure.ServicePrincipalToken", "InvokeRefreshCallbacks", nil, "A TokenRefreshCallback handler returned an error")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Refresh obtains a fresh token for the Service Principal.
|
||||
func (spt *ServicePrincipalToken) Refresh() error {
|
||||
return spt.refreshInternal(spt.resource)
|
||||
}
|
||||
|
||||
// RefreshExchange refreshes the token, but for a different resource.
|
||||
func (spt *ServicePrincipalToken) RefreshExchange(resource string) error {
|
||||
return spt.refreshInternal(resource)
|
||||
}
|
||||
|
||||
func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
|
||||
v := url.Values{}
|
||||
v.Set("client_id", spt.clientID)
|
||||
v.Set("resource", resource)
|
||||
|
||||
if spt.RefreshToken != "" {
|
||||
v.Set("grant_type", OAuthGrantTypeRefreshToken)
|
||||
v.Set("refresh_token", spt.RefreshToken)
|
||||
} else {
|
||||
v.Set("grant_type", OAuthGrantTypeClientCredentials)
|
||||
err := spt.secret.SetAuthenticationValues(spt, &v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
req, _ := autorest.Prepare(&http.Request{},
|
||||
autorest.AsPost(),
|
||||
autorest.AsFormURLEncoded(),
|
||||
autorest.WithBaseURL(spt.oauthConfig.TokenEndpoint.String()),
|
||||
autorest.WithFormData(v))
|
||||
|
||||
resp, err := autorest.SendWithSender(spt.sender, req)
|
||||
if err != nil {
|
||||
return autorest.NewErrorWithError(err,
|
||||
"azure.ServicePrincipalToken", "Refresh", resp, "Failure sending request for Service Principal %s",
|
||||
spt.clientID)
|
||||
}
|
||||
|
||||
var newToken Token
|
||||
err = autorest.Respond(resp,
|
||||
autorest.WithErrorUnlessStatusCode(http.StatusOK),
|
||||
autorest.ByUnmarshallingJSON(&newToken),
|
||||
autorest.ByClosing())
|
||||
if err != nil {
|
||||
return autorest.NewErrorWithError(err,
|
||||
"azure.ServicePrincipalToken", "Refresh", resp, "Failure handling response to Service Principal %s request",
|
||||
spt.clientID)
|
||||
}
|
||||
|
||||
spt.Token = newToken
|
||||
|
||||
err = spt.InvokeRefreshCallbacks(newToken)
|
||||
if err != nil {
|
||||
// its already wrapped inside InvokeRefreshCallbacks
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetAutoRefresh enables or disables automatic refreshing of stale tokens.
|
||||
func (spt *ServicePrincipalToken) SetAutoRefresh(autoRefresh bool) {
|
||||
spt.autoRefresh = autoRefresh
|
||||
}
|
||||
|
||||
// SetRefreshWithin sets the interval within which if the token will expire, EnsureFresh will
|
||||
// refresh the token.
|
||||
func (spt *ServicePrincipalToken) SetRefreshWithin(d time.Duration) {
|
||||
spt.refreshWithin = d
|
||||
return
|
||||
}
|
||||
|
||||
// SetSender sets the autorest.Sender used when obtaining the Service Principal token. An
|
||||
// undecorated http.Client is used by default.
|
||||
func (spt *ServicePrincipalToken) SetSender(s autorest.Sender) {
|
||||
spt.sender = s
|
||||
}
|
||||
|
||||
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
|
||||
// value is "Bearer " followed by the AccessToken of the ServicePrincipalToken.
|
||||
//
|
||||
// By default, the token will automatically refresh if nearly expired (as determined by the
|
||||
// RefreshWithin interval). Use the AutoRefresh method to enable or disable automatically refreshing
|
||||
// tokens.
|
||||
func (spt *ServicePrincipalToken) WithAuthorization() autorest.PrepareDecorator {
|
||||
return func(p autorest.Preparer) autorest.Preparer {
|
||||
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
if spt.autoRefresh {
|
||||
err := spt.EnsureFresh()
|
||||
if err != nil {
|
||||
return r, autorest.NewErrorWithError(err,
|
||||
"azure.ServicePrincipalToken", "WithAuthorization", nil, "Failed to refresh Service Principal Token for request to %s",
|
||||
r.URL)
|
||||
}
|
||||
}
|
||||
return (autorest.WithBearerAuthorization(spt.AccessToken)(p)).Prepare(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
212
vendor/github.com/Azure/go-autorest/autorest/client.go
generated
vendored
212
vendor/github.com/Azure/go-autorest/autorest/client.go
generated
vendored
@@ -1,212 +0,0 @@
|
||||
package autorest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultPollingDelay is a reasonable delay between polling requests.
|
||||
DefaultPollingDelay = 60 * time.Second
|
||||
|
||||
// DefaultPollingDuration is a reasonable total polling duration.
|
||||
DefaultPollingDuration = 15 * time.Minute
|
||||
|
||||
// DefaultRetryAttempts is number of attempts for retry status codes (5xx).
|
||||
DefaultRetryAttempts = 3
|
||||
)
|
||||
|
||||
var statusCodesForRetry = []int{
|
||||
http.StatusRequestTimeout, // 408
|
||||
http.StatusInternalServerError, // 500
|
||||
http.StatusBadGateway, // 502
|
||||
http.StatusServiceUnavailable, // 503
|
||||
http.StatusGatewayTimeout, // 504
|
||||
}
|
||||
|
||||
const (
|
||||
requestFormat = `HTTP Request Begin ===================================================
|
||||
%s
|
||||
===================================================== HTTP Request End
|
||||
`
|
||||
responseFormat = `HTTP Response Begin ===================================================
|
||||
%s
|
||||
===================================================== HTTP Response End
|
||||
`
|
||||
)
|
||||
|
||||
// Response serves as the base for all responses from generated clients. It provides access to the
|
||||
// last http.Response.
|
||||
type Response struct {
|
||||
*http.Response `json:"-"`
|
||||
}
|
||||
|
||||
// LoggingInspector implements request and response inspectors that log the full request and
|
||||
// response to a supplied log.
|
||||
type LoggingInspector struct {
|
||||
Logger *log.Logger
|
||||
}
|
||||
|
||||
// WithInspection returns a PrepareDecorator that emits the http.Request to the supplied logger. The
|
||||
// body is restored after being emitted.
|
||||
//
|
||||
// Note: Since it reads the entire Body, this decorator should not be used where body streaming is
|
||||
// important. It is best used to trace JSON or similar body values.
|
||||
func (li LoggingInspector) WithInspection() PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
var body, b bytes.Buffer
|
||||
|
||||
defer r.Body.Close()
|
||||
|
||||
r.Body = ioutil.NopCloser(io.TeeReader(r.Body, &body))
|
||||
if err := r.Write(&b); err != nil {
|
||||
return nil, fmt.Errorf("Failed to write response: %v", err)
|
||||
}
|
||||
|
||||
li.Logger.Printf(requestFormat, b.String())
|
||||
|
||||
r.Body = ioutil.NopCloser(&body)
|
||||
return p.Prepare(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ByInspecting returns a RespondDecorator that emits the http.Response to the supplied logger. The
|
||||
// body is restored after being emitted.
|
||||
//
|
||||
// Note: Since it reads the entire Body, this decorator should not be used where body streaming is
|
||||
// important. It is best used to trace JSON or similar body values.
|
||||
func (li LoggingInspector) ByInspecting() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
var body, b bytes.Buffer
|
||||
defer resp.Body.Close()
|
||||
resp.Body = ioutil.NopCloser(io.TeeReader(resp.Body, &body))
|
||||
if err := resp.Write(&b); err != nil {
|
||||
return fmt.Errorf("Failed to write response: %v", err)
|
||||
}
|
||||
|
||||
li.Logger.Printf(responseFormat, b.String())
|
||||
|
||||
resp.Body = ioutil.NopCloser(&body)
|
||||
return r.Respond(resp)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Client is the base for autorest generated clients. It provides default, "do nothing"
|
||||
// implementations of an Authorizer, RequestInspector, and ResponseInspector. It also returns the
|
||||
// standard, undecorated http.Client as a default Sender.
|
||||
//
|
||||
// Generated clients should also use Error (see NewError and NewErrorWithError) for errors and
|
||||
// return responses that compose with Response.
|
||||
//
|
||||
// Most customization of generated clients is best achieved by supplying a custom Authorizer, custom
|
||||
// RequestInspector, and / or custom ResponseInspector. Users may log requests, implement circuit
|
||||
// breakers (see https://msdn.microsoft.com/en-us/library/dn589784.aspx) or otherwise influence
|
||||
// sending the request by providing a decorated Sender.
|
||||
type Client struct {
|
||||
Authorizer Authorizer
|
||||
Sender Sender
|
||||
RequestInspector PrepareDecorator
|
||||
ResponseInspector RespondDecorator
|
||||
|
||||
// PollingDelay sets the polling frequency used in absence of a Retry-After HTTP header
|
||||
PollingDelay time.Duration
|
||||
|
||||
// PollingDuration sets the maximum polling time after which an error is returned.
|
||||
PollingDuration time.Duration
|
||||
|
||||
// RetryAttempts sets the default number of retry attempts for client.
|
||||
RetryAttempts int
|
||||
|
||||
// RetryDuration sets the delay duration for retries.
|
||||
RetryDuration time.Duration
|
||||
|
||||
// UserAgent, if not empty, will be set as the HTTP User-Agent header on all requests sent
|
||||
// through the Do method.
|
||||
UserAgent string
|
||||
|
||||
Jar http.CookieJar
|
||||
}
|
||||
|
||||
// NewClientWithUserAgent returns an instance of a Client with the UserAgent set to the passed
|
||||
// string.
|
||||
func NewClientWithUserAgent(ua string) Client {
|
||||
return Client{
|
||||
PollingDelay: DefaultPollingDelay,
|
||||
PollingDuration: DefaultPollingDuration,
|
||||
RetryAttempts: DefaultRetryAttempts,
|
||||
RetryDuration: 30 * time.Second,
|
||||
UserAgent: ua,
|
||||
}
|
||||
}
|
||||
|
||||
// Do implements the Sender interface by invoking the active Sender after applying authorization.
|
||||
// If Sender is not set, it uses a new instance of http.Client. In both cases it will, if UserAgent
|
||||
// is set, apply set the User-Agent header.
|
||||
func (c Client) Do(r *http.Request) (*http.Response, error) {
|
||||
if r.UserAgent() == "" {
|
||||
r, _ = Prepare(r,
|
||||
WithUserAgent(c.UserAgent))
|
||||
}
|
||||
r, err := Prepare(r,
|
||||
c.WithInspection(),
|
||||
c.WithAuthorization())
|
||||
if err != nil {
|
||||
return nil, NewErrorWithError(err, "autorest/Client", "Do", nil, "Preparing request failed")
|
||||
}
|
||||
resp, err := SendWithSender(c.sender(), r,
|
||||
DoRetryForStatusCodes(c.RetryAttempts, c.RetryDuration, statusCodesForRetry...))
|
||||
Respond(resp,
|
||||
c.ByInspecting())
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// sender returns the Sender to which to send requests.
|
||||
func (c Client) sender() Sender {
|
||||
if c.Sender == nil {
|
||||
j, _ := cookiejar.New(nil)
|
||||
return &http.Client{Jar: j}
|
||||
}
|
||||
return c.Sender
|
||||
}
|
||||
|
||||
// WithAuthorization is a convenience method that returns the WithAuthorization PrepareDecorator
|
||||
// from the current Authorizer. If not Authorizer is set, it uses the NullAuthorizer.
|
||||
func (c Client) WithAuthorization() PrepareDecorator {
|
||||
return c.authorizer().WithAuthorization()
|
||||
}
|
||||
|
||||
// authorizer returns the Authorizer to use.
|
||||
func (c Client) authorizer() Authorizer {
|
||||
if c.Authorizer == nil {
|
||||
return NullAuthorizer{}
|
||||
}
|
||||
return c.Authorizer
|
||||
}
|
||||
|
||||
// WithInspection is a convenience method that passes the request to the supplied RequestInspector,
|
||||
// if present, or returns the WithNothing PrepareDecorator otherwise.
|
||||
func (c Client) WithInspection() PrepareDecorator {
|
||||
if c.RequestInspector == nil {
|
||||
return WithNothing()
|
||||
}
|
||||
return c.RequestInspector
|
||||
}
|
||||
|
||||
// ByInspecting is a convenience method that passes the response to the supplied ResponseInspector,
|
||||
// if present, or returns the ByIgnoring RespondDecorator otherwise.
|
||||
func (c Client) ByInspecting() RespondDecorator {
|
||||
if c.ResponseInspector == nil {
|
||||
return ByIgnoring()
|
||||
}
|
||||
return c.ResponseInspector
|
||||
}
|
||||
82
vendor/github.com/Azure/go-autorest/autorest/date/date.go
generated
vendored
82
vendor/github.com/Azure/go-autorest/autorest/date/date.go
generated
vendored
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
Package date provides time.Time derivatives that conform to the Swagger.io (https://swagger.io/)
|
||||
defined date formats: Date and DateTime. Both types may, in most cases, be used in lieu of
|
||||
time.Time types. And both convert to time.Time through a ToTime method.
|
||||
*/
|
||||
package date
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
fullDate = "2006-01-02"
|
||||
fullDateJSON = `"2006-01-02"`
|
||||
dateFormat = "%04d-%02d-%02d"
|
||||
jsonFormat = `"%04d-%02d-%02d"`
|
||||
)
|
||||
|
||||
// Date defines a type similar to time.Time but assumes a layout of RFC3339 full-date (i.e.,
|
||||
// 2006-01-02).
|
||||
type Date struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
// ParseDate create a new Date from the passed string.
|
||||
func ParseDate(date string) (d Date, err error) {
|
||||
return parseDate(date, fullDate)
|
||||
}
|
||||
|
||||
func parseDate(date string, format string) (Date, error) {
|
||||
d, err := time.Parse(format, date)
|
||||
return Date{Time: d}, err
|
||||
}
|
||||
|
||||
// MarshalBinary preserves the Date as a byte array conforming to RFC3339 full-date (i.e.,
|
||||
// 2006-01-02).
|
||||
func (d Date) MarshalBinary() ([]byte, error) {
|
||||
return d.MarshalText()
|
||||
}
|
||||
|
||||
// UnmarshalBinary reconstitutes a Date saved as a byte array conforming to RFC3339 full-date (i.e.,
|
||||
// 2006-01-02).
|
||||
func (d *Date) UnmarshalBinary(data []byte) error {
|
||||
return d.UnmarshalText(data)
|
||||
}
|
||||
|
||||
// MarshalJSON preserves the Date as a JSON string conforming to RFC3339 full-date (i.e.,
|
||||
// 2006-01-02).
|
||||
func (d Date) MarshalJSON() (json []byte, err error) {
|
||||
return []byte(fmt.Sprintf(jsonFormat, d.Year(), d.Month(), d.Day())), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON reconstitutes the Date from a JSON string conforming to RFC3339 full-date (i.e.,
|
||||
// 2006-01-02).
|
||||
func (d *Date) UnmarshalJSON(data []byte) (err error) {
|
||||
d.Time, err = time.Parse(fullDateJSON, string(data))
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalText preserves the Date as a byte array conforming to RFC3339 full-date (i.e.,
|
||||
// 2006-01-02).
|
||||
func (d Date) MarshalText() (text []byte, err error) {
|
||||
return []byte(fmt.Sprintf(dateFormat, d.Year(), d.Month(), d.Day())), nil
|
||||
}
|
||||
|
||||
// UnmarshalText reconstitutes a Date saved as a byte array conforming to RFC3339 full-date (i.e.,
|
||||
// 2006-01-02).
|
||||
func (d *Date) UnmarshalText(data []byte) (err error) {
|
||||
d.Time, err = time.Parse(fullDate, string(data))
|
||||
return err
|
||||
}
|
||||
|
||||
// String returns the Date formatted as an RFC3339 full-date string (i.e., 2006-01-02).
|
||||
func (d Date) String() string {
|
||||
return fmt.Sprintf(dateFormat, d.Year(), d.Month(), d.Day())
|
||||
}
|
||||
|
||||
// ToTime returns a Date as a time.Time
|
||||
func (d Date) ToTime() time.Time {
|
||||
return d.Time
|
||||
}
|
||||
89
vendor/github.com/Azure/go-autorest/autorest/date/time.go
generated
vendored
89
vendor/github.com/Azure/go-autorest/autorest/date/time.go
generated
vendored
@@ -1,89 +0,0 @@
|
||||
package date
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Azure reports time in UTC but it doesn't include the 'Z' time zone suffix in some cases.
|
||||
const (
|
||||
azureUtcFormatJSON = `"2006-01-02T15:04:05.999999999"`
|
||||
azureUtcFormat = "2006-01-02T15:04:05.999999999"
|
||||
rfc3339JSON = `"` + time.RFC3339Nano + `"`
|
||||
rfc3339 = time.RFC3339Nano
|
||||
tzOffsetRegex = `(Z|z|\+|-)(\d+:\d+)*"*$`
|
||||
)
|
||||
|
||||
// Time defines a type similar to time.Time but assumes a layout of RFC3339 date-time (i.e.,
|
||||
// 2006-01-02T15:04:05Z).
|
||||
type Time struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
// MarshalBinary preserves the Time as a byte array conforming to RFC3339 date-time (i.e.,
|
||||
// 2006-01-02T15:04:05Z).
|
||||
func (t Time) MarshalBinary() ([]byte, error) {
|
||||
return t.Time.MarshalText()
|
||||
}
|
||||
|
||||
// UnmarshalBinary reconstitutes a Time saved as a byte array conforming to RFC3339 date-time
|
||||
// (i.e., 2006-01-02T15:04:05Z).
|
||||
func (t *Time) UnmarshalBinary(data []byte) error {
|
||||
return t.UnmarshalText(data)
|
||||
}
|
||||
|
||||
// MarshalJSON preserves the Time as a JSON string conforming to RFC3339 date-time (i.e.,
|
||||
// 2006-01-02T15:04:05Z).
|
||||
func (t Time) MarshalJSON() (json []byte, err error) {
|
||||
return t.Time.MarshalJSON()
|
||||
}
|
||||
|
||||
// UnmarshalJSON reconstitutes the Time from a JSON string conforming to RFC3339 date-time
|
||||
// (i.e., 2006-01-02T15:04:05Z).
|
||||
func (t *Time) UnmarshalJSON(data []byte) (err error) {
|
||||
timeFormat := azureUtcFormatJSON
|
||||
match, err := regexp.Match(tzOffsetRegex, data)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if match {
|
||||
timeFormat = rfc3339JSON
|
||||
}
|
||||
t.Time, err = ParseTime(timeFormat, string(data))
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalText preserves the Time as a byte array conforming to RFC3339 date-time (i.e.,
|
||||
// 2006-01-02T15:04:05Z).
|
||||
func (t Time) MarshalText() (text []byte, err error) {
|
||||
return t.Time.MarshalText()
|
||||
}
|
||||
|
||||
// UnmarshalText reconstitutes a Time saved as a byte array conforming to RFC3339 date-time
|
||||
// (i.e., 2006-01-02T15:04:05Z).
|
||||
func (t *Time) UnmarshalText(data []byte) (err error) {
|
||||
timeFormat := azureUtcFormat
|
||||
match, err := regexp.Match(tzOffsetRegex, data)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if match {
|
||||
timeFormat = rfc3339
|
||||
}
|
||||
t.Time, err = ParseTime(timeFormat, string(data))
|
||||
return err
|
||||
}
|
||||
|
||||
// String returns the Time formatted as an RFC3339 date-time string (i.e.,
|
||||
// 2006-01-02T15:04:05Z).
|
||||
func (t Time) String() string {
|
||||
// Note: time.Time.String does not return an RFC3339 compliant string, time.Time.MarshalText does.
|
||||
b, err := t.MarshalText()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// ToTime returns a Time as a time.Time
|
||||
func (t Time) ToTime() time.Time {
|
||||
return t.Time
|
||||
}
|
||||
86
vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123.go
generated
vendored
86
vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123.go
generated
vendored
@@ -1,86 +0,0 @@
|
||||
package date
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
rfc1123JSON = `"` + time.RFC1123 + `"`
|
||||
rfc1123 = time.RFC1123
|
||||
)
|
||||
|
||||
// TimeRFC1123 defines a type similar to time.Time but assumes a layout of RFC1123 date-time (i.e.,
|
||||
// Mon, 02 Jan 2006 15:04:05 MST).
|
||||
type TimeRFC1123 struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
// UnmarshalJSON reconstitutes the Time from a JSON string conforming to RFC1123 date-time
|
||||
// (i.e., Mon, 02 Jan 2006 15:04:05 MST).
|
||||
func (t *TimeRFC1123) UnmarshalJSON(data []byte) (err error) {
|
||||
t.Time, err = ParseTime(rfc1123JSON, string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON preserves the Time as a JSON string conforming to RFC1123 date-time (i.e.,
|
||||
// Mon, 02 Jan 2006 15:04:05 MST).
|
||||
func (t TimeRFC1123) MarshalJSON() ([]byte, error) {
|
||||
if y := t.Year(); y < 0 || y >= 10000 {
|
||||
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
|
||||
}
|
||||
b := []byte(t.Format(rfc1123JSON))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// MarshalText preserves the Time as a byte array conforming to RFC1123 date-time (i.e.,
|
||||
// Mon, 02 Jan 2006 15:04:05 MST).
|
||||
func (t TimeRFC1123) MarshalText() ([]byte, error) {
|
||||
if y := t.Year(); y < 0 || y >= 10000 {
|
||||
return nil, errors.New("Time.MarshalText: year outside of range [0,9999]")
|
||||
}
|
||||
|
||||
b := []byte(t.Format(rfc1123))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// UnmarshalText reconstitutes a Time saved as a byte array conforming to RFC1123 date-time
|
||||
// (i.e., Mon, 02 Jan 2006 15:04:05 MST).
|
||||
func (t *TimeRFC1123) UnmarshalText(data []byte) (err error) {
|
||||
t.Time, err = ParseTime(rfc1123, string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary preserves the Time as a byte array conforming to RFC1123 date-time (i.e.,
|
||||
// Mon, 02 Jan 2006 15:04:05 MST).
|
||||
func (t TimeRFC1123) MarshalBinary() ([]byte, error) {
|
||||
return t.MarshalText()
|
||||
}
|
||||
|
||||
// UnmarshalBinary reconstitutes a Time saved as a byte array conforming to RFC1123 date-time
|
||||
// (i.e., Mon, 02 Jan 2006 15:04:05 MST).
|
||||
func (t *TimeRFC1123) UnmarshalBinary(data []byte) error {
|
||||
return t.UnmarshalText(data)
|
||||
}
|
||||
|
||||
// ToTime returns a Time as a time.Time
|
||||
func (t TimeRFC1123) ToTime() time.Time {
|
||||
return t.Time
|
||||
}
|
||||
|
||||
// String returns the Time formatted as an RFC1123 date-time string (i.e.,
|
||||
// Mon, 02 Jan 2006 15:04:05 MST).
|
||||
func (t TimeRFC1123) String() string {
|
||||
// Note: time.Time.String does not return an RFC1123 compliant string, time.Time.MarshalText does.
|
||||
b, err := t.MarshalText()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
11
vendor/github.com/Azure/go-autorest/autorest/date/utility.go
generated
vendored
11
vendor/github.com/Azure/go-autorest/autorest/date/utility.go
generated
vendored
@@ -1,11 +0,0 @@
|
||||
package date
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ParseTime to parse Time string to specified format.
|
||||
func ParseTime(format string, t string) (d time.Time, err error) {
|
||||
return time.Parse(format, strings.ToUpper(t))
|
||||
}
|
||||
80
vendor/github.com/Azure/go-autorest/autorest/error.go
generated
vendored
80
vendor/github.com/Azure/go-autorest/autorest/error.go
generated
vendored
@@ -1,80 +0,0 @@
|
||||
package autorest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
// UndefinedStatusCode is used when HTTP status code is not available for an error.
|
||||
UndefinedStatusCode = 0
|
||||
)
|
||||
|
||||
// DetailedError encloses a error with details of the package, method, and associated HTTP
|
||||
// status code (if any).
|
||||
type DetailedError struct {
|
||||
Original error
|
||||
|
||||
// PackageType is the package type of the object emitting the error. For types, the value
|
||||
// matches that produced the the '%T' format specifier of the fmt package. For other elements,
|
||||
// such as functions, it is just the package name (e.g., "autorest").
|
||||
PackageType string
|
||||
|
||||
// Method is the name of the method raising the error.
|
||||
Method string
|
||||
|
||||
// StatusCode is the HTTP Response StatusCode (if non-zero) that led to the error.
|
||||
StatusCode interface{}
|
||||
|
||||
// Message is the error message.
|
||||
Message string
|
||||
|
||||
// Service Error is the response body of failed API in bytes
|
||||
ServiceError []byte
|
||||
}
|
||||
|
||||
// NewError creates a new Error conforming object from the passed packageType, method, and
|
||||
// message. message is treated as a format string to which the optional args apply.
|
||||
func NewError(packageType string, method string, message string, args ...interface{}) DetailedError {
|
||||
return NewErrorWithError(nil, packageType, method, nil, message, args...)
|
||||
}
|
||||
|
||||
// NewErrorWithResponse creates a new Error conforming object from the passed
|
||||
// packageType, method, statusCode of the given resp (UndefinedStatusCode if
|
||||
// resp is nil), and message. message is treated as a format string to which the
|
||||
// optional args apply.
|
||||
func NewErrorWithResponse(packageType string, method string, resp *http.Response, message string, args ...interface{}) DetailedError {
|
||||
return NewErrorWithError(nil, packageType, method, resp, message, args...)
|
||||
}
|
||||
|
||||
// NewErrorWithError creates a new Error conforming object from the
|
||||
// passed packageType, method, statusCode of the given resp (UndefinedStatusCode
|
||||
// if resp is nil), message, and original error. message is treated as a format
|
||||
// string to which the optional args apply.
|
||||
func NewErrorWithError(original error, packageType string, method string, resp *http.Response, message string, args ...interface{}) DetailedError {
|
||||
if v, ok := original.(DetailedError); ok {
|
||||
return v
|
||||
}
|
||||
|
||||
statusCode := UndefinedStatusCode
|
||||
if resp != nil {
|
||||
statusCode = resp.StatusCode
|
||||
}
|
||||
|
||||
return DetailedError{
|
||||
Original: original,
|
||||
PackageType: packageType,
|
||||
Method: method,
|
||||
StatusCode: statusCode,
|
||||
Message: fmt.Sprintf(message, args...),
|
||||
}
|
||||
}
|
||||
|
||||
// Error returns a formatted containing all available details (i.e., PackageType, Method,
|
||||
// StatusCode, Message, and original error (if any)).
|
||||
func (e DetailedError) Error() string {
|
||||
if e.Original == nil {
|
||||
return fmt.Sprintf("%s#%s: %s: StatusCode=%d", e.PackageType, e.Method, e.Message, e.StatusCode)
|
||||
}
|
||||
return fmt.Sprintf("%s#%s: %s: StatusCode=%d -- Original Error: %v", e.PackageType, e.Method, e.Message, e.StatusCode, e.Original)
|
||||
}
|
||||
433
vendor/github.com/Azure/go-autorest/autorest/preparer.go
generated
vendored
433
vendor/github.com/Azure/go-autorest/autorest/preparer.go
generated
vendored
@@ -1,433 +0,0 @@
|
||||
package autorest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
mimeTypeJSON = "application/json"
|
||||
mimeTypeFormPost = "application/x-www-form-urlencoded"
|
||||
|
||||
headerAuthorization = "Authorization"
|
||||
headerContentType = "Content-Type"
|
||||
headerUserAgent = "User-Agent"
|
||||
)
|
||||
|
||||
// Preparer is the interface that wraps the Prepare method.
|
||||
//
|
||||
// Prepare accepts and possibly modifies an http.Request (e.g., adding Headers). Implementations
|
||||
// must ensure to not share or hold per-invocation state since Preparers may be shared and re-used.
|
||||
type Preparer interface {
|
||||
Prepare(*http.Request) (*http.Request, error)
|
||||
}
|
||||
|
||||
// PreparerFunc is a method that implements the Preparer interface.
|
||||
type PreparerFunc func(*http.Request) (*http.Request, error)
|
||||
|
||||
// Prepare implements the Preparer interface on PreparerFunc.
|
||||
func (pf PreparerFunc) Prepare(r *http.Request) (*http.Request, error) {
|
||||
return pf(r)
|
||||
}
|
||||
|
||||
// PrepareDecorator takes and possibly decorates, by wrapping, a Preparer. Decorators may affect the
|
||||
// http.Request and pass it along or, first, pass the http.Request along then affect the result.
|
||||
type PrepareDecorator func(Preparer) Preparer
|
||||
|
||||
// CreatePreparer creates, decorates, and returns a Preparer.
|
||||
// Without decorators, the returned Preparer returns the passed http.Request unmodified.
|
||||
// Preparers are safe to share and re-use.
|
||||
func CreatePreparer(decorators ...PrepareDecorator) Preparer {
|
||||
return DecoratePreparer(
|
||||
Preparer(PreparerFunc(func(r *http.Request) (*http.Request, error) { return r, nil })),
|
||||
decorators...)
|
||||
}
|
||||
|
||||
// DecoratePreparer accepts a Preparer and a, possibly empty, set of PrepareDecorators, which it
|
||||
// applies to the Preparer. Decorators are applied in the order received, but their affect upon the
|
||||
// request depends on whether they are a pre-decorator (change the http.Request and then pass it
|
||||
// along) or a post-decorator (pass the http.Request along and alter it on return).
|
||||
func DecoratePreparer(p Preparer, decorators ...PrepareDecorator) Preparer {
|
||||
for _, decorate := range decorators {
|
||||
p = decorate(p)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Prepare accepts an http.Request and a, possibly empty, set of PrepareDecorators.
|
||||
// It creates a Preparer from the decorators which it then applies to the passed http.Request.
|
||||
func Prepare(r *http.Request, decorators ...PrepareDecorator) (*http.Request, error) {
|
||||
if r == nil {
|
||||
return nil, NewError("autorest", "Prepare", "Invoked without an http.Request")
|
||||
}
|
||||
return CreatePreparer(decorators...).Prepare(r)
|
||||
}
|
||||
|
||||
// WithNothing returns a "do nothing" PrepareDecorator that makes no changes to the passed
|
||||
// http.Request.
|
||||
func WithNothing() PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
return p.Prepare(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeader returns a PrepareDecorator that sets the specified HTTP header of the http.Request to
|
||||
// the passed value. It canonicalizes the passed header name (via http.CanonicalHeaderKey) before
|
||||
// adding the header.
|
||||
func WithHeader(header string, value string) PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
if r.Header == nil {
|
||||
r.Header = make(http.Header)
|
||||
}
|
||||
r.Header.Set(http.CanonicalHeaderKey(header), value)
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithBearerAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
|
||||
// value is "Bearer " followed by the supplied token.
|
||||
func WithBearerAuthorization(token string) PrepareDecorator {
|
||||
return WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", token))
|
||||
}
|
||||
|
||||
// AsContentType returns a PrepareDecorator that adds an HTTP Content-Type header whose value
|
||||
// is the passed contentType.
|
||||
func AsContentType(contentType string) PrepareDecorator {
|
||||
return WithHeader(headerContentType, contentType)
|
||||
}
|
||||
|
||||
// WithUserAgent returns a PrepareDecorator that adds an HTTP User-Agent header whose value is the
|
||||
// passed string.
|
||||
func WithUserAgent(ua string) PrepareDecorator {
|
||||
return WithHeader(headerUserAgent, ua)
|
||||
}
|
||||
|
||||
// AsFormURLEncoded returns a PrepareDecorator that adds an HTTP Content-Type header whose value is
|
||||
// "application/x-www-form-urlencoded".
|
||||
func AsFormURLEncoded() PrepareDecorator {
|
||||
return AsContentType(mimeTypeFormPost)
|
||||
}
|
||||
|
||||
// AsJSON returns a PrepareDecorator that adds an HTTP Content-Type header whose value is
|
||||
// "application/json".
|
||||
func AsJSON() PrepareDecorator {
|
||||
return AsContentType(mimeTypeJSON)
|
||||
}
|
||||
|
||||
// WithMethod returns a PrepareDecorator that sets the HTTP method of the passed request. The
|
||||
// decorator does not validate that the passed method string is a known HTTP method.
|
||||
func WithMethod(method string) PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r.Method = method
|
||||
return p.Prepare(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// AsDelete returns a PrepareDecorator that sets the HTTP method to DELETE.
|
||||
func AsDelete() PrepareDecorator { return WithMethod("DELETE") }
|
||||
|
||||
// AsGet returns a PrepareDecorator that sets the HTTP method to GET.
|
||||
func AsGet() PrepareDecorator { return WithMethod("GET") }
|
||||
|
||||
// AsHead returns a PrepareDecorator that sets the HTTP method to HEAD.
|
||||
func AsHead() PrepareDecorator { return WithMethod("HEAD") }
|
||||
|
||||
// AsOptions returns a PrepareDecorator that sets the HTTP method to OPTIONS.
|
||||
func AsOptions() PrepareDecorator { return WithMethod("OPTIONS") }
|
||||
|
||||
// AsPatch returns a PrepareDecorator that sets the HTTP method to PATCH.
|
||||
func AsPatch() PrepareDecorator { return WithMethod("PATCH") }
|
||||
|
||||
// AsPost returns a PrepareDecorator that sets the HTTP method to POST.
|
||||
func AsPost() PrepareDecorator { return WithMethod("POST") }
|
||||
|
||||
// AsPut returns a PrepareDecorator that sets the HTTP method to PUT.
|
||||
func AsPut() PrepareDecorator { return WithMethod("PUT") }
|
||||
|
||||
// WithBaseURL returns a PrepareDecorator that populates the http.Request with a url.URL constructed
|
||||
// from the supplied baseUrl.
|
||||
func WithBaseURL(baseURL string) PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
var u *url.URL
|
||||
if u, err = url.Parse(baseURL); err != nil {
|
||||
return r, err
|
||||
}
|
||||
if u.Scheme == "" {
|
||||
err = fmt.Errorf("autorest: No scheme detected in URL %s", baseURL)
|
||||
}
|
||||
if err == nil {
|
||||
r.URL = u
|
||||
}
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) into the
|
||||
// http.Request body.
|
||||
func WithFormData(v url.Values) PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
s := v.Encode()
|
||||
r.ContentLength = int64(len(s))
|
||||
r.Body = ioutil.NopCloser(strings.NewReader(s))
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithMultiPartFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) form parameters
|
||||
// into the http.Request body.
|
||||
func WithMultiPartFormData(formDataParameters map[string]interface{}) PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
var body bytes.Buffer
|
||||
writer := multipart.NewWriter(&body)
|
||||
for key, value := range formDataParameters {
|
||||
if rc, ok := value.(io.ReadCloser); ok {
|
||||
var fd io.Writer
|
||||
if fd, err = writer.CreateFormFile(key, key); err != nil {
|
||||
return r, err
|
||||
}
|
||||
if _, err = io.Copy(fd, rc); err != nil {
|
||||
return r, err
|
||||
}
|
||||
} else {
|
||||
if err = writer.WriteField(key, ensureValueString(value)); err != nil {
|
||||
return r, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err = writer.Close(); err != nil {
|
||||
return r, err
|
||||
}
|
||||
if r.Header == nil {
|
||||
r.Header = make(http.Header)
|
||||
}
|
||||
r.Header.Set(http.CanonicalHeaderKey(headerContentType), writer.FormDataContentType())
|
||||
r.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))
|
||||
r.ContentLength = int64(body.Len())
|
||||
return r, err
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithFile returns a PrepareDecorator that sends file in request body.
|
||||
func WithFile(f io.ReadCloser) PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
b, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
r.Body = ioutil.NopCloser(bytes.NewReader(b))
|
||||
r.ContentLength = int64(len(b))
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithBool returns a PrepareDecorator that encodes the passed bool into the body of the request
|
||||
// and sets the Content-Length header.
|
||||
func WithBool(v bool) PrepareDecorator {
|
||||
return WithString(fmt.Sprintf("%v", v))
|
||||
}
|
||||
|
||||
// WithFloat32 returns a PrepareDecorator that encodes the passed float32 into the body of the
|
||||
// request and sets the Content-Length header.
|
||||
func WithFloat32(v float32) PrepareDecorator {
|
||||
return WithString(fmt.Sprintf("%v", v))
|
||||
}
|
||||
|
||||
// WithFloat64 returns a PrepareDecorator that encodes the passed float64 into the body of the
|
||||
// request and sets the Content-Length header.
|
||||
func WithFloat64(v float64) PrepareDecorator {
|
||||
return WithString(fmt.Sprintf("%v", v))
|
||||
}
|
||||
|
||||
// WithInt32 returns a PrepareDecorator that encodes the passed int32 into the body of the request
|
||||
// and sets the Content-Length header.
|
||||
func WithInt32(v int32) PrepareDecorator {
|
||||
return WithString(fmt.Sprintf("%v", v))
|
||||
}
|
||||
|
||||
// WithInt64 returns a PrepareDecorator that encodes the passed int64 into the body of the request
|
||||
// and sets the Content-Length header.
|
||||
func WithInt64(v int64) PrepareDecorator {
|
||||
return WithString(fmt.Sprintf("%v", v))
|
||||
}
|
||||
|
||||
// WithString returns a PrepareDecorator that encodes the passed string into the body of the request
|
||||
// and sets the Content-Length header.
|
||||
func WithString(v string) PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
r.ContentLength = int64(len(v))
|
||||
r.Body = ioutil.NopCloser(strings.NewReader(v))
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithJSON returns a PrepareDecorator that encodes the data passed as JSON into the body of the
|
||||
// request and sets the Content-Length header.
|
||||
func WithJSON(v interface{}) PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
b, err := json.Marshal(v)
|
||||
if err == nil {
|
||||
r.ContentLength = int64(len(b))
|
||||
r.Body = ioutil.NopCloser(bytes.NewReader(b))
|
||||
}
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithPath returns a PrepareDecorator that adds the supplied path to the request URL. If the path
|
||||
// is absolute (that is, it begins with a "/"), it replaces the existing path.
|
||||
func WithPath(path string) PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
if r.URL == nil {
|
||||
return r, NewError("autorest", "WithPath", "Invoked with a nil URL")
|
||||
}
|
||||
if r.URL, err = parseURL(r.URL, path); err != nil {
|
||||
return r, err
|
||||
}
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithEscapedPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the
|
||||
// request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map. The
|
||||
// values will be escaped (aka URL encoded) before insertion into the path.
|
||||
func WithEscapedPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator {
|
||||
parameters := escapeValueStrings(ensureValueStrings(pathParameters))
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
if r.URL == nil {
|
||||
return r, NewError("autorest", "WithEscapedPathParameters", "Invoked with a nil URL")
|
||||
}
|
||||
for key, value := range parameters {
|
||||
path = strings.Replace(path, "{"+key+"}", value, -1)
|
||||
}
|
||||
if r.URL, err = parseURL(r.URL, path); err != nil {
|
||||
return r, err
|
||||
}
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the
|
||||
// request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map.
|
||||
func WithPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator {
|
||||
parameters := ensureValueStrings(pathParameters)
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
if r.URL == nil {
|
||||
return r, NewError("autorest", "WithPathParameters", "Invoked with a nil URL")
|
||||
}
|
||||
for key, value := range parameters {
|
||||
path = strings.Replace(path, "{"+key+"}", value, -1)
|
||||
}
|
||||
|
||||
if r.URL, err = parseURL(r.URL, path); err != nil {
|
||||
return r, err
|
||||
}
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func parseURL(u *url.URL, path string) (*url.URL, error) {
|
||||
p := strings.TrimRight(u.String(), "/")
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
return url.Parse(p + path)
|
||||
}
|
||||
|
||||
// WithQueryParameters returns a PrepareDecorators that encodes and applies the query parameters
|
||||
// given in the supplied map (i.e., key=value).
|
||||
func WithQueryParameters(queryParameters map[string]interface{}) PrepareDecorator {
|
||||
parameters := ensureValueStrings(queryParameters)
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
if r.URL == nil {
|
||||
return r, NewError("autorest", "WithQueryParameters", "Invoked with a nil URL")
|
||||
}
|
||||
v := r.URL.Query()
|
||||
for key, value := range parameters {
|
||||
v.Add(key, value)
|
||||
}
|
||||
r.URL.RawQuery = createQuery(v)
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Authorizer is the interface that provides a PrepareDecorator used to supply request
|
||||
// authorization. Most often, the Authorizer decorator runs last so it has access to the full
|
||||
// state of the formed HTTP request.
|
||||
type Authorizer interface {
|
||||
WithAuthorization() PrepareDecorator
|
||||
}
|
||||
|
||||
// NullAuthorizer implements a default, "do nothing" Authorizer.
|
||||
type NullAuthorizer struct{}
|
||||
|
||||
// WithAuthorization returns a PrepareDecorator that does nothing.
|
||||
func (na NullAuthorizer) WithAuthorization() PrepareDecorator {
|
||||
return WithNothing()
|
||||
}
|
||||
215
vendor/github.com/Azure/go-autorest/autorest/responder.go
generated
vendored
215
vendor/github.com/Azure/go-autorest/autorest/responder.go
generated
vendored
@@ -1,215 +0,0 @@
|
||||
package autorest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Responder is the interface that wraps the Respond method.
|
||||
//
|
||||
// Respond accepts and reacts to an http.Response. Implementations must ensure to not share or hold
|
||||
// state since Responders may be shared and re-used.
|
||||
type Responder interface {
|
||||
Respond(*http.Response) error
|
||||
}
|
||||
|
||||
// ResponderFunc is a method that implements the Responder interface.
|
||||
type ResponderFunc func(*http.Response) error
|
||||
|
||||
// Respond implements the Responder interface on ResponderFunc.
|
||||
func (rf ResponderFunc) Respond(r *http.Response) error {
|
||||
return rf(r)
|
||||
}
|
||||
|
||||
// RespondDecorator takes and possibly decorates, by wrapping, a Responder. Decorators may react to
|
||||
// the http.Response and pass it along or, first, pass the http.Response along then react.
|
||||
type RespondDecorator func(Responder) Responder
|
||||
|
||||
// CreateResponder creates, decorates, and returns a Responder. Without decorators, the returned
|
||||
// Responder returns the passed http.Response unmodified. Responders may or may not be safe to share
|
||||
// and re-used: It depends on the applied decorators. For example, a standard decorator that closes
|
||||
// the response body is fine to share whereas a decorator that reads the body into a passed struct
|
||||
// is not.
|
||||
//
|
||||
// To prevent memory leaks, ensure that at least one Responder closes the response body.
|
||||
func CreateResponder(decorators ...RespondDecorator) Responder {
|
||||
return DecorateResponder(
|
||||
Responder(ResponderFunc(func(r *http.Response) error { return nil })),
|
||||
decorators...)
|
||||
}
|
||||
|
||||
// DecorateResponder accepts a Responder and a, possibly empty, set of RespondDecorators, which it
|
||||
// applies to the Responder. Decorators are applied in the order received, but their affect upon the
|
||||
// request depends on whether they are a pre-decorator (react to the http.Response and then pass it
|
||||
// along) or a post-decorator (pass the http.Response along and then react).
|
||||
func DecorateResponder(r Responder, decorators ...RespondDecorator) Responder {
|
||||
for _, decorate := range decorators {
|
||||
r = decorate(r)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Respond accepts an http.Response and a, possibly empty, set of RespondDecorators.
|
||||
// It creates a Responder from the decorators it then applies to the passed http.Response.
|
||||
func Respond(r *http.Response, decorators ...RespondDecorator) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return CreateResponder(decorators...).Respond(r)
|
||||
}
|
||||
|
||||
// ByIgnoring returns a RespondDecorator that ignores the passed http.Response passing it unexamined
|
||||
// to the next RespondDecorator.
|
||||
func ByIgnoring() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
return r.Respond(resp)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ByCopying copies the contents of the http.Response Body into the passed bytes.Buffer as
|
||||
// the Body is read.
|
||||
func ByCopying(b *bytes.Buffer) RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
err := r.Respond(resp)
|
||||
if err == nil && resp != nil && resp.Body != nil {
|
||||
resp.Body = TeeReadCloser(resp.Body, b)
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ByClosing returns a RespondDecorator that first invokes the passed Responder after which it
|
||||
// closes the response body. Since the passed Responder is invoked prior to closing the response
|
||||
// body, the decorator may occur anywhere within the set.
|
||||
func ByClosing() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
err := r.Respond(resp)
|
||||
if resp != nil && resp.Body != nil {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
return fmt.Errorf("Error closing the response body: %v", err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ByClosingIfError returns a RespondDecorator that first invokes the passed Responder after which
|
||||
// it closes the response if the passed Responder returns an error and the response body exists.
|
||||
func ByClosingIfError() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
err := r.Respond(resp)
|
||||
if err != nil && resp != nil && resp.Body != nil {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
return fmt.Errorf("Error closing the response body: %v", err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ByUnmarshallingJSON returns a RespondDecorator that decodes a JSON document returned in the
|
||||
// response Body into the value pointed to by v.
|
||||
func ByUnmarshallingJSON(v interface{}) RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
err := r.Respond(resp)
|
||||
if err == nil {
|
||||
b, errInner := ioutil.ReadAll(resp.Body)
|
||||
if errInner != nil {
|
||||
err = fmt.Errorf("Error occurred reading http.Response#Body - Error = '%v'", errInner)
|
||||
} else if len(strings.Trim(string(b), " ")) > 0 {
|
||||
errInner = json.Unmarshal(b, v)
|
||||
if errInner != nil {
|
||||
err = fmt.Errorf("Error occurred unmarshalling JSON - Error = '%v' JSON = '%s'", errInner, string(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ByUnmarshallingXML returns a RespondDecorator that decodes a XML document returned in the
|
||||
// response Body into the value pointed to by v.
|
||||
func ByUnmarshallingXML(v interface{}) RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
err := r.Respond(resp)
|
||||
if err == nil {
|
||||
b, errInner := ioutil.ReadAll(resp.Body)
|
||||
if errInner != nil {
|
||||
err = fmt.Errorf("Error occurred reading http.Response#Body - Error = '%v'", errInner)
|
||||
} else {
|
||||
errInner = xml.Unmarshal(b, v)
|
||||
if errInner != nil {
|
||||
err = fmt.Errorf("Error occurred unmarshalling Xml - Error = '%v' Xml = '%s'", errInner, string(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithErrorUnlessStatusCode returns a RespondDecorator that emits an error unless the response
|
||||
// StatusCode is among the set passed. On error, response body is fully read into a buffer and
|
||||
// presented in the returned error, as well as in the response body.
|
||||
func WithErrorUnlessStatusCode(codes ...int) RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
err := r.Respond(resp)
|
||||
if err == nil && !ResponseHasStatusCode(resp, codes...) {
|
||||
derr := NewErrorWithResponse("autorest", "WithErrorUnlessStatusCode", resp, "%v %v failed with %s",
|
||||
resp.Request.Method,
|
||||
resp.Request.URL,
|
||||
resp.Status)
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
b, _ := ioutil.ReadAll(resp.Body)
|
||||
derr.ServiceError = b
|
||||
resp.Body = ioutil.NopCloser(bytes.NewReader(b))
|
||||
}
|
||||
err = derr
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithErrorUnlessOK returns a RespondDecorator that emits an error if the response StatusCode is
|
||||
// anything other than HTTP 200.
|
||||
func WithErrorUnlessOK() RespondDecorator {
|
||||
return WithErrorUnlessStatusCode(http.StatusOK)
|
||||
}
|
||||
|
||||
// ExtractHeader extracts all values of the specified header from the http.Response. It returns an
|
||||
// empty string slice if the passed http.Response is nil or the header does not exist.
|
||||
func ExtractHeader(header string, resp *http.Response) []string {
|
||||
if resp != nil && resp.Header != nil {
|
||||
return resp.Header[http.CanonicalHeaderKey(header)]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtractHeaderValue extracts the first value of the specified header from the http.Response. It
|
||||
// returns an empty string if the passed http.Response is nil or the header does not exist.
|
||||
func ExtractHeaderValue(header string, resp *http.Response) string {
|
||||
h := ExtractHeader(header, resp)
|
||||
if len(h) > 0 {
|
||||
return h[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
269
vendor/github.com/Azure/go-autorest/autorest/sender.go
generated
vendored
269
vendor/github.com/Azure/go-autorest/autorest/sender.go
generated
vendored
@@ -1,269 +0,0 @@
|
||||
package autorest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Sender is the interface that wraps the Do method to send HTTP requests.
|
||||
//
|
||||
// The standard http.Client conforms to this interface.
|
||||
type Sender interface {
|
||||
Do(*http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// SenderFunc is a method that implements the Sender interface.
|
||||
type SenderFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
// Do implements the Sender interface on SenderFunc.
|
||||
func (sf SenderFunc) Do(r *http.Request) (*http.Response, error) {
|
||||
return sf(r)
|
||||
}
|
||||
|
||||
// SendDecorator takes and possibily decorates, by wrapping, a Sender. Decorators may affect the
|
||||
// http.Request and pass it along or, first, pass the http.Request along then react to the
|
||||
// http.Response result.
|
||||
type SendDecorator func(Sender) Sender
|
||||
|
||||
// CreateSender creates, decorates, and returns, as a Sender, the default http.Client.
|
||||
func CreateSender(decorators ...SendDecorator) Sender {
|
||||
return DecorateSender(&http.Client{}, decorators...)
|
||||
}
|
||||
|
||||
// DecorateSender accepts a Sender and a, possibly empty, set of SendDecorators, which is applies to
|
||||
// the Sender. Decorators are applied in the order received, but their affect upon the request
|
||||
// depends on whether they are a pre-decorator (change the http.Request and then pass it along) or a
|
||||
// post-decorator (pass the http.Request along and react to the results in http.Response).
|
||||
func DecorateSender(s Sender, decorators ...SendDecorator) Sender {
|
||||
for _, decorate := range decorators {
|
||||
s = decorate(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Send sends, by means of the default http.Client, the passed http.Request, returning the
|
||||
// http.Response and possible error. It also accepts a, possibly empty, set of SendDecorators which
|
||||
// it will apply the http.Client before invoking the Do method.
|
||||
//
|
||||
// Send is a convenience method and not recommended for production. Advanced users should use
|
||||
// SendWithSender, passing and sharing their own Sender (e.g., instance of http.Client).
|
||||
//
|
||||
// Send will not poll or retry requests.
|
||||
func Send(r *http.Request, decorators ...SendDecorator) (*http.Response, error) {
|
||||
return SendWithSender(&http.Client{}, r, decorators...)
|
||||
}
|
||||
|
||||
// SendWithSender sends the passed http.Request, through the provided Sender, returning the
|
||||
// http.Response and possible error. It also accepts a, possibly empty, set of SendDecorators which
|
||||
// it will apply the http.Client before invoking the Do method.
|
||||
//
|
||||
// SendWithSender will not poll or retry requests.
|
||||
func SendWithSender(s Sender, r *http.Request, decorators ...SendDecorator) (*http.Response, error) {
|
||||
return DecorateSender(s, decorators...).Do(r)
|
||||
}
|
||||
|
||||
// AfterDelay returns a SendDecorator that delays for the passed time.Duration before
|
||||
// invoking the Sender. The delay may be terminated by closing the optional channel on the
|
||||
// http.Request. If canceled, no further Senders are invoked.
|
||||
func AfterDelay(d time.Duration) SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if !DelayForBackoff(d, 0, r.Cancel) {
|
||||
return nil, fmt.Errorf("autorest: AfterDelay canceled before full delay")
|
||||
}
|
||||
return s.Do(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// AsIs returns a SendDecorator that invokes the passed Sender without modifying the http.Request.
|
||||
func AsIs() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
return s.Do(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// DoCloseIfError returns a SendDecorator that first invokes the passed Sender after which
|
||||
// it closes the response if the passed Sender returns an error and the response body exists.
|
||||
func DoCloseIfError() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
resp, err := s.Do(r)
|
||||
if err != nil {
|
||||
Respond(resp, ByClosing())
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// DoErrorIfStatusCode returns a SendDecorator that emits an error if the response StatusCode is
|
||||
// among the set passed. Since these are artificial errors, the response body may still require
|
||||
// closing.
|
||||
func DoErrorIfStatusCode(codes ...int) SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
resp, err := s.Do(r)
|
||||
if err == nil && ResponseHasStatusCode(resp, codes...) {
|
||||
err = NewErrorWithResponse("autorest", "DoErrorIfStatusCode", resp, "%v %v failed with %s",
|
||||
resp.Request.Method,
|
||||
resp.Request.URL,
|
||||
resp.Status)
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// DoErrorUnlessStatusCode returns a SendDecorator that emits an error unless the response
|
||||
// StatusCode is among the set passed. Since these are artificial errors, the response body
|
||||
// may still require closing.
|
||||
func DoErrorUnlessStatusCode(codes ...int) SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
resp, err := s.Do(r)
|
||||
if err == nil && !ResponseHasStatusCode(resp, codes...) {
|
||||
err = NewErrorWithResponse("autorest", "DoErrorUnlessStatusCode", resp, "%v %v failed with %s",
|
||||
resp.Request.Method,
|
||||
resp.Request.URL,
|
||||
resp.Status)
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// DoPollForStatusCodes returns a SendDecorator that polls if the http.Response contains one of the
|
||||
// passed status codes. It expects the http.Response to contain a Location header providing the
|
||||
// URL at which to poll (using GET) and will poll until the time passed is equal to or greater than
|
||||
// the supplied duration. It will delay between requests for the duration specified in the
|
||||
// RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled by
|
||||
// closing the optional channel on the http.Request.
|
||||
func DoPollForStatusCodes(duration time.Duration, delay time.Duration, codes ...int) SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
|
||||
resp, err = s.Do(r)
|
||||
|
||||
if err == nil && ResponseHasStatusCode(resp, codes...) {
|
||||
r, err = NewPollingRequest(resp, r.Cancel)
|
||||
|
||||
for err == nil && ResponseHasStatusCode(resp, codes...) {
|
||||
Respond(resp,
|
||||
ByClosing())
|
||||
resp, err = SendWithSender(s, r,
|
||||
AfterDelay(GetRetryAfter(resp, delay)))
|
||||
}
|
||||
}
|
||||
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// DoRetryForAttempts returns a SendDecorator that retries a failed request for up to the specified
|
||||
// number of attempts, exponentially backing off between requests using the supplied backoff
|
||||
// time.Duration (which may be zero). Retrying may be canceled by closing the optional channel on
|
||||
// the http.Request.
|
||||
func DoRetryForAttempts(attempts int, backoff time.Duration) SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
|
||||
for attempt := 0; attempt < attempts; attempt++ {
|
||||
resp, err = s.Do(r)
|
||||
if err == nil {
|
||||
return resp, err
|
||||
}
|
||||
DelayForBackoff(backoff, attempt, r.Cancel)
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// DoRetryForStatusCodes returns a SendDecorator that retries for specified statusCodes for up to the specified
|
||||
// number of attempts, exponentially backing off between requests using the supplied backoff
|
||||
// time.Duration (which may be zero). Retrying may be canceled by closing the optional channel on
|
||||
// the http.Request.
|
||||
func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
|
||||
b := []byte{}
|
||||
if r.Body != nil {
|
||||
b, err = ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
|
||||
// Increment to add the first call (attempts denotes number of retries)
|
||||
attempts++
|
||||
for attempt := 0; attempt < attempts; attempt++ {
|
||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(b))
|
||||
resp, err = s.Do(r)
|
||||
if err != nil || !ResponseHasStatusCode(resp, codes...) {
|
||||
return resp, err
|
||||
}
|
||||
DelayForBackoff(backoff, attempt, r.Cancel)
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// DoRetryForDuration returns a SendDecorator that retries the request until the total time is equal
|
||||
// to or greater than the specified duration, exponentially backing off between requests using the
|
||||
// supplied backoff time.Duration (which may be zero). Retrying may be canceled by closing the
|
||||
// optional channel on the http.Request.
|
||||
func DoRetryForDuration(d time.Duration, backoff time.Duration) SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
|
||||
end := time.Now().Add(d)
|
||||
for attempt := 0; time.Now().Before(end); attempt++ {
|
||||
resp, err = s.Do(r)
|
||||
if err == nil {
|
||||
return resp, err
|
||||
}
|
||||
DelayForBackoff(backoff, attempt, r.Cancel)
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogging returns a SendDecorator that implements simple before and after logging of the
|
||||
// request.
|
||||
func WithLogging(logger *log.Logger) SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
logger.Printf("Sending %s %s", r.Method, r.URL)
|
||||
resp, err := s.Do(r)
|
||||
if err != nil {
|
||||
logger.Printf("%s %s received error '%v'", r.Method, r.URL, err)
|
||||
} else {
|
||||
logger.Printf("%s %s received %s", r.Method, r.URL, resp.Status)
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// DelayForBackoff invokes time.After for the supplied backoff duration raised to the power of
|
||||
// passed attempt (i.e., an exponential backoff delay). Backoff duration is in seconds and can set
|
||||
// to zero for no delay. The delay may be canceled by closing the passed channel. If terminated early,
|
||||
// returns false.
|
||||
// Note: Passing attempt 1 will result in doubling "backoff" duration. Treat this as a zero-based attempt
|
||||
// count.
|
||||
func DelayForBackoff(backoff time.Duration, attempt int, cancel <-chan struct{}) bool {
|
||||
select {
|
||||
case <-time.After(time.Duration(backoff.Seconds()*math.Pow(2, float64(attempt))) * time.Second):
|
||||
return true
|
||||
case <-cancel:
|
||||
return false
|
||||
}
|
||||
}
|
||||
178
vendor/github.com/Azure/go-autorest/autorest/utility.go
generated
vendored
178
vendor/github.com/Azure/go-autorest/autorest/utility.go
generated
vendored
@@ -1,178 +0,0 @@
|
||||
package autorest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// EncodedAs is a series of constants specifying various data encodings
|
||||
type EncodedAs string
|
||||
|
||||
const (
|
||||
// EncodedAsJSON states that data is encoded as JSON
|
||||
EncodedAsJSON EncodedAs = "JSON"
|
||||
|
||||
// EncodedAsXML states that data is encoded as Xml
|
||||
EncodedAsXML EncodedAs = "XML"
|
||||
)
|
||||
|
||||
// Decoder defines the decoding method json.Decoder and xml.Decoder share
|
||||
type Decoder interface {
|
||||
Decode(v interface{}) error
|
||||
}
|
||||
|
||||
// NewDecoder creates a new decoder appropriate to the passed encoding.
|
||||
// encodedAs specifies the type of encoding and r supplies the io.Reader containing the
|
||||
// encoded data.
|
||||
func NewDecoder(encodedAs EncodedAs, r io.Reader) Decoder {
|
||||
if encodedAs == EncodedAsJSON {
|
||||
return json.NewDecoder(r)
|
||||
} else if encodedAs == EncodedAsXML {
|
||||
return xml.NewDecoder(r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CopyAndDecode decodes the data from the passed io.Reader while making a copy. Having a copy
|
||||
// is especially useful if there is a chance the data will fail to decode.
|
||||
// encodedAs specifies the expected encoding, r provides the io.Reader to the data, and v
|
||||
// is the decoding destination.
|
||||
func CopyAndDecode(encodedAs EncodedAs, r io.Reader, v interface{}) (bytes.Buffer, error) {
|
||||
b := bytes.Buffer{}
|
||||
return b, NewDecoder(encodedAs, io.TeeReader(r, &b)).Decode(v)
|
||||
}
|
||||
|
||||
// TeeReadCloser returns a ReadCloser that writes to w what it reads from rc.
|
||||
// It utilizes io.TeeReader to copy the data read and has the same behavior when reading.
|
||||
// Further, when it is closed, it ensures that rc is closed as well.
|
||||
func TeeReadCloser(rc io.ReadCloser, w io.Writer) io.ReadCloser {
|
||||
return &teeReadCloser{rc, io.TeeReader(rc, w)}
|
||||
}
|
||||
|
||||
type teeReadCloser struct {
|
||||
rc io.ReadCloser
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
func (t *teeReadCloser) Read(p []byte) (int, error) {
|
||||
return t.r.Read(p)
|
||||
}
|
||||
|
||||
func (t *teeReadCloser) Close() error {
|
||||
return t.rc.Close()
|
||||
}
|
||||
|
||||
func containsInt(ints []int, n int) bool {
|
||||
for _, i := range ints {
|
||||
if i == n {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func escapeValueStrings(m map[string]string) map[string]string {
|
||||
for key, value := range m {
|
||||
m[key] = url.QueryEscape(value)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func ensureValueStrings(mapOfInterface map[string]interface{}) map[string]string {
|
||||
mapOfStrings := make(map[string]string)
|
||||
for key, value := range mapOfInterface {
|
||||
mapOfStrings[key] = ensureValueString(value)
|
||||
}
|
||||
return mapOfStrings
|
||||
}
|
||||
|
||||
func ensureValueString(value interface{}) string {
|
||||
if value == nil {
|
||||
return ""
|
||||
}
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
return v
|
||||
case []byte:
|
||||
return string(v)
|
||||
default:
|
||||
return fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
|
||||
// MapToValues method converts map[string]interface{} to url.Values.
|
||||
func MapToValues(m map[string]interface{}) url.Values {
|
||||
v := url.Values{}
|
||||
for key, value := range m {
|
||||
x := reflect.ValueOf(value)
|
||||
if x.Kind() == reflect.Array || x.Kind() == reflect.Slice {
|
||||
for i := 0; i < x.Len(); i++ {
|
||||
v.Add(key, ensureValueString(x.Index(i)))
|
||||
}
|
||||
} else {
|
||||
v.Add(key, ensureValueString(value))
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// String method converts interface v to string. If interface is a list, it
|
||||
// joins list elements using separator.
|
||||
func String(v interface{}, sep ...string) string {
|
||||
if len(sep) > 0 {
|
||||
return ensureValueString(strings.Join(v.([]string), sep[0]))
|
||||
}
|
||||
return ensureValueString(v)
|
||||
}
|
||||
|
||||
// Encode method encodes url path and query parameters.
|
||||
func Encode(location string, v interface{}, sep ...string) string {
|
||||
s := String(v, sep...)
|
||||
switch strings.ToLower(location) {
|
||||
case "path":
|
||||
return pathEscape(s)
|
||||
case "query":
|
||||
return queryEscape(s)
|
||||
default:
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
func pathEscape(s string) string {
|
||||
return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
|
||||
}
|
||||
|
||||
func queryEscape(s string) string {
|
||||
return url.QueryEscape(s)
|
||||
}
|
||||
|
||||
// This method is same as Encode() method of "net/url" go package,
|
||||
// except it does not encode the query parameters because they
|
||||
// already come encoded. It formats values map in query format (bar=foo&a=b).
|
||||
func createQuery(v url.Values) string {
|
||||
var buf bytes.Buffer
|
||||
keys := make([]string, 0, len(v))
|
||||
for k := range v {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
vs := v[k]
|
||||
prefix := url.QueryEscape(k) + "="
|
||||
for _, v := range vs {
|
||||
if buf.Len() > 0 {
|
||||
buf.WriteByte('&')
|
||||
}
|
||||
buf.WriteString(prefix)
|
||||
buf.WriteString(v)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
18
vendor/github.com/Azure/go-autorest/autorest/version.go
generated
vendored
18
vendor/github.com/Azure/go-autorest/autorest/version.go
generated
vendored
@@ -1,18 +0,0 @@
|
||||
package autorest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
major = "7"
|
||||
minor = "0"
|
||||
patch = "0"
|
||||
tag = ""
|
||||
semVerFormat = "%s.%s.%s%s"
|
||||
)
|
||||
|
||||
// Version returns the semantic version (see http://semver.org).
|
||||
func Version() string {
|
||||
return fmt.Sprintf(semVerFormat, major, minor, patch, tag)
|
||||
}
|
||||
5
vendor/github.com/PuerkitoBio/purell/.gitignore
generated
vendored
5
vendor/github.com/PuerkitoBio/purell/.gitignore
generated
vendored
@@ -1,5 +0,0 @@
|
||||
*.sublime-*
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
tags
|
||||
7
vendor/github.com/PuerkitoBio/purell/.travis.yml
generated
vendored
7
vendor/github.com/PuerkitoBio/purell/.travis.yml
generated
vendored
@@ -1,7 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
12
vendor/github.com/PuerkitoBio/purell/LICENSE
generated
vendored
12
vendor/github.com/PuerkitoBio/purell/LICENSE
generated
vendored
@@ -1,12 +0,0 @@
|
||||
Copyright (c) 2012, Martin Angers
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
185
vendor/github.com/PuerkitoBio/purell/README.md
generated
vendored
185
vendor/github.com/PuerkitoBio/purell/README.md
generated
vendored
@@ -1,185 +0,0 @@
|
||||
# Purell
|
||||
|
||||
Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell. Sanitizer and all. Yeah, I know...
|
||||
|
||||
Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc].
|
||||
|
||||
[](http://travis-ci.org/PuerkitoBio/purell)
|
||||
|
||||
## Install
|
||||
|
||||
`go get github.com/PuerkitoBio/purell`
|
||||
|
||||
## Changelog
|
||||
|
||||
* **2016-07-27 (v1.0.0)** : Normalize IDN to ASCII (thanks to @zenovich).
|
||||
* **2015-02-08** : Add fix for relative paths issue ([PR #5][pr5]) and add fix for unnecessary encoding of reserved characters ([see issue #7][iss7]).
|
||||
* **v0.2.0** : Add benchmarks, Attempt IDN support.
|
||||
* **v0.1.0** : Initial release.
|
||||
|
||||
## Examples
|
||||
|
||||
From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."):
|
||||
|
||||
```go
|
||||
package purell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func ExampleNormalizeURLString() {
|
||||
if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/",
|
||||
FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
fmt.Print(normalized)
|
||||
}
|
||||
// Output: http://somewebsite.com:80/Amazing%3F/url/
|
||||
}
|
||||
|
||||
func ExampleMustNormalizeURLString() {
|
||||
normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/",
|
||||
FlagsUnsafeGreedy)
|
||||
fmt.Print(normalized)
|
||||
|
||||
// Output: http://somewebsite.com/Amazing%FA/url
|
||||
}
|
||||
|
||||
func ExampleNormalizeURL() {
|
||||
if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment)
|
||||
fmt.Print(normalized)
|
||||
}
|
||||
|
||||
// Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
As seen in the examples above, purell offers three methods, `NormalizeURLString(string, NormalizationFlags) (string, error)`, `MustNormalizeURLString(string, NormalizationFlags) (string)` and `NormalizeURL(*url.URL, NormalizationFlags) (string)`. They all normalize the provided URL based on the specified flags. Here are the available flags:
|
||||
|
||||
```go
|
||||
const (
|
||||
// Safe normalizations
|
||||
FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
|
||||
FlagLowercaseHost // http://HOST -> http://host
|
||||
FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
|
||||
FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
|
||||
FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$
|
||||
FlagRemoveDefaultPort // http://host:80 -> http://host
|
||||
FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
|
||||
|
||||
// Usually safe normalizations
|
||||
FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
|
||||
FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
|
||||
FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
|
||||
|
||||
// Unsafe normalizations
|
||||
FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
|
||||
FlagRemoveFragment // http://host/path#fragment -> http://host/path
|
||||
FlagForceHTTP // https://host -> http://host
|
||||
FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
|
||||
FlagRemoveWWW // http://www.host/ -> http://host/
|
||||
FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
|
||||
FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
|
||||
|
||||
// Normalizations not in the wikipedia article, required to cover tests cases
|
||||
// submitted by jehiah
|
||||
FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
|
||||
FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
|
||||
FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
|
||||
FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
|
||||
FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
|
||||
|
||||
// Convenience set of safe normalizations
|
||||
FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
|
||||
|
||||
// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
|
||||
// while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
|
||||
|
||||
// Convenience set of usually safe normalizations (includes FlagsSafe)
|
||||
FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
|
||||
FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
|
||||
|
||||
// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
|
||||
FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
|
||||
FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
|
||||
|
||||
// Convenience set of all available flags
|
||||
FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
|
||||
FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
|
||||
)
|
||||
```
|
||||
|
||||
For convenience, the set of flags `FlagsSafe`, `FlagsUsuallySafe[Greedy|NonGreedy]`, `FlagsUnsafe[Greedy|NonGreedy]` and `FlagsAll[Greedy|NonGreedy]` are provided for the similarly grouped normalizations on [wikipedia's URL normalization page][wiki]. You can add (using the bitwise OR `|` operator) or remove (using the bitwise AND NOT `&^` operator) individual flags from the sets if required, to build your own custom set.
|
||||
|
||||
The [full godoc reference is available on gopkgdoc][godoc].
|
||||
|
||||
Some things to note:
|
||||
|
||||
* `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it.
|
||||
|
||||
* The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*):
|
||||
- %24 -> $
|
||||
- %26 -> &
|
||||
- %2B-%3B -> +,-./0123456789:;
|
||||
- %3D -> =
|
||||
- %40-%5A -> @ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
- %5F -> _
|
||||
- %61-%7A -> abcdefghijklmnopqrstuvwxyz
|
||||
- %7E -> ~
|
||||
|
||||
|
||||
* When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization).
|
||||
|
||||
* The *replace IP with domain name* normalization (`http://208.77.188.166/ → http://www.example.com/`) is obviously not possible for a library without making some network requests. This is not implemented in purell.
|
||||
|
||||
* The *remove unused query string parameters* and *remove default query parameters* are also not implemented, since this is a very case-specific normalization, and it is quite trivial to do with an URL object.
|
||||
|
||||
### Safe vs Usually Safe vs Unsafe
|
||||
|
||||
Purell allows you to control the level of risk you take while normalizing an URL. You can aggressively normalize, play it totally safe, or anything in between.
|
||||
|
||||
Consider the following URL:
|
||||
|
||||
`HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
|
||||
|
||||
Normalizing with the `FlagsSafe` gives:
|
||||
|
||||
`https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
|
||||
|
||||
With the `FlagsUsuallySafeGreedy`:
|
||||
|
||||
`https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid`
|
||||
|
||||
And with `FlagsUnsafeGreedy`:
|
||||
|
||||
`http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3`
|
||||
|
||||
## TODOs
|
||||
|
||||
* Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`.
|
||||
|
||||
## Thanks / Contributions
|
||||
|
||||
@rogpeppe
|
||||
@jehiah
|
||||
@opennota
|
||||
@pchristopher1275
|
||||
@zenovich
|
||||
|
||||
## License
|
||||
|
||||
The [BSD 3-Clause license][bsd].
|
||||
|
||||
[bsd]: http://opensource.org/licenses/BSD-3-Clause
|
||||
[wiki]: http://en.wikipedia.org/wiki/URL_normalization
|
||||
[rfc]: http://tools.ietf.org/html/rfc3986#section-6
|
||||
[godoc]: http://go.pkgdoc.org/github.com/PuerkitoBio/purell
|
||||
[pr5]: https://github.com/PuerkitoBio/purell/pull/5
|
||||
[iss7]: https://github.com/PuerkitoBio/purell/issues/7
|
||||
375
vendor/github.com/PuerkitoBio/purell/purell.go
generated
vendored
375
vendor/github.com/PuerkitoBio/purell/purell.go
generated
vendored
@@ -1,375 +0,0 @@
|
||||
/*
|
||||
Package purell offers URL normalization as described on the wikipedia page:
|
||||
http://en.wikipedia.org/wiki/URL_normalization
|
||||
*/
|
||||
package purell
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/PuerkitoBio/urlesc"
|
||||
"golang.org/x/net/idna"
|
||||
"golang.org/x/text/secure/precis"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
)
|
||||
|
||||
// A set of normalization flags determines how a URL will
|
||||
// be normalized.
|
||||
type NormalizationFlags uint
|
||||
|
||||
const (
|
||||
// Safe normalizations
|
||||
FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
|
||||
FlagLowercaseHost // http://HOST -> http://host
|
||||
FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
|
||||
FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
|
||||
FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$
|
||||
FlagRemoveDefaultPort // http://host:80 -> http://host
|
||||
FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
|
||||
|
||||
// Usually safe normalizations
|
||||
FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
|
||||
FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
|
||||
FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
|
||||
|
||||
// Unsafe normalizations
|
||||
FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
|
||||
FlagRemoveFragment // http://host/path#fragment -> http://host/path
|
||||
FlagForceHTTP // https://host -> http://host
|
||||
FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
|
||||
FlagRemoveWWW // http://www.host/ -> http://host/
|
||||
FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
|
||||
FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
|
||||
|
||||
// Normalizations not in the wikipedia article, required to cover tests cases
|
||||
// submitted by jehiah
|
||||
FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
|
||||
FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
|
||||
FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
|
||||
FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
|
||||
FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
|
||||
|
||||
// Convenience set of safe normalizations
|
||||
FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
|
||||
|
||||
// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
|
||||
// while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
|
||||
|
||||
// Convenience set of usually safe normalizations (includes FlagsSafe)
|
||||
FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
|
||||
FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
|
||||
|
||||
// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
|
||||
FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
|
||||
FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
|
||||
|
||||
// Convenience set of all available flags
|
||||
FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
|
||||
FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
|
||||
)
|
||||
|
||||
const (
|
||||
defaultHttpPort = ":80"
|
||||
defaultHttpsPort = ":443"
|
||||
)
|
||||
|
||||
// Regular expressions used by the normalizations
|
||||
var rxPort = regexp.MustCompile(`(:\d+)/?$`)
|
||||
var rxDirIndex = regexp.MustCompile(`(^|/)((?:default|index)\.\w{1,4})$`)
|
||||
var rxDupSlashes = regexp.MustCompile(`/{2,}`)
|
||||
var rxDWORDHost = regexp.MustCompile(`^(\d+)((?:\.+)?(?:\:\d*)?)$`)
|
||||
var rxOctalHost = regexp.MustCompile(`^(0\d*)\.(0\d*)\.(0\d*)\.(0\d*)((?:\.+)?(?:\:\d*)?)$`)
|
||||
var rxHexHost = regexp.MustCompile(`^0x([0-9A-Fa-f]+)((?:\.+)?(?:\:\d*)?)$`)
|
||||
var rxHostDots = regexp.MustCompile(`^(.+?)(:\d+)?$`)
|
||||
var rxEmptyPort = regexp.MustCompile(`:+$`)
|
||||
|
||||
// Map of flags to implementation function.
|
||||
// FlagDecodeUnnecessaryEscapes has no action, since it is done automatically
|
||||
// by parsing the string as an URL. Same for FlagUppercaseEscapes and FlagRemoveEmptyQuerySeparator.
|
||||
|
||||
// Since maps have undefined traversing order, make a slice of ordered keys
|
||||
var flagsOrder = []NormalizationFlags{
|
||||
FlagLowercaseScheme,
|
||||
FlagLowercaseHost,
|
||||
FlagRemoveDefaultPort,
|
||||
FlagRemoveDirectoryIndex,
|
||||
FlagRemoveDotSegments,
|
||||
FlagRemoveFragment,
|
||||
FlagForceHTTP, // Must be after remove default port (because https=443/http=80)
|
||||
FlagRemoveDuplicateSlashes,
|
||||
FlagRemoveWWW,
|
||||
FlagAddWWW,
|
||||
FlagSortQuery,
|
||||
FlagDecodeDWORDHost,
|
||||
FlagDecodeOctalHost,
|
||||
FlagDecodeHexHost,
|
||||
FlagRemoveUnnecessaryHostDots,
|
||||
FlagRemoveEmptyPortSeparator,
|
||||
FlagRemoveTrailingSlash, // These two (add/remove trailing slash) must be last
|
||||
FlagAddTrailingSlash,
|
||||
}
|
||||
|
||||
// ... and then the map, where order is unimportant
|
||||
var flags = map[NormalizationFlags]func(*url.URL){
|
||||
FlagLowercaseScheme: lowercaseScheme,
|
||||
FlagLowercaseHost: lowercaseHost,
|
||||
FlagRemoveDefaultPort: removeDefaultPort,
|
||||
FlagRemoveDirectoryIndex: removeDirectoryIndex,
|
||||
FlagRemoveDotSegments: removeDotSegments,
|
||||
FlagRemoveFragment: removeFragment,
|
||||
FlagForceHTTP: forceHTTP,
|
||||
FlagRemoveDuplicateSlashes: removeDuplicateSlashes,
|
||||
FlagRemoveWWW: removeWWW,
|
||||
FlagAddWWW: addWWW,
|
||||
FlagSortQuery: sortQuery,
|
||||
FlagDecodeDWORDHost: decodeDWORDHost,
|
||||
FlagDecodeOctalHost: decodeOctalHost,
|
||||
FlagDecodeHexHost: decodeHexHost,
|
||||
FlagRemoveUnnecessaryHostDots: removeUnncessaryHostDots,
|
||||
FlagRemoveEmptyPortSeparator: removeEmptyPortSeparator,
|
||||
FlagRemoveTrailingSlash: removeTrailingSlash,
|
||||
FlagAddTrailingSlash: addTrailingSlash,
|
||||
}
|
||||
|
||||
// MustNormalizeURLString returns the normalized string, and panics if an error occurs.
|
||||
// It takes an URL string as input, as well as the normalization flags.
|
||||
func MustNormalizeURLString(u string, f NormalizationFlags) string {
|
||||
result, e := NormalizeURLString(u, f)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// NormalizeURLString returns the normalized string, or an error if it can't be parsed into an URL object.
|
||||
// It takes an URL string as input, as well as the normalization flags.
|
||||
func NormalizeURLString(u string, f NormalizationFlags) (string, error) {
|
||||
if parsed, e := url.Parse(u); e != nil {
|
||||
return "", e
|
||||
} else {
|
||||
options := make([]precis.Option, 1, 3)
|
||||
options[0] = precis.IgnoreCase
|
||||
if f&FlagLowercaseHost == FlagLowercaseHost {
|
||||
options = append(options, precis.FoldCase())
|
||||
}
|
||||
options = append(options, precis.Norm(norm.NFC))
|
||||
profile := precis.NewFreeform(options...)
|
||||
if parsed.Host, e = idna.ToASCII(profile.NewTransformer().String(parsed.Host)); e != nil {
|
||||
return "", e
|
||||
}
|
||||
return NormalizeURL(parsed, f), nil
|
||||
}
|
||||
panic("Unreachable code.")
|
||||
}
|
||||
|
||||
// NormalizeURL returns the normalized string.
|
||||
// It takes a parsed URL object as input, as well as the normalization flags.
|
||||
func NormalizeURL(u *url.URL, f NormalizationFlags) string {
|
||||
for _, k := range flagsOrder {
|
||||
if f&k == k {
|
||||
flags[k](u)
|
||||
}
|
||||
}
|
||||
return urlesc.Escape(u)
|
||||
}
|
||||
|
||||
func lowercaseScheme(u *url.URL) {
|
||||
if len(u.Scheme) > 0 {
|
||||
u.Scheme = strings.ToLower(u.Scheme)
|
||||
}
|
||||
}
|
||||
|
||||
func lowercaseHost(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
u.Host = strings.ToLower(u.Host)
|
||||
}
|
||||
}
|
||||
|
||||
func removeDefaultPort(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
scheme := strings.ToLower(u.Scheme)
|
||||
u.Host = rxPort.ReplaceAllStringFunc(u.Host, func(val string) string {
|
||||
if (scheme == "http" && val == defaultHttpPort) || (scheme == "https" && val == defaultHttpsPort) {
|
||||
return ""
|
||||
}
|
||||
return val
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func removeTrailingSlash(u *url.URL) {
|
||||
if l := len(u.Path); l > 0 {
|
||||
if strings.HasSuffix(u.Path, "/") {
|
||||
u.Path = u.Path[:l-1]
|
||||
}
|
||||
} else if l = len(u.Host); l > 0 {
|
||||
if strings.HasSuffix(u.Host, "/") {
|
||||
u.Host = u.Host[:l-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addTrailingSlash(u *url.URL) {
|
||||
if l := len(u.Path); l > 0 {
|
||||
if !strings.HasSuffix(u.Path, "/") {
|
||||
u.Path += "/"
|
||||
}
|
||||
} else if l = len(u.Host); l > 0 {
|
||||
if !strings.HasSuffix(u.Host, "/") {
|
||||
u.Host += "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeDotSegments(u *url.URL) {
|
||||
if len(u.Path) > 0 {
|
||||
var dotFree []string
|
||||
var lastIsDot bool
|
||||
|
||||
sections := strings.Split(u.Path, "/")
|
||||
for _, s := range sections {
|
||||
if s == ".." {
|
||||
if len(dotFree) > 0 {
|
||||
dotFree = dotFree[:len(dotFree)-1]
|
||||
}
|
||||
} else if s != "." {
|
||||
dotFree = append(dotFree, s)
|
||||
}
|
||||
lastIsDot = (s == "." || s == "..")
|
||||
}
|
||||
// Special case if host does not end with / and new path does not begin with /
|
||||
u.Path = strings.Join(dotFree, "/")
|
||||
if u.Host != "" && !strings.HasSuffix(u.Host, "/") && !strings.HasPrefix(u.Path, "/") {
|
||||
u.Path = "/" + u.Path
|
||||
}
|
||||
// Special case if the last segment was a dot, make sure the path ends with a slash
|
||||
if lastIsDot && !strings.HasSuffix(u.Path, "/") {
|
||||
u.Path += "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeDirectoryIndex(u *url.URL) {
|
||||
if len(u.Path) > 0 {
|
||||
u.Path = rxDirIndex.ReplaceAllString(u.Path, "$1")
|
||||
}
|
||||
}
|
||||
|
||||
func removeFragment(u *url.URL) {
|
||||
u.Fragment = ""
|
||||
}
|
||||
|
||||
func forceHTTP(u *url.URL) {
|
||||
if strings.ToLower(u.Scheme) == "https" {
|
||||
u.Scheme = "http"
|
||||
}
|
||||
}
|
||||
|
||||
func removeDuplicateSlashes(u *url.URL) {
|
||||
if len(u.Path) > 0 {
|
||||
u.Path = rxDupSlashes.ReplaceAllString(u.Path, "/")
|
||||
}
|
||||
}
|
||||
|
||||
func removeWWW(u *url.URL) {
|
||||
if len(u.Host) > 0 && strings.HasPrefix(strings.ToLower(u.Host), "www.") {
|
||||
u.Host = u.Host[4:]
|
||||
}
|
||||
}
|
||||
|
||||
func addWWW(u *url.URL) {
|
||||
if len(u.Host) > 0 && !strings.HasPrefix(strings.ToLower(u.Host), "www.") {
|
||||
u.Host = "www." + u.Host
|
||||
}
|
||||
}
|
||||
|
||||
func sortQuery(u *url.URL) {
|
||||
q := u.Query()
|
||||
|
||||
if len(q) > 0 {
|
||||
arKeys := make([]string, len(q))
|
||||
i := 0
|
||||
for k, _ := range q {
|
||||
arKeys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(arKeys)
|
||||
buf := new(bytes.Buffer)
|
||||
for _, k := range arKeys {
|
||||
sort.Strings(q[k])
|
||||
for _, v := range q[k] {
|
||||
if buf.Len() > 0 {
|
||||
buf.WriteRune('&')
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("%s=%s", k, urlesc.QueryEscape(v)))
|
||||
}
|
||||
}
|
||||
|
||||
// Rebuild the raw query string
|
||||
u.RawQuery = buf.String()
|
||||
}
|
||||
}
|
||||
|
||||
func decodeDWORDHost(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
if matches := rxDWORDHost.FindStringSubmatch(u.Host); len(matches) > 2 {
|
||||
var parts [4]int64
|
||||
|
||||
dword, _ := strconv.ParseInt(matches[1], 10, 0)
|
||||
for i, shift := range []uint{24, 16, 8, 0} {
|
||||
parts[i] = dword >> shift & 0xFF
|
||||
}
|
||||
u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func decodeOctalHost(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
if matches := rxOctalHost.FindStringSubmatch(u.Host); len(matches) > 5 {
|
||||
var parts [4]int64
|
||||
|
||||
for i := 1; i <= 4; i++ {
|
||||
parts[i-1], _ = strconv.ParseInt(matches[i], 8, 0)
|
||||
}
|
||||
u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[5])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func decodeHexHost(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
if matches := rxHexHost.FindStringSubmatch(u.Host); len(matches) > 2 {
|
||||
// Conversion is safe because of regex validation
|
||||
parsed, _ := strconv.ParseInt(matches[1], 16, 0)
|
||||
// Set host as DWORD (base 10) encoded host
|
||||
u.Host = fmt.Sprintf("%d%s", parsed, matches[2])
|
||||
// The rest is the same as decoding a DWORD host
|
||||
decodeDWORDHost(u)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeUnncessaryHostDots(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
if matches := rxHostDots.FindStringSubmatch(u.Host); len(matches) > 1 {
|
||||
// Trim the leading and trailing dots
|
||||
u.Host = strings.Trim(matches[1], ".")
|
||||
if len(matches) > 2 {
|
||||
u.Host += matches[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeEmptyPortSeparator(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
u.Host = rxEmptyPort.ReplaceAllString(u.Host, "")
|
||||
}
|
||||
}
|
||||
11
vendor/github.com/PuerkitoBio/urlesc/.travis.yml
generated
vendored
11
vendor/github.com/PuerkitoBio/urlesc/.travis.yml
generated
vendored
@@ -1,11 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4
|
||||
- tip
|
||||
|
||||
install:
|
||||
- go build .
|
||||
|
||||
script:
|
||||
- go test -v
|
||||
27
vendor/github.com/PuerkitoBio/urlesc/LICENSE
generated
vendored
27
vendor/github.com/PuerkitoBio/urlesc/LICENSE
generated
vendored
@@ -1,27 +0,0 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
16
vendor/github.com/PuerkitoBio/urlesc/README.md
generated
vendored
16
vendor/github.com/PuerkitoBio/urlesc/README.md
generated
vendored
@@ -1,16 +0,0 @@
|
||||
urlesc [](https://travis-ci.org/PuerkitoBio/urlesc) [](http://godoc.org/github.com/PuerkitoBio/urlesc)
|
||||
======
|
||||
|
||||
Package urlesc implements query escaping as per RFC 3986.
|
||||
|
||||
It contains some parts of the net/url package, modified so as to allow
|
||||
some reserved characters incorrectly escaped by net/url (see [issue 5684](https://github.com/golang/go/issues/5684)).
|
||||
|
||||
## Install
|
||||
|
||||
go get github.com/PuerkitoBio/urlesc
|
||||
|
||||
## License
|
||||
|
||||
Go license (BSD-3-Clause)
|
||||
|
||||
180
vendor/github.com/PuerkitoBio/urlesc/urlesc.go
generated
vendored
180
vendor/github.com/PuerkitoBio/urlesc/urlesc.go
generated
vendored
@@ -1,180 +0,0 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package urlesc implements query escaping as per RFC 3986.
|
||||
// It contains some parts of the net/url package, modified so as to allow
|
||||
// some reserved characters incorrectly escaped by net/url.
|
||||
// See https://github.com/golang/go/issues/5684
|
||||
package urlesc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type encoding int
|
||||
|
||||
const (
|
||||
encodePath encoding = 1 + iota
|
||||
encodeUserPassword
|
||||
encodeQueryComponent
|
||||
encodeFragment
|
||||
)
|
||||
|
||||
// Return true if the specified character should be escaped when
|
||||
// appearing in a URL string, according to RFC 3986.
|
||||
func shouldEscape(c byte, mode encoding) bool {
|
||||
// §2.3 Unreserved characters (alphanum)
|
||||
if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
|
||||
return false
|
||||
}
|
||||
|
||||
switch c {
|
||||
case '-', '.', '_', '~': // §2.3 Unreserved characters (mark)
|
||||
return false
|
||||
|
||||
// §2.2 Reserved characters (reserved)
|
||||
case ':', '/', '?', '#', '[', ']', '@', // gen-delims
|
||||
'!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=': // sub-delims
|
||||
// Different sections of the URL allow a few of
|
||||
// the reserved characters to appear unescaped.
|
||||
switch mode {
|
||||
case encodePath: // §3.3
|
||||
// The RFC allows sub-delims and : @.
|
||||
// '/', '[' and ']' can be used to assign meaning to individual path
|
||||
// segments. This package only manipulates the path as a whole,
|
||||
// so we allow those as well. That leaves only ? and # to escape.
|
||||
return c == '?' || c == '#'
|
||||
|
||||
case encodeUserPassword: // §3.2.1
|
||||
// The RFC allows : and sub-delims in
|
||||
// userinfo. The parsing of userinfo treats ':' as special so we must escape
|
||||
// all the gen-delims.
|
||||
return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@'
|
||||
|
||||
case encodeQueryComponent: // §3.4
|
||||
// The RFC allows / and ?.
|
||||
return c != '/' && c != '?'
|
||||
|
||||
case encodeFragment: // §4.1
|
||||
// The RFC text is silent but the grammar allows
|
||||
// everything, so escape nothing but #
|
||||
return c == '#'
|
||||
}
|
||||
}
|
||||
|
||||
// Everything else must be escaped.
|
||||
return true
|
||||
}
|
||||
|
||||
// QueryEscape escapes the string so it can be safely placed
|
||||
// inside a URL query.
|
||||
func QueryEscape(s string) string {
|
||||
return escape(s, encodeQueryComponent)
|
||||
}
|
||||
|
||||
func escape(s string, mode encoding) string {
|
||||
spaceCount, hexCount := 0, 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if shouldEscape(c, mode) {
|
||||
if c == ' ' && mode == encodeQueryComponent {
|
||||
spaceCount++
|
||||
} else {
|
||||
hexCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if spaceCount == 0 && hexCount == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
t := make([]byte, len(s)+2*hexCount)
|
||||
j := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch c := s[i]; {
|
||||
case c == ' ' && mode == encodeQueryComponent:
|
||||
t[j] = '+'
|
||||
j++
|
||||
case shouldEscape(c, mode):
|
||||
t[j] = '%'
|
||||
t[j+1] = "0123456789ABCDEF"[c>>4]
|
||||
t[j+2] = "0123456789ABCDEF"[c&15]
|
||||
j += 3
|
||||
default:
|
||||
t[j] = s[i]
|
||||
j++
|
||||
}
|
||||
}
|
||||
return string(t)
|
||||
}
|
||||
|
||||
var uiReplacer = strings.NewReplacer(
|
||||
"%21", "!",
|
||||
"%27", "'",
|
||||
"%28", "(",
|
||||
"%29", ")",
|
||||
"%2A", "*",
|
||||
)
|
||||
|
||||
// unescapeUserinfo unescapes some characters that need not to be escaped as per RFC3986.
|
||||
func unescapeUserinfo(s string) string {
|
||||
return uiReplacer.Replace(s)
|
||||
}
|
||||
|
||||
// Escape reassembles the URL into a valid URL string.
|
||||
// The general form of the result is one of:
|
||||
//
|
||||
// scheme:opaque
|
||||
// scheme://userinfo@host/path?query#fragment
|
||||
//
|
||||
// If u.Opaque is non-empty, String uses the first form;
|
||||
// otherwise it uses the second form.
|
||||
//
|
||||
// In the second form, the following rules apply:
|
||||
// - if u.Scheme is empty, scheme: is omitted.
|
||||
// - if u.User is nil, userinfo@ is omitted.
|
||||
// - if u.Host is empty, host/ is omitted.
|
||||
// - if u.Scheme and u.Host are empty and u.User is nil,
|
||||
// the entire scheme://userinfo@host/ is omitted.
|
||||
// - if u.Host is non-empty and u.Path begins with a /,
|
||||
// the form host/path does not add its own /.
|
||||
// - if u.RawQuery is empty, ?query is omitted.
|
||||
// - if u.Fragment is empty, #fragment is omitted.
|
||||
func Escape(u *url.URL) string {
|
||||
var buf bytes.Buffer
|
||||
if u.Scheme != "" {
|
||||
buf.WriteString(u.Scheme)
|
||||
buf.WriteByte(':')
|
||||
}
|
||||
if u.Opaque != "" {
|
||||
buf.WriteString(u.Opaque)
|
||||
} else {
|
||||
if u.Scheme != "" || u.Host != "" || u.User != nil {
|
||||
buf.WriteString("//")
|
||||
if ui := u.User; ui != nil {
|
||||
buf.WriteString(unescapeUserinfo(ui.String()))
|
||||
buf.WriteByte('@')
|
||||
}
|
||||
if h := u.Host; h != "" {
|
||||
buf.WriteString(h)
|
||||
}
|
||||
}
|
||||
if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
|
||||
buf.WriteByte('/')
|
||||
}
|
||||
buf.WriteString(escape(u.Path, encodePath))
|
||||
}
|
||||
if u.RawQuery != "" {
|
||||
buf.WriteByte('?')
|
||||
buf.WriteString(u.RawQuery)
|
||||
}
|
||||
if u.Fragment != "" {
|
||||
buf.WriteByte('#')
|
||||
buf.WriteString(escape(u.Fragment, encodeFragment))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
202
vendor/github.com/coreos/go-oidc/LICENSE
generated
vendored
202
vendor/github.com/coreos/go-oidc/LICENSE
generated
vendored
@@ -1,202 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
|
||||
5
vendor/github.com/coreos/go-oidc/NOTICE
generated
vendored
5
vendor/github.com/coreos/go-oidc/NOTICE
generated
vendored
@@ -1,5 +0,0 @@
|
||||
CoreOS Project
|
||||
Copyright 2014 CoreOS, Inc
|
||||
|
||||
This product includes software developed at CoreOS, Inc.
|
||||
(http://www.coreos.com/).
|
||||
7
vendor/github.com/coreos/go-oidc/http/client.go
generated
vendored
7
vendor/github.com/coreos/go-oidc/http/client.go
generated
vendored
@@ -1,7 +0,0 @@
|
||||
package http
|
||||
|
||||
import "net/http"
|
||||
|
||||
type Client interface {
|
||||
Do(*http.Request) (*http.Response, error)
|
||||
}
|
||||
2
vendor/github.com/coreos/go-oidc/http/doc.go
generated
vendored
2
vendor/github.com/coreos/go-oidc/http/doc.go
generated
vendored
@@ -1,2 +0,0 @@
|
||||
// Package http is DEPRECATED. Use net/http instead.
|
||||
package http
|
||||
156
vendor/github.com/coreos/go-oidc/http/http.go
generated
vendored
156
vendor/github.com/coreos/go-oidc/http/http.go
generated
vendored
@@ -1,156 +0,0 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func WriteError(w http.ResponseWriter, code int, msg string) {
|
||||
e := struct {
|
||||
Error string `json:"error"`
|
||||
}{
|
||||
Error: msg,
|
||||
}
|
||||
b, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
log.Printf("go-oidc: failed to marshal %#v: %v", e, err)
|
||||
code = http.StatusInternalServerError
|
||||
b = []byte(`{"error":"server_error"}`)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(code)
|
||||
w.Write(b)
|
||||
}
|
||||
|
||||
// BasicAuth parses a username and password from the request's
|
||||
// Authorization header. This was pulled from golang master:
|
||||
// https://codereview.appspot.com/76540043
|
||||
func BasicAuth(r *http.Request) (username, password string, ok bool) {
|
||||
auth := r.Header.Get("Authorization")
|
||||
if auth == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(auth, "Basic ") {
|
||||
return
|
||||
}
|
||||
c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic "))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cs := string(c)
|
||||
s := strings.IndexByte(cs, ':')
|
||||
if s < 0 {
|
||||
return
|
||||
}
|
||||
return cs[:s], cs[s+1:], true
|
||||
}
|
||||
|
||||
func cacheControlMaxAge(hdr string) (time.Duration, bool, error) {
|
||||
for _, field := range strings.Split(hdr, ",") {
|
||||
parts := strings.SplitN(strings.TrimSpace(field), "=", 2)
|
||||
k := strings.ToLower(strings.TrimSpace(parts[0]))
|
||||
if k != "max-age" {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(parts) == 1 {
|
||||
return 0, false, errors.New("max-age has no value")
|
||||
}
|
||||
|
||||
v := strings.TrimSpace(parts[1])
|
||||
if v == "" {
|
||||
return 0, false, errors.New("max-age has empty value")
|
||||
}
|
||||
|
||||
age, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
|
||||
if age <= 0 {
|
||||
return 0, false, nil
|
||||
}
|
||||
|
||||
return time.Duration(age) * time.Second, true, nil
|
||||
}
|
||||
|
||||
return 0, false, nil
|
||||
}
|
||||
|
||||
func expires(date, expires string) (time.Duration, bool, error) {
|
||||
if date == "" || expires == "" {
|
||||
return 0, false, nil
|
||||
}
|
||||
|
||||
te, err := time.Parse(time.RFC1123, expires)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
|
||||
td, err := time.Parse(time.RFC1123, date)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
|
||||
ttl := te.Sub(td)
|
||||
|
||||
// headers indicate data already expired, caller should not
|
||||
// have to care about this case
|
||||
if ttl <= 0 {
|
||||
return 0, false, nil
|
||||
}
|
||||
|
||||
return ttl, true, nil
|
||||
}
|
||||
|
||||
func Cacheable(hdr http.Header) (time.Duration, bool, error) {
|
||||
ttl, ok, err := cacheControlMaxAge(hdr.Get("Cache-Control"))
|
||||
if err != nil || ok {
|
||||
return ttl, ok, err
|
||||
}
|
||||
|
||||
return expires(hdr.Get("Date"), hdr.Get("Expires"))
|
||||
}
|
||||
|
||||
// MergeQuery appends additional query values to an existing URL.
|
||||
func MergeQuery(u url.URL, q url.Values) url.URL {
|
||||
uv := u.Query()
|
||||
for k, vs := range q {
|
||||
for _, v := range vs {
|
||||
uv.Add(k, v)
|
||||
}
|
||||
}
|
||||
u.RawQuery = uv.Encode()
|
||||
return u
|
||||
}
|
||||
|
||||
// NewResourceLocation appends a resource id to the end of the requested URL path.
|
||||
func NewResourceLocation(reqURL *url.URL, id string) string {
|
||||
var u url.URL
|
||||
u = *reqURL
|
||||
u.Path = path.Join(u.Path, id)
|
||||
u.RawQuery = ""
|
||||
u.Fragment = ""
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// CopyRequest returns a clone of the provided *http.Request.
|
||||
// The returned object is a shallow copy of the struct and a
|
||||
// deep copy of its Header field.
|
||||
func CopyRequest(r *http.Request) *http.Request {
|
||||
r2 := *r
|
||||
r2.Header = make(http.Header)
|
||||
for k, s := range r.Header {
|
||||
r2.Header[k] = s
|
||||
}
|
||||
return &r2
|
||||
}
|
||||
29
vendor/github.com/coreos/go-oidc/http/url.go
generated
vendored
29
vendor/github.com/coreos/go-oidc/http/url.go
generated
vendored
@@ -1,29 +0,0 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// ParseNonEmptyURL checks that a string is a parsable URL which is also not empty
|
||||
// since `url.Parse("")` does not return an error. Must contian a scheme and a host.
|
||||
func ParseNonEmptyURL(u string) (*url.URL, error) {
|
||||
if u == "" {
|
||||
return nil, errors.New("url is empty")
|
||||
}
|
||||
|
||||
ur, err := url.Parse(u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ur.Scheme == "" {
|
||||
return nil, errors.New("url scheme is empty")
|
||||
}
|
||||
|
||||
if ur.Host == "" {
|
||||
return nil, errors.New("url host is empty")
|
||||
}
|
||||
|
||||
return ur, nil
|
||||
}
|
||||
126
vendor/github.com/coreos/go-oidc/jose/claims.go
generated
vendored
126
vendor/github.com/coreos/go-oidc/jose/claims.go
generated
vendored
@@ -1,126 +0,0 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Claims map[string]interface{}
|
||||
|
||||
func (c Claims) Add(name string, value interface{}) {
|
||||
c[name] = value
|
||||
}
|
||||
|
||||
func (c Claims) StringClaim(name string) (string, bool, error) {
|
||||
cl, ok := c[name]
|
||||
if !ok {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
v, ok := cl.(string)
|
||||
if !ok {
|
||||
return "", false, fmt.Errorf("unable to parse claim as string: %v", name)
|
||||
}
|
||||
|
||||
return v, true, nil
|
||||
}
|
||||
|
||||
func (c Claims) StringsClaim(name string) ([]string, bool, error) {
|
||||
cl, ok := c[name]
|
||||
if !ok {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
if v, ok := cl.([]string); ok {
|
||||
return v, true, nil
|
||||
}
|
||||
|
||||
// When unmarshaled, []string will become []interface{}.
|
||||
if v, ok := cl.([]interface{}); ok {
|
||||
var ret []string
|
||||
for _, vv := range v {
|
||||
str, ok := vv.(string)
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("unable to parse claim as string array: %v", name)
|
||||
}
|
||||
ret = append(ret, str)
|
||||
}
|
||||
return ret, true, nil
|
||||
}
|
||||
|
||||
return nil, false, fmt.Errorf("unable to parse claim as string array: %v", name)
|
||||
}
|
||||
|
||||
func (c Claims) Int64Claim(name string) (int64, bool, error) {
|
||||
cl, ok := c[name]
|
||||
if !ok {
|
||||
return 0, false, nil
|
||||
}
|
||||
|
||||
v, ok := cl.(int64)
|
||||
if !ok {
|
||||
vf, ok := cl.(float64)
|
||||
if !ok {
|
||||
return 0, false, fmt.Errorf("unable to parse claim as int64: %v", name)
|
||||
}
|
||||
v = int64(vf)
|
||||
}
|
||||
|
||||
return v, true, nil
|
||||
}
|
||||
|
||||
func (c Claims) Float64Claim(name string) (float64, bool, error) {
|
||||
cl, ok := c[name]
|
||||
if !ok {
|
||||
return 0, false, nil
|
||||
}
|
||||
|
||||
v, ok := cl.(float64)
|
||||
if !ok {
|
||||
vi, ok := cl.(int64)
|
||||
if !ok {
|
||||
return 0, false, fmt.Errorf("unable to parse claim as float64: %v", name)
|
||||
}
|
||||
v = float64(vi)
|
||||
}
|
||||
|
||||
return v, true, nil
|
||||
}
|
||||
|
||||
func (c Claims) TimeClaim(name string) (time.Time, bool, error) {
|
||||
v, ok, err := c.Float64Claim(name)
|
||||
if !ok || err != nil {
|
||||
return time.Time{}, ok, err
|
||||
}
|
||||
|
||||
s := math.Trunc(v)
|
||||
ns := (v - s) * math.Pow(10, 9)
|
||||
return time.Unix(int64(s), int64(ns)).UTC(), true, nil
|
||||
}
|
||||
|
||||
func decodeClaims(payload []byte) (Claims, error) {
|
||||
var c Claims
|
||||
if err := json.Unmarshal(payload, &c); err != nil {
|
||||
return nil, fmt.Errorf("malformed JWT claims, unable to decode: %v", err)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func marshalClaims(c Claims) ([]byte, error) {
|
||||
b, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func encodeClaims(c Claims) (string, error) {
|
||||
b, err := marshalClaims(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return encodeSegment(b), nil
|
||||
}
|
||||
2
vendor/github.com/coreos/go-oidc/jose/doc.go
generated
vendored
2
vendor/github.com/coreos/go-oidc/jose/doc.go
generated
vendored
@@ -1,2 +0,0 @@
|
||||
// Package jose is DEPRECATED. Use gopkg.in/square/go-jose.v2 instead.
|
||||
package jose
|
||||
112
vendor/github.com/coreos/go-oidc/jose/jose.go
generated
vendored
112
vendor/github.com/coreos/go-oidc/jose/jose.go
generated
vendored
@@ -1,112 +0,0 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
HeaderMediaType = "typ"
|
||||
HeaderKeyAlgorithm = "alg"
|
||||
HeaderKeyID = "kid"
|
||||
)
|
||||
|
||||
const (
|
||||
// Encryption Algorithm Header Parameter Values for JWS
|
||||
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#page-6
|
||||
AlgHS256 = "HS256"
|
||||
AlgHS384 = "HS384"
|
||||
AlgHS512 = "HS512"
|
||||
AlgRS256 = "RS256"
|
||||
AlgRS384 = "RS384"
|
||||
AlgRS512 = "RS512"
|
||||
AlgES256 = "ES256"
|
||||
AlgES384 = "ES384"
|
||||
AlgES512 = "ES512"
|
||||
AlgPS256 = "PS256"
|
||||
AlgPS384 = "PS384"
|
||||
AlgPS512 = "PS512"
|
||||
AlgNone = "none"
|
||||
)
|
||||
|
||||
const (
|
||||
// Algorithm Header Parameter Values for JWE
|
||||
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-4.1
|
||||
AlgRSA15 = "RSA1_5"
|
||||
AlgRSAOAEP = "RSA-OAEP"
|
||||
AlgRSAOAEP256 = "RSA-OAEP-256"
|
||||
AlgA128KW = "A128KW"
|
||||
AlgA192KW = "A192KW"
|
||||
AlgA256KW = "A256KW"
|
||||
AlgDir = "dir"
|
||||
AlgECDHES = "ECDH-ES"
|
||||
AlgECDHESA128KW = "ECDH-ES+A128KW"
|
||||
AlgECDHESA192KW = "ECDH-ES+A192KW"
|
||||
AlgECDHESA256KW = "ECDH-ES+A256KW"
|
||||
AlgA128GCMKW = "A128GCMKW"
|
||||
AlgA192GCMKW = "A192GCMKW"
|
||||
AlgA256GCMKW = "A256GCMKW"
|
||||
AlgPBES2HS256A128KW = "PBES2-HS256+A128KW"
|
||||
AlgPBES2HS384A192KW = "PBES2-HS384+A192KW"
|
||||
AlgPBES2HS512A256KW = "PBES2-HS512+A256KW"
|
||||
)
|
||||
|
||||
const (
|
||||
// Encryption Algorithm Header Parameter Values for JWE
|
||||
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#page-22
|
||||
EncA128CBCHS256 = "A128CBC-HS256"
|
||||
EncA128CBCHS384 = "A128CBC-HS384"
|
||||
EncA256CBCHS512 = "A256CBC-HS512"
|
||||
EncA128GCM = "A128GCM"
|
||||
EncA192GCM = "A192GCM"
|
||||
EncA256GCM = "A256GCM"
|
||||
)
|
||||
|
||||
type JOSEHeader map[string]string
|
||||
|
||||
func (j JOSEHeader) Validate() error {
|
||||
if _, exists := j[HeaderKeyAlgorithm]; !exists {
|
||||
return fmt.Errorf("header missing %q parameter", HeaderKeyAlgorithm)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeHeader(seg string) (JOSEHeader, error) {
|
||||
b, err := decodeSegment(seg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var h JOSEHeader
|
||||
err = json.Unmarshal(b, &h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func encodeHeader(h JOSEHeader) (string, error) {
|
||||
b, err := json.Marshal(h)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return encodeSegment(b), nil
|
||||
}
|
||||
|
||||
// Decode JWT specific base64url encoding with padding stripped
|
||||
func decodeSegment(seg string) ([]byte, error) {
|
||||
if l := len(seg) % 4; l != 0 {
|
||||
seg += strings.Repeat("=", 4-l)
|
||||
}
|
||||
return base64.URLEncoding.DecodeString(seg)
|
||||
}
|
||||
|
||||
// Encode JWT specific base64url encoding with padding stripped
|
||||
func encodeSegment(seg []byte) string {
|
||||
return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=")
|
||||
}
|
||||
135
vendor/github.com/coreos/go-oidc/jose/jwk.go
generated
vendored
135
vendor/github.com/coreos/go-oidc/jose/jwk.go
generated
vendored
@@ -1,135 +0,0 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// JSON Web Key
|
||||
// https://tools.ietf.org/html/draft-ietf-jose-json-web-key-36#page-5
|
||||
type JWK struct {
|
||||
ID string
|
||||
Type string
|
||||
Alg string
|
||||
Use string
|
||||
Exponent int
|
||||
Modulus *big.Int
|
||||
Secret []byte
|
||||
}
|
||||
|
||||
type jwkJSON struct {
|
||||
ID string `json:"kid"`
|
||||
Type string `json:"kty"`
|
||||
Alg string `json:"alg"`
|
||||
Use string `json:"use"`
|
||||
Exponent string `json:"e"`
|
||||
Modulus string `json:"n"`
|
||||
}
|
||||
|
||||
func (j *JWK) MarshalJSON() ([]byte, error) {
|
||||
t := jwkJSON{
|
||||
ID: j.ID,
|
||||
Type: j.Type,
|
||||
Alg: j.Alg,
|
||||
Use: j.Use,
|
||||
Exponent: encodeExponent(j.Exponent),
|
||||
Modulus: encodeModulus(j.Modulus),
|
||||
}
|
||||
|
||||
return json.Marshal(&t)
|
||||
}
|
||||
|
||||
func (j *JWK) UnmarshalJSON(data []byte) error {
|
||||
var t jwkJSON
|
||||
err := json.Unmarshal(data, &t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e, err := decodeExponent(t.Exponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := decodeModulus(t.Modulus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
j.ID = t.ID
|
||||
j.Type = t.Type
|
||||
j.Alg = t.Alg
|
||||
j.Use = t.Use
|
||||
j.Exponent = e
|
||||
j.Modulus = n
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type JWKSet struct {
|
||||
Keys []JWK `json:"keys"`
|
||||
}
|
||||
|
||||
func decodeExponent(e string) (int, error) {
|
||||
decE, err := decodeBase64URLPaddingOptional(e)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var eBytes []byte
|
||||
if len(decE) < 8 {
|
||||
eBytes = make([]byte, 8-len(decE), 8)
|
||||
eBytes = append(eBytes, decE...)
|
||||
} else {
|
||||
eBytes = decE
|
||||
}
|
||||
eReader := bytes.NewReader(eBytes)
|
||||
var E uint64
|
||||
err = binary.Read(eReader, binary.BigEndian, &E)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(E), nil
|
||||
}
|
||||
|
||||
func encodeExponent(e int) string {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, uint64(e))
|
||||
var idx int
|
||||
for ; idx < 8; idx++ {
|
||||
if b[idx] != 0x0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return base64.RawURLEncoding.EncodeToString(b[idx:])
|
||||
}
|
||||
|
||||
// Turns a URL encoded modulus of a key into a big int.
|
||||
func decodeModulus(n string) (*big.Int, error) {
|
||||
decN, err := decodeBase64URLPaddingOptional(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
N := big.NewInt(0)
|
||||
N.SetBytes(decN)
|
||||
return N, nil
|
||||
}
|
||||
|
||||
func encodeModulus(n *big.Int) string {
|
||||
return base64.RawURLEncoding.EncodeToString(n.Bytes())
|
||||
}
|
||||
|
||||
// decodeBase64URLPaddingOptional decodes Base64 whether there is padding or not.
|
||||
// The stdlib version currently doesn't handle this.
|
||||
// We can get rid of this is if this bug:
|
||||
// https://github.com/golang/go/issues/4237
|
||||
// ever closes.
|
||||
func decodeBase64URLPaddingOptional(e string) ([]byte, error) {
|
||||
if m := len(e) % 4; m != 0 {
|
||||
e += strings.Repeat("=", 4-m)
|
||||
}
|
||||
return base64.URLEncoding.DecodeString(e)
|
||||
}
|
||||
51
vendor/github.com/coreos/go-oidc/jose/jws.go
generated
vendored
51
vendor/github.com/coreos/go-oidc/jose/jws.go
generated
vendored
@@ -1,51 +0,0 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type JWS struct {
|
||||
RawHeader string
|
||||
Header JOSEHeader
|
||||
RawPayload string
|
||||
Payload []byte
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
// Given a raw encoded JWS token parses it and verifies the structure.
|
||||
func ParseJWS(raw string) (JWS, error) {
|
||||
parts := strings.Split(raw, ".")
|
||||
if len(parts) != 3 {
|
||||
return JWS{}, fmt.Errorf("malformed JWS, only %d segments", len(parts))
|
||||
}
|
||||
|
||||
rawSig := parts[2]
|
||||
jws := JWS{
|
||||
RawHeader: parts[0],
|
||||
RawPayload: parts[1],
|
||||
}
|
||||
|
||||
header, err := decodeHeader(jws.RawHeader)
|
||||
if err != nil {
|
||||
return JWS{}, fmt.Errorf("malformed JWS, unable to decode header, %s", err)
|
||||
}
|
||||
if err = header.Validate(); err != nil {
|
||||
return JWS{}, fmt.Errorf("malformed JWS, %s", err)
|
||||
}
|
||||
jws.Header = header
|
||||
|
||||
payload, err := decodeSegment(jws.RawPayload)
|
||||
if err != nil {
|
||||
return JWS{}, fmt.Errorf("malformed JWS, unable to decode payload: %s", err)
|
||||
}
|
||||
jws.Payload = payload
|
||||
|
||||
sig, err := decodeSegment(rawSig)
|
||||
if err != nil {
|
||||
return JWS{}, fmt.Errorf("malformed JWS, unable to decode signature: %s", err)
|
||||
}
|
||||
jws.Signature = sig
|
||||
|
||||
return jws, nil
|
||||
}
|
||||
82
vendor/github.com/coreos/go-oidc/jose/jwt.go
generated
vendored
82
vendor/github.com/coreos/go-oidc/jose/jwt.go
generated
vendored
@@ -1,82 +0,0 @@
|
||||
package jose
|
||||
|
||||
import "strings"
|
||||
|
||||
type JWT JWS
|
||||
|
||||
func ParseJWT(token string) (jwt JWT, err error) {
|
||||
jws, err := ParseJWS(token)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return JWT(jws), nil
|
||||
}
|
||||
|
||||
func NewJWT(header JOSEHeader, claims Claims) (jwt JWT, err error) {
|
||||
jwt = JWT{}
|
||||
|
||||
jwt.Header = header
|
||||
jwt.Header[HeaderMediaType] = "JWT"
|
||||
|
||||
claimBytes, err := marshalClaims(claims)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
jwt.Payload = claimBytes
|
||||
|
||||
eh, err := encodeHeader(header)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
jwt.RawHeader = eh
|
||||
|
||||
ec, err := encodeClaims(claims)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
jwt.RawPayload = ec
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (j *JWT) KeyID() (string, bool) {
|
||||
kID, ok := j.Header[HeaderKeyID]
|
||||
return kID, ok
|
||||
}
|
||||
|
||||
func (j *JWT) Claims() (Claims, error) {
|
||||
return decodeClaims(j.Payload)
|
||||
}
|
||||
|
||||
// Encoded data part of the token which may be signed.
|
||||
func (j *JWT) Data() string {
|
||||
return strings.Join([]string{j.RawHeader, j.RawPayload}, ".")
|
||||
}
|
||||
|
||||
// Full encoded JWT token string in format: header.claims.signature
|
||||
func (j *JWT) Encode() string {
|
||||
d := j.Data()
|
||||
s := encodeSegment(j.Signature)
|
||||
return strings.Join([]string{d, s}, ".")
|
||||
}
|
||||
|
||||
func NewSignedJWT(claims Claims, s Signer) (*JWT, error) {
|
||||
header := JOSEHeader{
|
||||
HeaderKeyAlgorithm: s.Alg(),
|
||||
HeaderKeyID: s.ID(),
|
||||
}
|
||||
|
||||
jwt, err := NewJWT(header, claims)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sig, err := s.Sign([]byte(jwt.Data()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jwt.Signature = sig
|
||||
|
||||
return &jwt, nil
|
||||
}
|
||||
24
vendor/github.com/coreos/go-oidc/jose/sig.go
generated
vendored
24
vendor/github.com/coreos/go-oidc/jose/sig.go
generated
vendored
@@ -1,24 +0,0 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Verifier interface {
|
||||
ID() string
|
||||
Alg() string
|
||||
Verify(sig []byte, data []byte) error
|
||||
}
|
||||
|
||||
type Signer interface {
|
||||
Verifier
|
||||
Sign(data []byte) (sig []byte, err error)
|
||||
}
|
||||
|
||||
func NewVerifier(jwk JWK) (Verifier, error) {
|
||||
if jwk.Type != "RSA" {
|
||||
return nil, fmt.Errorf("unsupported key type %q", jwk.Type)
|
||||
}
|
||||
|
||||
return NewVerifierRSA(jwk)
|
||||
}
|
||||
67
vendor/github.com/coreos/go-oidc/jose/sig_rsa.go
generated
vendored
67
vendor/github.com/coreos/go-oidc/jose/sig_rsa.go
generated
vendored
@@ -1,67 +0,0 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type VerifierRSA struct {
|
||||
KeyID string
|
||||
Hash crypto.Hash
|
||||
PublicKey rsa.PublicKey
|
||||
}
|
||||
|
||||
type SignerRSA struct {
|
||||
PrivateKey rsa.PrivateKey
|
||||
VerifierRSA
|
||||
}
|
||||
|
||||
func NewVerifierRSA(jwk JWK) (*VerifierRSA, error) {
|
||||
if jwk.Alg != "" && jwk.Alg != "RS256" {
|
||||
return nil, fmt.Errorf("unsupported key algorithm %q", jwk.Alg)
|
||||
}
|
||||
|
||||
v := VerifierRSA{
|
||||
KeyID: jwk.ID,
|
||||
PublicKey: rsa.PublicKey{
|
||||
N: jwk.Modulus,
|
||||
E: jwk.Exponent,
|
||||
},
|
||||
Hash: crypto.SHA256,
|
||||
}
|
||||
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func NewSignerRSA(kid string, key rsa.PrivateKey) *SignerRSA {
|
||||
return &SignerRSA{
|
||||
PrivateKey: key,
|
||||
VerifierRSA: VerifierRSA{
|
||||
KeyID: kid,
|
||||
PublicKey: key.PublicKey,
|
||||
Hash: crypto.SHA256,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (v *VerifierRSA) ID() string {
|
||||
return v.KeyID
|
||||
}
|
||||
|
||||
func (v *VerifierRSA) Alg() string {
|
||||
return "RS256"
|
||||
}
|
||||
|
||||
func (v *VerifierRSA) Verify(sig []byte, data []byte) error {
|
||||
h := v.Hash.New()
|
||||
h.Write(data)
|
||||
return rsa.VerifyPKCS1v15(&v.PublicKey, v.Hash, h.Sum(nil), sig)
|
||||
}
|
||||
|
||||
func (s *SignerRSA) Sign(data []byte) ([]byte, error) {
|
||||
h := s.Hash.New()
|
||||
h.Write(data)
|
||||
return rsa.SignPKCS1v15(rand.Reader, &s.PrivateKey, s.Hash, h.Sum(nil))
|
||||
}
|
||||
2
vendor/github.com/coreos/go-oidc/key/doc.go
generated
vendored
2
vendor/github.com/coreos/go-oidc/key/doc.go
generated
vendored
@@ -1,2 +0,0 @@
|
||||
// Package key is DEPRECATED. Use github.com/coreos/go-oidc instead.
|
||||
package key
|
||||
153
vendor/github.com/coreos/go-oidc/key/key.go
generated
vendored
153
vendor/github.com/coreos/go-oidc/key/key.go
generated
vendored
@@ -1,153 +0,0 @@
|
||||
package key
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
)
|
||||
|
||||
func NewPublicKey(jwk jose.JWK) *PublicKey {
|
||||
return &PublicKey{jwk: jwk}
|
||||
}
|
||||
|
||||
type PublicKey struct {
|
||||
jwk jose.JWK
|
||||
}
|
||||
|
||||
func (k *PublicKey) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(&k.jwk)
|
||||
}
|
||||
|
||||
func (k *PublicKey) UnmarshalJSON(data []byte) error {
|
||||
var jwk jose.JWK
|
||||
if err := json.Unmarshal(data, &jwk); err != nil {
|
||||
return err
|
||||
}
|
||||
k.jwk = jwk
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *PublicKey) ID() string {
|
||||
return k.jwk.ID
|
||||
}
|
||||
|
||||
func (k *PublicKey) Verifier() (jose.Verifier, error) {
|
||||
return jose.NewVerifierRSA(k.jwk)
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
KeyID string
|
||||
PrivateKey *rsa.PrivateKey
|
||||
}
|
||||
|
||||
func (k *PrivateKey) ID() string {
|
||||
return k.KeyID
|
||||
}
|
||||
|
||||
func (k *PrivateKey) Signer() jose.Signer {
|
||||
return jose.NewSignerRSA(k.ID(), *k.PrivateKey)
|
||||
}
|
||||
|
||||
func (k *PrivateKey) JWK() jose.JWK {
|
||||
return jose.JWK{
|
||||
ID: k.KeyID,
|
||||
Type: "RSA",
|
||||
Alg: "RS256",
|
||||
Use: "sig",
|
||||
Exponent: k.PrivateKey.PublicKey.E,
|
||||
Modulus: k.PrivateKey.PublicKey.N,
|
||||
}
|
||||
}
|
||||
|
||||
type KeySet interface {
|
||||
ExpiresAt() time.Time
|
||||
}
|
||||
|
||||
type PublicKeySet struct {
|
||||
keys []PublicKey
|
||||
index map[string]*PublicKey
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
func NewPublicKeySet(jwks []jose.JWK, exp time.Time) *PublicKeySet {
|
||||
keys := make([]PublicKey, len(jwks))
|
||||
index := make(map[string]*PublicKey)
|
||||
for i, jwk := range jwks {
|
||||
keys[i] = *NewPublicKey(jwk)
|
||||
index[keys[i].ID()] = &keys[i]
|
||||
}
|
||||
return &PublicKeySet{
|
||||
keys: keys,
|
||||
index: index,
|
||||
expiresAt: exp,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PublicKeySet) ExpiresAt() time.Time {
|
||||
return s.expiresAt
|
||||
}
|
||||
|
||||
func (s *PublicKeySet) Keys() []PublicKey {
|
||||
return s.keys
|
||||
}
|
||||
|
||||
func (s *PublicKeySet) Key(id string) *PublicKey {
|
||||
return s.index[id]
|
||||
}
|
||||
|
||||
type PrivateKeySet struct {
|
||||
keys []*PrivateKey
|
||||
ActiveKeyID string
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
func NewPrivateKeySet(keys []*PrivateKey, exp time.Time) *PrivateKeySet {
|
||||
return &PrivateKeySet{
|
||||
keys: keys,
|
||||
ActiveKeyID: keys[0].ID(),
|
||||
expiresAt: exp.UTC(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PrivateKeySet) Keys() []*PrivateKey {
|
||||
return s.keys
|
||||
}
|
||||
|
||||
func (s *PrivateKeySet) ExpiresAt() time.Time {
|
||||
return s.expiresAt
|
||||
}
|
||||
|
||||
func (s *PrivateKeySet) Active() *PrivateKey {
|
||||
for i, k := range s.keys {
|
||||
if k.ID() == s.ActiveKeyID {
|
||||
return s.keys[i]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type GeneratePrivateKeyFunc func() (*PrivateKey, error)
|
||||
|
||||
func GeneratePrivateKey() (*PrivateKey, error) {
|
||||
pk, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyID := make([]byte, 20)
|
||||
if _, err := io.ReadFull(rand.Reader, keyID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k := PrivateKey{
|
||||
KeyID: hex.EncodeToString(keyID),
|
||||
PrivateKey: pk,
|
||||
}
|
||||
|
||||
return &k, nil
|
||||
}
|
||||
99
vendor/github.com/coreos/go-oidc/key/manager.go
generated
vendored
99
vendor/github.com/coreos/go-oidc/key/manager.go
generated
vendored
@@ -1,99 +0,0 @@
|
||||
package key
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/jonboulle/clockwork"
|
||||
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
"github.com/coreos/pkg/health"
|
||||
)
|
||||
|
||||
type PrivateKeyManager interface {
|
||||
ExpiresAt() time.Time
|
||||
Signer() (jose.Signer, error)
|
||||
JWKs() ([]jose.JWK, error)
|
||||
PublicKeys() ([]PublicKey, error)
|
||||
|
||||
WritableKeySetRepo
|
||||
health.Checkable
|
||||
}
|
||||
|
||||
func NewPrivateKeyManager() PrivateKeyManager {
|
||||
return &privateKeyManager{
|
||||
clock: clockwork.NewRealClock(),
|
||||
}
|
||||
}
|
||||
|
||||
type privateKeyManager struct {
|
||||
keySet *PrivateKeySet
|
||||
clock clockwork.Clock
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) ExpiresAt() time.Time {
|
||||
if m.keySet == nil {
|
||||
return m.clock.Now().UTC()
|
||||
}
|
||||
|
||||
return m.keySet.ExpiresAt()
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) Signer() (jose.Signer, error) {
|
||||
if err := m.Healthy(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m.keySet.Active().Signer(), nil
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) JWKs() ([]jose.JWK, error) {
|
||||
if err := m.Healthy(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keys := m.keySet.Keys()
|
||||
jwks := make([]jose.JWK, len(keys))
|
||||
for i, k := range keys {
|
||||
jwks[i] = k.JWK()
|
||||
}
|
||||
return jwks, nil
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) PublicKeys() ([]PublicKey, error) {
|
||||
jwks, err := m.JWKs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keys := make([]PublicKey, len(jwks))
|
||||
for i, jwk := range jwks {
|
||||
keys[i] = *NewPublicKey(jwk)
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) Healthy() error {
|
||||
if m.keySet == nil {
|
||||
return errors.New("private key manager uninitialized")
|
||||
}
|
||||
|
||||
if len(m.keySet.Keys()) == 0 {
|
||||
return errors.New("private key manager zero keys")
|
||||
}
|
||||
|
||||
if m.keySet.ExpiresAt().Before(m.clock.Now().UTC()) {
|
||||
return errors.New("private key manager keys expired")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) Set(keySet KeySet) error {
|
||||
privKeySet, ok := keySet.(*PrivateKeySet)
|
||||
if !ok {
|
||||
return errors.New("unable to cast to PrivateKeySet")
|
||||
}
|
||||
|
||||
m.keySet = privKeySet
|
||||
return nil
|
||||
}
|
||||
55
vendor/github.com/coreos/go-oidc/key/repo.go
generated
vendored
55
vendor/github.com/coreos/go-oidc/key/repo.go
generated
vendored
@@ -1,55 +0,0 @@
|
||||
package key
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var ErrorNoKeys = errors.New("no keys found")
|
||||
|
||||
type WritableKeySetRepo interface {
|
||||
Set(KeySet) error
|
||||
}
|
||||
|
||||
type ReadableKeySetRepo interface {
|
||||
Get() (KeySet, error)
|
||||
}
|
||||
|
||||
type PrivateKeySetRepo interface {
|
||||
WritableKeySetRepo
|
||||
ReadableKeySetRepo
|
||||
}
|
||||
|
||||
func NewPrivateKeySetRepo() PrivateKeySetRepo {
|
||||
return &memPrivateKeySetRepo{}
|
||||
}
|
||||
|
||||
type memPrivateKeySetRepo struct {
|
||||
mu sync.RWMutex
|
||||
pks PrivateKeySet
|
||||
}
|
||||
|
||||
func (r *memPrivateKeySetRepo) Set(ks KeySet) error {
|
||||
pks, ok := ks.(*PrivateKeySet)
|
||||
if !ok {
|
||||
return errors.New("unable to cast to PrivateKeySet")
|
||||
} else if pks == nil {
|
||||
return errors.New("nil KeySet")
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
r.pks = *pks
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *memPrivateKeySetRepo) Get() (KeySet, error) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
if r.pks.keys == nil {
|
||||
return nil, ErrorNoKeys
|
||||
}
|
||||
return KeySet(&r.pks), nil
|
||||
}
|
||||
159
vendor/github.com/coreos/go-oidc/key/rotate.go
generated
vendored
159
vendor/github.com/coreos/go-oidc/key/rotate.go
generated
vendored
@@ -1,159 +0,0 @@
|
||||
package key
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
ptime "github.com/coreos/pkg/timeutil"
|
||||
"github.com/jonboulle/clockwork"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorPrivateKeysExpired = errors.New("private keys have expired")
|
||||
)
|
||||
|
||||
func NewPrivateKeyRotator(repo PrivateKeySetRepo, ttl time.Duration) *PrivateKeyRotator {
|
||||
return &PrivateKeyRotator{
|
||||
repo: repo,
|
||||
ttl: ttl,
|
||||
|
||||
keep: 2,
|
||||
generateKey: GeneratePrivateKey,
|
||||
clock: clockwork.NewRealClock(),
|
||||
}
|
||||
}
|
||||
|
||||
type PrivateKeyRotator struct {
|
||||
repo PrivateKeySetRepo
|
||||
generateKey GeneratePrivateKeyFunc
|
||||
clock clockwork.Clock
|
||||
keep int
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
func (r *PrivateKeyRotator) expiresAt() time.Time {
|
||||
return r.clock.Now().UTC().Add(r.ttl)
|
||||
}
|
||||
|
||||
func (r *PrivateKeyRotator) Healthy() error {
|
||||
pks, err := r.privateKeySet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.clock.Now().After(pks.ExpiresAt()) {
|
||||
return ErrorPrivateKeysExpired
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *PrivateKeyRotator) privateKeySet() (*PrivateKeySet, error) {
|
||||
ks, err := r.repo.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pks, ok := ks.(*PrivateKeySet)
|
||||
if !ok {
|
||||
return nil, errors.New("unable to cast to PrivateKeySet")
|
||||
}
|
||||
return pks, nil
|
||||
}
|
||||
|
||||
func (r *PrivateKeyRotator) nextRotation() (time.Duration, error) {
|
||||
pks, err := r.privateKeySet()
|
||||
if err == ErrorNoKeys {
|
||||
return 0, nil
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
now := r.clock.Now()
|
||||
|
||||
// Ideally, we want to rotate after half the TTL has elapsed.
|
||||
idealRotationTime := pks.ExpiresAt().Add(-r.ttl / 2)
|
||||
|
||||
// If we are past the ideal rotation time, rotate immediatly.
|
||||
return max(0, idealRotationTime.Sub(now)), nil
|
||||
}
|
||||
|
||||
func max(a, b time.Duration) time.Duration {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (r *PrivateKeyRotator) Run() chan struct{} {
|
||||
attempt := func() {
|
||||
k, err := r.generateKey()
|
||||
if err != nil {
|
||||
log.Printf("go-oidc: failed generating signing key: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
exp := r.expiresAt()
|
||||
if err := rotatePrivateKeys(r.repo, k, r.keep, exp); err != nil {
|
||||
log.Printf("go-oidc: key rotation failed: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
stop := make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
var nextRotation time.Duration
|
||||
var sleep time.Duration
|
||||
var err error
|
||||
for {
|
||||
if nextRotation, err = r.nextRotation(); err == nil {
|
||||
break
|
||||
}
|
||||
sleep = ptime.ExpBackoff(sleep, time.Minute)
|
||||
log.Printf("go-oidc: error getting nextRotation, retrying in %v: %v", sleep, err)
|
||||
time.Sleep(sleep)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-r.clock.After(nextRotation):
|
||||
attempt()
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return stop
|
||||
}
|
||||
|
||||
func rotatePrivateKeys(repo PrivateKeySetRepo, k *PrivateKey, keep int, exp time.Time) error {
|
||||
ks, err := repo.Get()
|
||||
if err != nil && err != ErrorNoKeys {
|
||||
return err
|
||||
}
|
||||
|
||||
var keys []*PrivateKey
|
||||
if ks != nil {
|
||||
pks, ok := ks.(*PrivateKeySet)
|
||||
if !ok {
|
||||
return errors.New("unable to cast to PrivateKeySet")
|
||||
}
|
||||
keys = pks.Keys()
|
||||
}
|
||||
|
||||
keys = append([]*PrivateKey{k}, keys...)
|
||||
if l := len(keys); l > keep {
|
||||
keys = keys[0:keep]
|
||||
}
|
||||
|
||||
nks := PrivateKeySet{
|
||||
keys: keys,
|
||||
ActiveKeyID: k.ID(),
|
||||
expiresAt: exp,
|
||||
}
|
||||
|
||||
return repo.Set(KeySet(&nks))
|
||||
}
|
||||
91
vendor/github.com/coreos/go-oidc/key/sync.go
generated
vendored
91
vendor/github.com/coreos/go-oidc/key/sync.go
generated
vendored
@@ -1,91 +0,0 @@
|
||||
package key
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/jonboulle/clockwork"
|
||||
|
||||
"github.com/coreos/pkg/timeutil"
|
||||
)
|
||||
|
||||
func NewKeySetSyncer(r ReadableKeySetRepo, w WritableKeySetRepo) *KeySetSyncer {
|
||||
return &KeySetSyncer{
|
||||
readable: r,
|
||||
writable: w,
|
||||
clock: clockwork.NewRealClock(),
|
||||
}
|
||||
}
|
||||
|
||||
type KeySetSyncer struct {
|
||||
readable ReadableKeySetRepo
|
||||
writable WritableKeySetRepo
|
||||
clock clockwork.Clock
|
||||
}
|
||||
|
||||
func (s *KeySetSyncer) Run() chan struct{} {
|
||||
stop := make(chan struct{})
|
||||
go func() {
|
||||
var failing bool
|
||||
var next time.Duration
|
||||
for {
|
||||
exp, err := syncKeySet(s.readable, s.writable, s.clock)
|
||||
if err != nil || exp == 0 {
|
||||
if !failing {
|
||||
failing = true
|
||||
next = time.Second
|
||||
} else {
|
||||
next = timeutil.ExpBackoff(next, time.Minute)
|
||||
}
|
||||
if exp == 0 {
|
||||
log.Printf("Synced to already expired key set, retrying in %v: %v", next, err)
|
||||
|
||||
} else {
|
||||
log.Printf("Failed syncing key set, retrying in %v: %v", next, err)
|
||||
}
|
||||
} else {
|
||||
failing = false
|
||||
next = exp / 2
|
||||
}
|
||||
|
||||
select {
|
||||
case <-s.clock.After(next):
|
||||
continue
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return stop
|
||||
}
|
||||
|
||||
func Sync(r ReadableKeySetRepo, w WritableKeySetRepo) (time.Duration, error) {
|
||||
return syncKeySet(r, w, clockwork.NewRealClock())
|
||||
}
|
||||
|
||||
// syncKeySet copies the keyset from r to the KeySet at w and returns the duration in which the KeySet will expire.
|
||||
// If keyset has already expired, returns a zero duration.
|
||||
func syncKeySet(r ReadableKeySetRepo, w WritableKeySetRepo, clock clockwork.Clock) (exp time.Duration, err error) {
|
||||
var ks KeySet
|
||||
ks, err = r.Get()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if ks == nil {
|
||||
err = errors.New("no source KeySet")
|
||||
return
|
||||
}
|
||||
|
||||
if err = w.Set(ks); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
now := clock.Now()
|
||||
if ks.ExpiresAt().After(now) {
|
||||
exp = ks.ExpiresAt().Sub(now)
|
||||
}
|
||||
return
|
||||
}
|
||||
2
vendor/github.com/coreos/go-oidc/oauth2/doc.go
generated
vendored
2
vendor/github.com/coreos/go-oidc/oauth2/doc.go
generated
vendored
@@ -1,2 +0,0 @@
|
||||
// Package oauth2 is DEPRECATED. Use golang.org/x/oauth instead.
|
||||
package oauth2
|
||||
29
vendor/github.com/coreos/go-oidc/oauth2/error.go
generated
vendored
29
vendor/github.com/coreos/go-oidc/oauth2/error.go
generated
vendored
@@ -1,29 +0,0 @@
|
||||
package oauth2
|
||||
|
||||
const (
|
||||
ErrorAccessDenied = "access_denied"
|
||||
ErrorInvalidClient = "invalid_client"
|
||||
ErrorInvalidGrant = "invalid_grant"
|
||||
ErrorInvalidRequest = "invalid_request"
|
||||
ErrorServerError = "server_error"
|
||||
ErrorUnauthorizedClient = "unauthorized_client"
|
||||
ErrorUnsupportedGrantType = "unsupported_grant_type"
|
||||
ErrorUnsupportedResponseType = "unsupported_response_type"
|
||||
)
|
||||
|
||||
type Error struct {
|
||||
Type string `json:"error"`
|
||||
Description string `json:"error_description,omitempty"`
|
||||
State string `json:"state,omitempty"`
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
if e.Description != "" {
|
||||
return e.Type + ": " + e.Description
|
||||
}
|
||||
return e.Type
|
||||
}
|
||||
|
||||
func NewError(typ string) *Error {
|
||||
return &Error{Type: typ}
|
||||
}
|
||||
416
vendor/github.com/coreos/go-oidc/oauth2/oauth2.go
generated
vendored
416
vendor/github.com/coreos/go-oidc/oauth2/oauth2.go
generated
vendored
@@ -1,416 +0,0 @@
|
||||
package oauth2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
phttp "github.com/coreos/go-oidc/http"
|
||||
)
|
||||
|
||||
// ResponseTypesEqual compares two response_type values. If either
|
||||
// contains a space, it is treated as an unordered list. For example,
|
||||
// comparing "code id_token" and "id_token code" would evaluate to true.
|
||||
func ResponseTypesEqual(r1, r2 string) bool {
|
||||
if !strings.Contains(r1, " ") || !strings.Contains(r2, " ") {
|
||||
// fast route, no split needed
|
||||
return r1 == r2
|
||||
}
|
||||
|
||||
// split, sort, and compare
|
||||
r1Fields := strings.Fields(r1)
|
||||
r2Fields := strings.Fields(r2)
|
||||
if len(r1Fields) != len(r2Fields) {
|
||||
return false
|
||||
}
|
||||
sort.Strings(r1Fields)
|
||||
sort.Strings(r2Fields)
|
||||
for i, r1Field := range r1Fields {
|
||||
if r1Field != r2Fields[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const (
|
||||
// OAuth2.0 response types registered by OIDC.
|
||||
//
|
||||
// See: https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#RegistryContents
|
||||
ResponseTypeCode = "code"
|
||||
ResponseTypeCodeIDToken = "code id_token"
|
||||
ResponseTypeCodeIDTokenToken = "code id_token token"
|
||||
ResponseTypeIDToken = "id_token"
|
||||
ResponseTypeIDTokenToken = "id_token token"
|
||||
ResponseTypeToken = "token"
|
||||
ResponseTypeNone = "none"
|
||||
)
|
||||
|
||||
const (
|
||||
GrantTypeAuthCode = "authorization_code"
|
||||
GrantTypeClientCreds = "client_credentials"
|
||||
GrantTypeUserCreds = "password"
|
||||
GrantTypeImplicit = "implicit"
|
||||
GrantTypeRefreshToken = "refresh_token"
|
||||
|
||||
AuthMethodClientSecretPost = "client_secret_post"
|
||||
AuthMethodClientSecretBasic = "client_secret_basic"
|
||||
AuthMethodClientSecretJWT = "client_secret_jwt"
|
||||
AuthMethodPrivateKeyJWT = "private_key_jwt"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Credentials ClientCredentials
|
||||
Scope []string
|
||||
RedirectURL string
|
||||
AuthURL string
|
||||
TokenURL string
|
||||
|
||||
// Must be one of the AuthMethodXXX methods above. Right now, only
|
||||
// AuthMethodClientSecretPost and AuthMethodClientSecretBasic are supported.
|
||||
AuthMethod string
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
hc phttp.Client
|
||||
creds ClientCredentials
|
||||
scope []string
|
||||
authURL *url.URL
|
||||
redirectURL *url.URL
|
||||
tokenURL *url.URL
|
||||
authMethod string
|
||||
}
|
||||
|
||||
type ClientCredentials struct {
|
||||
ID string
|
||||
Secret string
|
||||
}
|
||||
|
||||
func NewClient(hc phttp.Client, cfg Config) (c *Client, err error) {
|
||||
if len(cfg.Credentials.ID) == 0 {
|
||||
err = errors.New("missing client id")
|
||||
return
|
||||
}
|
||||
|
||||
if len(cfg.Credentials.Secret) == 0 {
|
||||
err = errors.New("missing client secret")
|
||||
return
|
||||
}
|
||||
|
||||
if cfg.AuthMethod == "" {
|
||||
cfg.AuthMethod = AuthMethodClientSecretBasic
|
||||
} else if cfg.AuthMethod != AuthMethodClientSecretPost && cfg.AuthMethod != AuthMethodClientSecretBasic {
|
||||
err = fmt.Errorf("auth method %q is not supported", cfg.AuthMethod)
|
||||
return
|
||||
}
|
||||
|
||||
au, err := phttp.ParseNonEmptyURL(cfg.AuthURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tu, err := phttp.ParseNonEmptyURL(cfg.TokenURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Allow empty redirect URL in the case where the client
|
||||
// only needs to verify a given token.
|
||||
ru, err := url.Parse(cfg.RedirectURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c = &Client{
|
||||
creds: cfg.Credentials,
|
||||
scope: cfg.Scope,
|
||||
redirectURL: ru,
|
||||
authURL: au,
|
||||
tokenURL: tu,
|
||||
hc: hc,
|
||||
authMethod: cfg.AuthMethod,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Return the embedded HTTP client
|
||||
func (c *Client) HttpClient() phttp.Client {
|
||||
return c.hc
|
||||
}
|
||||
|
||||
// Generate the url for initial redirect to oauth provider.
|
||||
func (c *Client) AuthCodeURL(state, accessType, prompt string) string {
|
||||
v := c.commonURLValues()
|
||||
v.Set("state", state)
|
||||
if strings.ToLower(accessType) == "offline" {
|
||||
v.Set("access_type", "offline")
|
||||
}
|
||||
|
||||
if prompt != "" {
|
||||
v.Set("prompt", prompt)
|
||||
}
|
||||
v.Set("response_type", "code")
|
||||
|
||||
q := v.Encode()
|
||||
u := *c.authURL
|
||||
if u.RawQuery == "" {
|
||||
u.RawQuery = q
|
||||
} else {
|
||||
u.RawQuery += "&" + q
|
||||
}
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (c *Client) commonURLValues() url.Values {
|
||||
return url.Values{
|
||||
"redirect_uri": {c.redirectURL.String()},
|
||||
"scope": {strings.Join(c.scope, " ")},
|
||||
"client_id": {c.creds.ID},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) newAuthenticatedRequest(urlToken string, values url.Values) (*http.Request, error) {
|
||||
var req *http.Request
|
||||
var err error
|
||||
switch c.authMethod {
|
||||
case AuthMethodClientSecretPost:
|
||||
values.Set("client_secret", c.creds.Secret)
|
||||
req, err = http.NewRequest("POST", urlToken, strings.NewReader(values.Encode()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case AuthMethodClientSecretBasic:
|
||||
req, err = http.NewRequest("POST", urlToken, strings.NewReader(values.Encode()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encodedID := url.QueryEscape(c.creds.ID)
|
||||
encodedSecret := url.QueryEscape(c.creds.Secret)
|
||||
req.SetBasicAuth(encodedID, encodedSecret)
|
||||
default:
|
||||
panic("misconfigured client: auth method not supported")
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
return req, nil
|
||||
|
||||
}
|
||||
|
||||
// ClientCredsToken posts the client id and secret to obtain a token scoped to the OAuth2 client via the "client_credentials" grant type.
|
||||
// May not be supported by all OAuth2 servers.
|
||||
func (c *Client) ClientCredsToken(scope []string) (result TokenResponse, err error) {
|
||||
v := url.Values{
|
||||
"scope": {strings.Join(scope, " ")},
|
||||
"grant_type": {GrantTypeClientCreds},
|
||||
}
|
||||
|
||||
req, err := c.newAuthenticatedRequest(c.tokenURL.String(), v)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := c.hc.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return parseTokenResponse(resp)
|
||||
}
|
||||
|
||||
// UserCredsToken posts the username and password to obtain a token scoped to the OAuth2 client via the "password" grant_type
|
||||
// May not be supported by all OAuth2 servers.
|
||||
func (c *Client) UserCredsToken(username, password string) (result TokenResponse, err error) {
|
||||
v := url.Values{
|
||||
"scope": {strings.Join(c.scope, " ")},
|
||||
"grant_type": {GrantTypeUserCreds},
|
||||
"username": {username},
|
||||
"password": {password},
|
||||
}
|
||||
|
||||
req, err := c.newAuthenticatedRequest(c.tokenURL.String(), v)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := c.hc.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return parseTokenResponse(resp)
|
||||
}
|
||||
|
||||
// RequestToken requests a token from the Token Endpoint with the specified grantType.
|
||||
// If 'grantType' == GrantTypeAuthCode, then 'value' should be the authorization code.
|
||||
// If 'grantType' == GrantTypeRefreshToken, then 'value' should be the refresh token.
|
||||
func (c *Client) RequestToken(grantType, value string) (result TokenResponse, err error) {
|
||||
v := c.commonURLValues()
|
||||
|
||||
v.Set("grant_type", grantType)
|
||||
v.Set("client_secret", c.creds.Secret)
|
||||
switch grantType {
|
||||
case GrantTypeAuthCode:
|
||||
v.Set("code", value)
|
||||
case GrantTypeRefreshToken:
|
||||
v.Set("refresh_token", value)
|
||||
default:
|
||||
err = fmt.Errorf("unsupported grant_type: %v", grantType)
|
||||
return
|
||||
}
|
||||
|
||||
req, err := c.newAuthenticatedRequest(c.tokenURL.String(), v)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := c.hc.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return parseTokenResponse(resp)
|
||||
}
|
||||
|
||||
func parseTokenResponse(resp *http.Response) (result TokenResponse, err error) {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
badStatusCode := resp.StatusCode < 200 || resp.StatusCode > 299
|
||||
|
||||
contentType, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result = TokenResponse{
|
||||
RawBody: body,
|
||||
}
|
||||
|
||||
newError := func(typ, desc, state string) error {
|
||||
if typ == "" {
|
||||
return fmt.Errorf("unrecognized error %s", body)
|
||||
}
|
||||
return &Error{typ, desc, state}
|
||||
}
|
||||
|
||||
if contentType == "application/x-www-form-urlencoded" || contentType == "text/plain" {
|
||||
var vals url.Values
|
||||
vals, err = url.ParseQuery(string(body))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if error := vals.Get("error"); error != "" || badStatusCode {
|
||||
err = newError(error, vals.Get("error_description"), vals.Get("state"))
|
||||
return
|
||||
}
|
||||
e := vals.Get("expires_in")
|
||||
if e == "" {
|
||||
e = vals.Get("expires")
|
||||
}
|
||||
if e != "" {
|
||||
result.Expires, err = strconv.Atoi(e)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
result.AccessToken = vals.Get("access_token")
|
||||
result.TokenType = vals.Get("token_type")
|
||||
result.IDToken = vals.Get("id_token")
|
||||
result.RefreshToken = vals.Get("refresh_token")
|
||||
result.Scope = vals.Get("scope")
|
||||
} else {
|
||||
var r struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
IDToken string `json:"id_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
Scope string `json:"scope"`
|
||||
State string `json:"state"`
|
||||
ExpiresIn json.Number `json:"expires_in"` // Azure AD returns string
|
||||
Expires int `json:"expires"`
|
||||
Error string `json:"error"`
|
||||
Desc string `json:"error_description"`
|
||||
}
|
||||
if err = json.Unmarshal(body, &r); err != nil {
|
||||
return
|
||||
}
|
||||
if r.Error != "" || badStatusCode {
|
||||
err = newError(r.Error, r.Desc, r.State)
|
||||
return
|
||||
}
|
||||
result.AccessToken = r.AccessToken
|
||||
result.TokenType = r.TokenType
|
||||
result.IDToken = r.IDToken
|
||||
result.RefreshToken = r.RefreshToken
|
||||
result.Scope = r.Scope
|
||||
if expiresIn, err := r.ExpiresIn.Int64(); err != nil {
|
||||
result.Expires = r.Expires
|
||||
} else {
|
||||
result.Expires = int(expiresIn)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type TokenResponse struct {
|
||||
AccessToken string
|
||||
TokenType string
|
||||
Expires int
|
||||
IDToken string
|
||||
RefreshToken string // OPTIONAL.
|
||||
Scope string // OPTIONAL, if identical to the scope requested by the client, otherwise, REQUIRED.
|
||||
RawBody []byte // In case callers need some other non-standard info from the token response
|
||||
}
|
||||
|
||||
type AuthCodeRequest struct {
|
||||
ResponseType string
|
||||
ClientID string
|
||||
RedirectURL *url.URL
|
||||
Scope []string
|
||||
State string
|
||||
}
|
||||
|
||||
func ParseAuthCodeRequest(q url.Values) (AuthCodeRequest, error) {
|
||||
acr := AuthCodeRequest{
|
||||
ResponseType: q.Get("response_type"),
|
||||
ClientID: q.Get("client_id"),
|
||||
State: q.Get("state"),
|
||||
Scope: make([]string, 0),
|
||||
}
|
||||
|
||||
qs := strings.TrimSpace(q.Get("scope"))
|
||||
if qs != "" {
|
||||
acr.Scope = strings.Split(qs, " ")
|
||||
}
|
||||
|
||||
err := func() error {
|
||||
if acr.ClientID == "" {
|
||||
return NewError(ErrorInvalidRequest)
|
||||
}
|
||||
|
||||
redirectURL := q.Get("redirect_uri")
|
||||
if redirectURL != "" {
|
||||
ru, err := url.Parse(redirectURL)
|
||||
if err != nil {
|
||||
return NewError(ErrorInvalidRequest)
|
||||
}
|
||||
acr.RedirectURL = ru
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
return acr, err
|
||||
}
|
||||
846
vendor/github.com/coreos/go-oidc/oidc/client.go
generated
vendored
846
vendor/github.com/coreos/go-oidc/oidc/client.go
generated
vendored
@@ -1,846 +0,0 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/mail"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
phttp "github.com/coreos/go-oidc/http"
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
"github.com/coreos/go-oidc/key"
|
||||
"github.com/coreos/go-oidc/oauth2"
|
||||
)
|
||||
|
||||
const (
|
||||
// amount of time that must pass after the last key sync
|
||||
// completes before another attempt may begin
|
||||
keySyncWindow = 5 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultScope = []string{"openid", "email", "profile"}
|
||||
|
||||
supportedAuthMethods = map[string]struct{}{
|
||||
oauth2.AuthMethodClientSecretBasic: struct{}{},
|
||||
oauth2.AuthMethodClientSecretPost: struct{}{},
|
||||
}
|
||||
)
|
||||
|
||||
type ClientCredentials oauth2.ClientCredentials
|
||||
|
||||
type ClientIdentity struct {
|
||||
Credentials ClientCredentials
|
||||
Metadata ClientMetadata
|
||||
}
|
||||
|
||||
type JWAOptions struct {
|
||||
// SigningAlg specifies an JWA alg for signing JWTs.
|
||||
//
|
||||
// Specifying this field implies different actions depending on the context. It may
|
||||
// require objects be serialized and signed as a JWT instead of plain JSON, or
|
||||
// require an existing JWT object use the specified alg.
|
||||
//
|
||||
// See: http://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
|
||||
SigningAlg string
|
||||
// EncryptionAlg, if provided, specifies that the returned or sent object be stored
|
||||
// (or nested) within a JWT object and encrypted with the provided JWA alg.
|
||||
EncryptionAlg string
|
||||
// EncryptionEnc specifies the JWA enc algorithm to use with EncryptionAlg. If
|
||||
// EncryptionAlg is provided and EncryptionEnc is omitted, this field defaults
|
||||
// to A128CBC-HS256.
|
||||
//
|
||||
// If EncryptionEnc is provided EncryptionAlg must also be specified.
|
||||
EncryptionEnc string
|
||||
}
|
||||
|
||||
func (opt JWAOptions) valid() error {
|
||||
if opt.EncryptionEnc != "" && opt.EncryptionAlg == "" {
|
||||
return errors.New("encryption encoding provided with no encryption algorithm")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (opt JWAOptions) defaults() JWAOptions {
|
||||
if opt.EncryptionAlg != "" && opt.EncryptionEnc == "" {
|
||||
opt.EncryptionEnc = jose.EncA128CBCHS256
|
||||
}
|
||||
return opt
|
||||
}
|
||||
|
||||
var (
|
||||
// Ensure ClientMetadata satisfies these interfaces.
|
||||
_ json.Marshaler = &ClientMetadata{}
|
||||
_ json.Unmarshaler = &ClientMetadata{}
|
||||
)
|
||||
|
||||
// ClientMetadata holds metadata that the authorization server associates
|
||||
// with a client identifier. The fields range from human-facing display
|
||||
// strings such as client name, to items that impact the security of the
|
||||
// protocol, such as the list of valid redirect URIs.
|
||||
//
|
||||
// See http://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
|
||||
//
|
||||
// TODO: support language specific claim representations
|
||||
// http://openid.net/specs/openid-connect-registration-1_0.html#LanguagesAndScripts
|
||||
type ClientMetadata struct {
|
||||
RedirectURIs []url.URL // Required
|
||||
|
||||
// A list of OAuth 2.0 "response_type" values that the client wishes to restrict
|
||||
// itself to. Either "code", "token", or another registered extension.
|
||||
//
|
||||
// If omitted, only "code" will be used.
|
||||
ResponseTypes []string
|
||||
// A list of OAuth 2.0 grant types the client wishes to restrict itself to.
|
||||
// The grant type values used by OIDC are "authorization_code", "implicit",
|
||||
// and "refresh_token".
|
||||
//
|
||||
// If ommitted, only "authorization_code" will be used.
|
||||
GrantTypes []string
|
||||
// "native" or "web". If omitted, "web".
|
||||
ApplicationType string
|
||||
|
||||
// List of email addresses.
|
||||
Contacts []mail.Address
|
||||
// Name of client to be presented to the end-user.
|
||||
ClientName string
|
||||
// URL that references a logo for the Client application.
|
||||
LogoURI *url.URL
|
||||
// URL of the home page of the Client.
|
||||
ClientURI *url.URL
|
||||
// Profile data policies and terms of use to be provided to the end user.
|
||||
PolicyURI *url.URL
|
||||
TermsOfServiceURI *url.URL
|
||||
|
||||
// URL to or the value of the client's JSON Web Key Set document.
|
||||
JWKSURI *url.URL
|
||||
JWKS *jose.JWKSet
|
||||
|
||||
// URL referencing a flie with a single JSON array of redirect URIs.
|
||||
SectorIdentifierURI *url.URL
|
||||
|
||||
SubjectType string
|
||||
|
||||
// Options to restrict the JWS alg and enc values used for server responses and requests.
|
||||
IDTokenResponseOptions JWAOptions
|
||||
UserInfoResponseOptions JWAOptions
|
||||
RequestObjectOptions JWAOptions
|
||||
|
||||
// Client requested authorization method and signing options for the token endpoint.
|
||||
//
|
||||
// Defaults to "client_secret_basic"
|
||||
TokenEndpointAuthMethod string
|
||||
TokenEndpointAuthSigningAlg string
|
||||
|
||||
// DefaultMaxAge specifies the maximum amount of time in seconds before an authorized
|
||||
// user must reauthroize.
|
||||
//
|
||||
// If 0, no limitation is placed on the maximum.
|
||||
DefaultMaxAge int64
|
||||
// RequireAuthTime specifies if the auth_time claim in the ID token is required.
|
||||
RequireAuthTime bool
|
||||
|
||||
// Default Authentication Context Class Reference values for authentication requests.
|
||||
DefaultACRValues []string
|
||||
|
||||
// URI that a third party can use to initiate a login by the relaying party.
|
||||
//
|
||||
// See: http://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin
|
||||
InitiateLoginURI *url.URL
|
||||
// Pre-registered request_uri values that may be cached by the server.
|
||||
RequestURIs []url.URL
|
||||
}
|
||||
|
||||
// Defaults returns a shallow copy of ClientMetadata with default
|
||||
// values replacing omitted fields.
|
||||
func (m ClientMetadata) Defaults() ClientMetadata {
|
||||
if len(m.ResponseTypes) == 0 {
|
||||
m.ResponseTypes = []string{oauth2.ResponseTypeCode}
|
||||
}
|
||||
if len(m.GrantTypes) == 0 {
|
||||
m.GrantTypes = []string{oauth2.GrantTypeAuthCode}
|
||||
}
|
||||
if m.ApplicationType == "" {
|
||||
m.ApplicationType = "web"
|
||||
}
|
||||
if m.TokenEndpointAuthMethod == "" {
|
||||
m.TokenEndpointAuthMethod = oauth2.AuthMethodClientSecretBasic
|
||||
}
|
||||
m.IDTokenResponseOptions = m.IDTokenResponseOptions.defaults()
|
||||
m.UserInfoResponseOptions = m.UserInfoResponseOptions.defaults()
|
||||
m.RequestObjectOptions = m.RequestObjectOptions.defaults()
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *ClientMetadata) MarshalJSON() ([]byte, error) {
|
||||
e := m.toEncodableStruct()
|
||||
return json.Marshal(&e)
|
||||
}
|
||||
|
||||
func (m *ClientMetadata) UnmarshalJSON(data []byte) error {
|
||||
var e encodableClientMetadata
|
||||
if err := json.Unmarshal(data, &e); err != nil {
|
||||
return err
|
||||
}
|
||||
meta, err := e.toStruct()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := meta.Valid(); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = meta
|
||||
return nil
|
||||
}
|
||||
|
||||
type encodableClientMetadata struct {
|
||||
RedirectURIs []string `json:"redirect_uris"` // Required
|
||||
ResponseTypes []string `json:"response_types,omitempty"`
|
||||
GrantTypes []string `json:"grant_types,omitempty"`
|
||||
ApplicationType string `json:"application_type,omitempty"`
|
||||
Contacts []string `json:"contacts,omitempty"`
|
||||
ClientName string `json:"client_name,omitempty"`
|
||||
LogoURI string `json:"logo_uri,omitempty"`
|
||||
ClientURI string `json:"client_uri,omitempty"`
|
||||
PolicyURI string `json:"policy_uri,omitempty"`
|
||||
TermsOfServiceURI string `json:"tos_uri,omitempty"`
|
||||
JWKSURI string `json:"jwks_uri,omitempty"`
|
||||
JWKS *jose.JWKSet `json:"jwks,omitempty"`
|
||||
SectorIdentifierURI string `json:"sector_identifier_uri,omitempty"`
|
||||
SubjectType string `json:"subject_type,omitempty"`
|
||||
IDTokenSignedResponseAlg string `json:"id_token_signed_response_alg,omitempty"`
|
||||
IDTokenEncryptedResponseAlg string `json:"id_token_encrypted_response_alg,omitempty"`
|
||||
IDTokenEncryptedResponseEnc string `json:"id_token_encrypted_response_enc,omitempty"`
|
||||
UserInfoSignedResponseAlg string `json:"userinfo_signed_response_alg,omitempty"`
|
||||
UserInfoEncryptedResponseAlg string `json:"userinfo_encrypted_response_alg,omitempty"`
|
||||
UserInfoEncryptedResponseEnc string `json:"userinfo_encrypted_response_enc,omitempty"`
|
||||
RequestObjectSigningAlg string `json:"request_object_signing_alg,omitempty"`
|
||||
RequestObjectEncryptionAlg string `json:"request_object_encryption_alg,omitempty"`
|
||||
RequestObjectEncryptionEnc string `json:"request_object_encryption_enc,omitempty"`
|
||||
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty"`
|
||||
TokenEndpointAuthSigningAlg string `json:"token_endpoint_auth_signing_alg,omitempty"`
|
||||
DefaultMaxAge int64 `json:"default_max_age,omitempty"`
|
||||
RequireAuthTime bool `json:"require_auth_time,omitempty"`
|
||||
DefaultACRValues []string `json:"default_acr_values,omitempty"`
|
||||
InitiateLoginURI string `json:"initiate_login_uri,omitempty"`
|
||||
RequestURIs []string `json:"request_uris,omitempty"`
|
||||
}
|
||||
|
||||
func (c *encodableClientMetadata) toStruct() (ClientMetadata, error) {
|
||||
p := stickyErrParser{}
|
||||
m := ClientMetadata{
|
||||
RedirectURIs: p.parseURIs(c.RedirectURIs, "redirect_uris"),
|
||||
ResponseTypes: c.ResponseTypes,
|
||||
GrantTypes: c.GrantTypes,
|
||||
ApplicationType: c.ApplicationType,
|
||||
Contacts: p.parseEmails(c.Contacts, "contacts"),
|
||||
ClientName: c.ClientName,
|
||||
LogoURI: p.parseURI(c.LogoURI, "logo_uri"),
|
||||
ClientURI: p.parseURI(c.ClientURI, "client_uri"),
|
||||
PolicyURI: p.parseURI(c.PolicyURI, "policy_uri"),
|
||||
TermsOfServiceURI: p.parseURI(c.TermsOfServiceURI, "tos_uri"),
|
||||
JWKSURI: p.parseURI(c.JWKSURI, "jwks_uri"),
|
||||
JWKS: c.JWKS,
|
||||
SectorIdentifierURI: p.parseURI(c.SectorIdentifierURI, "sector_identifier_uri"),
|
||||
SubjectType: c.SubjectType,
|
||||
TokenEndpointAuthMethod: c.TokenEndpointAuthMethod,
|
||||
TokenEndpointAuthSigningAlg: c.TokenEndpointAuthSigningAlg,
|
||||
DefaultMaxAge: c.DefaultMaxAge,
|
||||
RequireAuthTime: c.RequireAuthTime,
|
||||
DefaultACRValues: c.DefaultACRValues,
|
||||
InitiateLoginURI: p.parseURI(c.InitiateLoginURI, "initiate_login_uri"),
|
||||
RequestURIs: p.parseURIs(c.RequestURIs, "request_uris"),
|
||||
IDTokenResponseOptions: JWAOptions{
|
||||
c.IDTokenSignedResponseAlg,
|
||||
c.IDTokenEncryptedResponseAlg,
|
||||
c.IDTokenEncryptedResponseEnc,
|
||||
},
|
||||
UserInfoResponseOptions: JWAOptions{
|
||||
c.UserInfoSignedResponseAlg,
|
||||
c.UserInfoEncryptedResponseAlg,
|
||||
c.UserInfoEncryptedResponseEnc,
|
||||
},
|
||||
RequestObjectOptions: JWAOptions{
|
||||
c.RequestObjectSigningAlg,
|
||||
c.RequestObjectEncryptionAlg,
|
||||
c.RequestObjectEncryptionEnc,
|
||||
},
|
||||
}
|
||||
if p.firstErr != nil {
|
||||
return ClientMetadata{}, p.firstErr
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// stickyErrParser parses URIs and email addresses. Once it encounters
|
||||
// a parse error, subsequent calls become no-op.
|
||||
type stickyErrParser struct {
|
||||
firstErr error
|
||||
}
|
||||
|
||||
func (p *stickyErrParser) parseURI(s, field string) *url.URL {
|
||||
if p.firstErr != nil || s == "" {
|
||||
return nil
|
||||
}
|
||||
u, err := url.Parse(s)
|
||||
if err == nil {
|
||||
if u.Host == "" {
|
||||
err = errors.New("no host in URI")
|
||||
} else if u.Scheme != "http" && u.Scheme != "https" {
|
||||
err = errors.New("invalid URI scheme")
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
p.firstErr = fmt.Errorf("failed to parse %s: %v", field, err)
|
||||
return nil
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
func (p *stickyErrParser) parseURIs(s []string, field string) []url.URL {
|
||||
if p.firstErr != nil || len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
uris := make([]url.URL, len(s))
|
||||
for i, val := range s {
|
||||
if val == "" {
|
||||
p.firstErr = fmt.Errorf("invalid URI in field %s", field)
|
||||
return nil
|
||||
}
|
||||
if u := p.parseURI(val, field); u != nil {
|
||||
uris[i] = *u
|
||||
}
|
||||
}
|
||||
return uris
|
||||
}
|
||||
|
||||
func (p *stickyErrParser) parseEmails(s []string, field string) []mail.Address {
|
||||
if p.firstErr != nil || len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
addrs := make([]mail.Address, len(s))
|
||||
for i, addr := range s {
|
||||
if addr == "" {
|
||||
p.firstErr = fmt.Errorf("invalid email in field %s", field)
|
||||
return nil
|
||||
}
|
||||
a, err := mail.ParseAddress(addr)
|
||||
if err != nil {
|
||||
p.firstErr = fmt.Errorf("invalid email in field %s: %v", field, err)
|
||||
return nil
|
||||
}
|
||||
addrs[i] = *a
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
func (m *ClientMetadata) toEncodableStruct() encodableClientMetadata {
|
||||
return encodableClientMetadata{
|
||||
RedirectURIs: urisToStrings(m.RedirectURIs),
|
||||
ResponseTypes: m.ResponseTypes,
|
||||
GrantTypes: m.GrantTypes,
|
||||
ApplicationType: m.ApplicationType,
|
||||
Contacts: emailsToStrings(m.Contacts),
|
||||
ClientName: m.ClientName,
|
||||
LogoURI: uriToString(m.LogoURI),
|
||||
ClientURI: uriToString(m.ClientURI),
|
||||
PolicyURI: uriToString(m.PolicyURI),
|
||||
TermsOfServiceURI: uriToString(m.TermsOfServiceURI),
|
||||
JWKSURI: uriToString(m.JWKSURI),
|
||||
JWKS: m.JWKS,
|
||||
SectorIdentifierURI: uriToString(m.SectorIdentifierURI),
|
||||
SubjectType: m.SubjectType,
|
||||
IDTokenSignedResponseAlg: m.IDTokenResponseOptions.SigningAlg,
|
||||
IDTokenEncryptedResponseAlg: m.IDTokenResponseOptions.EncryptionAlg,
|
||||
IDTokenEncryptedResponseEnc: m.IDTokenResponseOptions.EncryptionEnc,
|
||||
UserInfoSignedResponseAlg: m.UserInfoResponseOptions.SigningAlg,
|
||||
UserInfoEncryptedResponseAlg: m.UserInfoResponseOptions.EncryptionAlg,
|
||||
UserInfoEncryptedResponseEnc: m.UserInfoResponseOptions.EncryptionEnc,
|
||||
RequestObjectSigningAlg: m.RequestObjectOptions.SigningAlg,
|
||||
RequestObjectEncryptionAlg: m.RequestObjectOptions.EncryptionAlg,
|
||||
RequestObjectEncryptionEnc: m.RequestObjectOptions.EncryptionEnc,
|
||||
TokenEndpointAuthMethod: m.TokenEndpointAuthMethod,
|
||||
TokenEndpointAuthSigningAlg: m.TokenEndpointAuthSigningAlg,
|
||||
DefaultMaxAge: m.DefaultMaxAge,
|
||||
RequireAuthTime: m.RequireAuthTime,
|
||||
DefaultACRValues: m.DefaultACRValues,
|
||||
InitiateLoginURI: uriToString(m.InitiateLoginURI),
|
||||
RequestURIs: urisToStrings(m.RequestURIs),
|
||||
}
|
||||
}
|
||||
|
||||
func uriToString(u *url.URL) string {
|
||||
if u == nil {
|
||||
return ""
|
||||
}
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func urisToStrings(urls []url.URL) []string {
|
||||
if len(urls) == 0 {
|
||||
return nil
|
||||
}
|
||||
sli := make([]string, len(urls))
|
||||
for i, u := range urls {
|
||||
sli[i] = u.String()
|
||||
}
|
||||
return sli
|
||||
}
|
||||
|
||||
func emailsToStrings(addrs []mail.Address) []string {
|
||||
if len(addrs) == 0 {
|
||||
return nil
|
||||
}
|
||||
sli := make([]string, len(addrs))
|
||||
for i, addr := range addrs {
|
||||
sli[i] = addr.String()
|
||||
}
|
||||
return sli
|
||||
}
|
||||
|
||||
// Valid determines if a ClientMetadata conforms with the OIDC specification.
|
||||
//
|
||||
// Valid is called by UnmarshalJSON.
|
||||
//
|
||||
// NOTE(ericchiang): For development purposes Valid does not mandate 'https' for
|
||||
// URLs fields where the OIDC spec requires it. This may change in future releases
|
||||
// of this package. See: https://github.com/coreos/go-oidc/issues/34
|
||||
func (m *ClientMetadata) Valid() error {
|
||||
if len(m.RedirectURIs) == 0 {
|
||||
return errors.New("zero redirect URLs")
|
||||
}
|
||||
|
||||
validURI := func(u *url.URL, fieldName string) error {
|
||||
if u.Host == "" {
|
||||
return fmt.Errorf("no host for uri field %s", fieldName)
|
||||
}
|
||||
if u.Scheme != "http" && u.Scheme != "https" {
|
||||
return fmt.Errorf("uri field %s scheme is not http or https", fieldName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
uris := []struct {
|
||||
val *url.URL
|
||||
name string
|
||||
}{
|
||||
{m.LogoURI, "logo_uri"},
|
||||
{m.ClientURI, "client_uri"},
|
||||
{m.PolicyURI, "policy_uri"},
|
||||
{m.TermsOfServiceURI, "tos_uri"},
|
||||
{m.JWKSURI, "jwks_uri"},
|
||||
{m.SectorIdentifierURI, "sector_identifier_uri"},
|
||||
{m.InitiateLoginURI, "initiate_login_uri"},
|
||||
}
|
||||
|
||||
for _, uri := range uris {
|
||||
if uri.val == nil {
|
||||
continue
|
||||
}
|
||||
if err := validURI(uri.val, uri.name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
uriLists := []struct {
|
||||
vals []url.URL
|
||||
name string
|
||||
}{
|
||||
{m.RedirectURIs, "redirect_uris"},
|
||||
{m.RequestURIs, "request_uris"},
|
||||
}
|
||||
for _, list := range uriLists {
|
||||
for _, uri := range list.vals {
|
||||
if err := validURI(&uri, list.name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
options := []struct {
|
||||
option JWAOptions
|
||||
name string
|
||||
}{
|
||||
{m.IDTokenResponseOptions, "id_token response"},
|
||||
{m.UserInfoResponseOptions, "userinfo response"},
|
||||
{m.RequestObjectOptions, "request_object"},
|
||||
}
|
||||
for _, option := range options {
|
||||
if err := option.option.valid(); err != nil {
|
||||
return fmt.Errorf("invalid JWA values for %s: %v", option.name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ClientRegistrationResponse struct {
|
||||
ClientID string // Required
|
||||
ClientSecret string
|
||||
RegistrationAccessToken string
|
||||
RegistrationClientURI string
|
||||
// If IsZero is true, unspecified.
|
||||
ClientIDIssuedAt time.Time
|
||||
// Time at which the client_secret will expire.
|
||||
// If IsZero is true, it will not expire.
|
||||
ClientSecretExpiresAt time.Time
|
||||
|
||||
ClientMetadata
|
||||
}
|
||||
|
||||
type encodableClientRegistrationResponse struct {
|
||||
ClientID string `json:"client_id"` // Required
|
||||
ClientSecret string `json:"client_secret,omitempty"`
|
||||
RegistrationAccessToken string `json:"registration_access_token,omitempty"`
|
||||
RegistrationClientURI string `json:"registration_client_uri,omitempty"`
|
||||
ClientIDIssuedAt int64 `json:"client_id_issued_at,omitempty"`
|
||||
// Time at which the client_secret will expire, in seconds since the epoch.
|
||||
// If 0 it will not expire.
|
||||
ClientSecretExpiresAt int64 `json:"client_secret_expires_at"` // Required
|
||||
|
||||
encodableClientMetadata
|
||||
}
|
||||
|
||||
func unixToSec(t time.Time) int64 {
|
||||
if t.IsZero() {
|
||||
return 0
|
||||
}
|
||||
return t.Unix()
|
||||
}
|
||||
|
||||
func (c *ClientRegistrationResponse) MarshalJSON() ([]byte, error) {
|
||||
e := encodableClientRegistrationResponse{
|
||||
ClientID: c.ClientID,
|
||||
ClientSecret: c.ClientSecret,
|
||||
RegistrationAccessToken: c.RegistrationAccessToken,
|
||||
RegistrationClientURI: c.RegistrationClientURI,
|
||||
ClientIDIssuedAt: unixToSec(c.ClientIDIssuedAt),
|
||||
ClientSecretExpiresAt: unixToSec(c.ClientSecretExpiresAt),
|
||||
encodableClientMetadata: c.ClientMetadata.toEncodableStruct(),
|
||||
}
|
||||
return json.Marshal(&e)
|
||||
}
|
||||
|
||||
func secToUnix(sec int64) time.Time {
|
||||
if sec == 0 {
|
||||
return time.Time{}
|
||||
}
|
||||
return time.Unix(sec, 0)
|
||||
}
|
||||
|
||||
func (c *ClientRegistrationResponse) UnmarshalJSON(data []byte) error {
|
||||
var e encodableClientRegistrationResponse
|
||||
if err := json.Unmarshal(data, &e); err != nil {
|
||||
return err
|
||||
}
|
||||
if e.ClientID == "" {
|
||||
return errors.New("no client_id in client registration response")
|
||||
}
|
||||
metadata, err := e.encodableClientMetadata.toStruct()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*c = ClientRegistrationResponse{
|
||||
ClientID: e.ClientID,
|
||||
ClientSecret: e.ClientSecret,
|
||||
RegistrationAccessToken: e.RegistrationAccessToken,
|
||||
RegistrationClientURI: e.RegistrationClientURI,
|
||||
ClientIDIssuedAt: secToUnix(e.ClientIDIssuedAt),
|
||||
ClientSecretExpiresAt: secToUnix(e.ClientSecretExpiresAt),
|
||||
ClientMetadata: metadata,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ClientConfig struct {
|
||||
HTTPClient phttp.Client
|
||||
Credentials ClientCredentials
|
||||
Scope []string
|
||||
RedirectURL string
|
||||
ProviderConfig ProviderConfig
|
||||
KeySet key.PublicKeySet
|
||||
}
|
||||
|
||||
func NewClient(cfg ClientConfig) (*Client, error) {
|
||||
// Allow empty redirect URL in the case where the client
|
||||
// only needs to verify a given token.
|
||||
ru, err := url.Parse(cfg.RedirectURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid redirect URL: %v", err)
|
||||
}
|
||||
|
||||
c := Client{
|
||||
credentials: cfg.Credentials,
|
||||
httpClient: cfg.HTTPClient,
|
||||
scope: cfg.Scope,
|
||||
redirectURL: ru.String(),
|
||||
providerConfig: newProviderConfigRepo(cfg.ProviderConfig),
|
||||
keySet: cfg.KeySet,
|
||||
}
|
||||
|
||||
if c.httpClient == nil {
|
||||
c.httpClient = http.DefaultClient
|
||||
}
|
||||
|
||||
if c.scope == nil {
|
||||
c.scope = make([]string, len(DefaultScope))
|
||||
copy(c.scope, DefaultScope)
|
||||
}
|
||||
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
httpClient phttp.Client
|
||||
providerConfig *providerConfigRepo
|
||||
credentials ClientCredentials
|
||||
redirectURL string
|
||||
scope []string
|
||||
keySet key.PublicKeySet
|
||||
providerSyncer *ProviderConfigSyncer
|
||||
|
||||
keySetSyncMutex sync.RWMutex
|
||||
lastKeySetSync time.Time
|
||||
}
|
||||
|
||||
func (c *Client) Healthy() error {
|
||||
now := time.Now().UTC()
|
||||
|
||||
cfg := c.providerConfig.Get()
|
||||
|
||||
if cfg.Empty() {
|
||||
return errors.New("oidc client provider config empty")
|
||||
}
|
||||
|
||||
if !cfg.ExpiresAt.IsZero() && cfg.ExpiresAt.Before(now) {
|
||||
return errors.New("oidc client provider config expired")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) OAuthClient() (*oauth2.Client, error) {
|
||||
cfg := c.providerConfig.Get()
|
||||
authMethod, err := chooseAuthMethod(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ocfg := oauth2.Config{
|
||||
Credentials: oauth2.ClientCredentials(c.credentials),
|
||||
RedirectURL: c.redirectURL,
|
||||
AuthURL: cfg.AuthEndpoint.String(),
|
||||
TokenURL: cfg.TokenEndpoint.String(),
|
||||
Scope: c.scope,
|
||||
AuthMethod: authMethod,
|
||||
}
|
||||
|
||||
return oauth2.NewClient(c.httpClient, ocfg)
|
||||
}
|
||||
|
||||
func chooseAuthMethod(cfg ProviderConfig) (string, error) {
|
||||
if len(cfg.TokenEndpointAuthMethodsSupported) == 0 {
|
||||
return oauth2.AuthMethodClientSecretBasic, nil
|
||||
}
|
||||
|
||||
for _, authMethod := range cfg.TokenEndpointAuthMethodsSupported {
|
||||
if _, ok := supportedAuthMethods[authMethod]; ok {
|
||||
return authMethod, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("no supported auth methods")
|
||||
}
|
||||
|
||||
// SyncProviderConfig starts the provider config syncer
|
||||
func (c *Client) SyncProviderConfig(discoveryURL string) chan struct{} {
|
||||
r := NewHTTPProviderConfigGetter(c.httpClient, discoveryURL)
|
||||
s := NewProviderConfigSyncer(r, c.providerConfig)
|
||||
stop := s.Run()
|
||||
s.WaitUntilInitialSync()
|
||||
return stop
|
||||
}
|
||||
|
||||
func (c *Client) maybeSyncKeys() error {
|
||||
tooSoon := func() bool {
|
||||
return time.Now().UTC().Before(c.lastKeySetSync.Add(keySyncWindow))
|
||||
}
|
||||
|
||||
// ignore request to sync keys if a sync operation has been
|
||||
// attempted too recently
|
||||
if tooSoon() {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.keySetSyncMutex.Lock()
|
||||
defer c.keySetSyncMutex.Unlock()
|
||||
|
||||
// check again, as another goroutine may have been holding
|
||||
// the lock while updating the keys
|
||||
if tooSoon() {
|
||||
return nil
|
||||
}
|
||||
|
||||
cfg := c.providerConfig.Get()
|
||||
r := NewRemotePublicKeyRepo(c.httpClient, cfg.KeysEndpoint.String())
|
||||
w := &clientKeyRepo{client: c}
|
||||
_, err := key.Sync(r, w)
|
||||
c.lastKeySetSync = time.Now().UTC()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type clientKeyRepo struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (r *clientKeyRepo) Set(ks key.KeySet) error {
|
||||
pks, ok := ks.(*key.PublicKeySet)
|
||||
if !ok {
|
||||
return errors.New("unable to cast to PublicKey")
|
||||
}
|
||||
r.client.keySet = *pks
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) ClientCredsToken(scope []string) (jose.JWT, error) {
|
||||
cfg := c.providerConfig.Get()
|
||||
|
||||
if !cfg.SupportsGrantType(oauth2.GrantTypeClientCreds) {
|
||||
return jose.JWT{}, fmt.Errorf("%v grant type is not supported", oauth2.GrantTypeClientCreds)
|
||||
}
|
||||
|
||||
oac, err := c.OAuthClient()
|
||||
if err != nil {
|
||||
return jose.JWT{}, err
|
||||
}
|
||||
|
||||
t, err := oac.ClientCredsToken(scope)
|
||||
if err != nil {
|
||||
return jose.JWT{}, err
|
||||
}
|
||||
|
||||
jwt, err := jose.ParseJWT(t.IDToken)
|
||||
if err != nil {
|
||||
return jose.JWT{}, err
|
||||
}
|
||||
|
||||
return jwt, c.VerifyJWT(jwt)
|
||||
}
|
||||
|
||||
// ExchangeAuthCode exchanges an OAuth2 auth code for an OIDC JWT ID token.
|
||||
func (c *Client) ExchangeAuthCode(code string) (jose.JWT, error) {
|
||||
oac, err := c.OAuthClient()
|
||||
if err != nil {
|
||||
return jose.JWT{}, err
|
||||
}
|
||||
|
||||
t, err := oac.RequestToken(oauth2.GrantTypeAuthCode, code)
|
||||
if err != nil {
|
||||
return jose.JWT{}, err
|
||||
}
|
||||
|
||||
jwt, err := jose.ParseJWT(t.IDToken)
|
||||
if err != nil {
|
||||
return jose.JWT{}, err
|
||||
}
|
||||
|
||||
return jwt, c.VerifyJWT(jwt)
|
||||
}
|
||||
|
||||
// RefreshToken uses a refresh token to exchange for a new OIDC JWT ID Token.
|
||||
func (c *Client) RefreshToken(refreshToken string) (jose.JWT, error) {
|
||||
oac, err := c.OAuthClient()
|
||||
if err != nil {
|
||||
return jose.JWT{}, err
|
||||
}
|
||||
|
||||
t, err := oac.RequestToken(oauth2.GrantTypeRefreshToken, refreshToken)
|
||||
if err != nil {
|
||||
return jose.JWT{}, err
|
||||
}
|
||||
|
||||
jwt, err := jose.ParseJWT(t.IDToken)
|
||||
if err != nil {
|
||||
return jose.JWT{}, err
|
||||
}
|
||||
|
||||
return jwt, c.VerifyJWT(jwt)
|
||||
}
|
||||
|
||||
func (c *Client) VerifyJWT(jwt jose.JWT) error {
|
||||
var keysFunc func() []key.PublicKey
|
||||
if kID, ok := jwt.KeyID(); ok {
|
||||
keysFunc = c.keysFuncWithID(kID)
|
||||
} else {
|
||||
keysFunc = c.keysFuncAll()
|
||||
}
|
||||
|
||||
v := NewJWTVerifier(
|
||||
c.providerConfig.Get().Issuer.String(),
|
||||
c.credentials.ID,
|
||||
c.maybeSyncKeys, keysFunc)
|
||||
|
||||
return v.Verify(jwt)
|
||||
}
|
||||
|
||||
// keysFuncWithID returns a function that retrieves at most unexpired
|
||||
// public key from the Client that matches the provided ID
|
||||
func (c *Client) keysFuncWithID(kID string) func() []key.PublicKey {
|
||||
return func() []key.PublicKey {
|
||||
c.keySetSyncMutex.RLock()
|
||||
defer c.keySetSyncMutex.RUnlock()
|
||||
|
||||
if c.keySet.ExpiresAt().Before(time.Now()) {
|
||||
return []key.PublicKey{}
|
||||
}
|
||||
|
||||
k := c.keySet.Key(kID)
|
||||
if k == nil {
|
||||
return []key.PublicKey{}
|
||||
}
|
||||
|
||||
return []key.PublicKey{*k}
|
||||
}
|
||||
}
|
||||
|
||||
// keysFuncAll returns a function that retrieves all unexpired public
|
||||
// keys from the Client
|
||||
func (c *Client) keysFuncAll() func() []key.PublicKey {
|
||||
return func() []key.PublicKey {
|
||||
c.keySetSyncMutex.RLock()
|
||||
defer c.keySetSyncMutex.RUnlock()
|
||||
|
||||
if c.keySet.ExpiresAt().Before(time.Now()) {
|
||||
return []key.PublicKey{}
|
||||
}
|
||||
|
||||
return c.keySet.Keys()
|
||||
}
|
||||
}
|
||||
|
||||
type providerConfigRepo struct {
|
||||
mu sync.RWMutex
|
||||
config ProviderConfig // do not access directly, use Get()
|
||||
}
|
||||
|
||||
func newProviderConfigRepo(pc ProviderConfig) *providerConfigRepo {
|
||||
return &providerConfigRepo{sync.RWMutex{}, pc}
|
||||
}
|
||||
|
||||
// returns an error to implement ProviderConfigSetter
|
||||
func (r *providerConfigRepo) Set(cfg ProviderConfig) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.config = cfg
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *providerConfigRepo) Get() ProviderConfig {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
return r.config
|
||||
}
|
||||
2
vendor/github.com/coreos/go-oidc/oidc/doc.go
generated
vendored
2
vendor/github.com/coreos/go-oidc/oidc/doc.go
generated
vendored
@@ -1,2 +0,0 @@
|
||||
// Package oidc is DEPRECATED. Use github.com/coreos/go-oidc instead.
|
||||
package oidc
|
||||
44
vendor/github.com/coreos/go-oidc/oidc/identity.go
generated
vendored
44
vendor/github.com/coreos/go-oidc/oidc/identity.go
generated
vendored
@@ -1,44 +0,0 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
)
|
||||
|
||||
type Identity struct {
|
||||
ID string
|
||||
Name string
|
||||
Email string
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
func IdentityFromClaims(claims jose.Claims) (*Identity, error) {
|
||||
if claims == nil {
|
||||
return nil, errors.New("nil claim set")
|
||||
}
|
||||
|
||||
var ident Identity
|
||||
var err error
|
||||
var ok bool
|
||||
|
||||
if ident.ID, ok, err = claims.StringClaim("sub"); err != nil {
|
||||
return nil, err
|
||||
} else if !ok {
|
||||
return nil, errors.New("missing required claim: sub")
|
||||
}
|
||||
|
||||
if ident.Email, _, err = claims.StringClaim("email"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
exp, ok, err := claims.TimeClaim("exp")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if ok {
|
||||
ident.ExpiresAt = exp
|
||||
}
|
||||
|
||||
return &ident, nil
|
||||
}
|
||||
3
vendor/github.com/coreos/go-oidc/oidc/interface.go
generated
vendored
3
vendor/github.com/coreos/go-oidc/oidc/interface.go
generated
vendored
@@ -1,3 +0,0 @@
|
||||
package oidc
|
||||
|
||||
type LoginFunc func(ident Identity, sessionKey string) (redirectURL string, err error)
|
||||
67
vendor/github.com/coreos/go-oidc/oidc/key.go
generated
vendored
67
vendor/github.com/coreos/go-oidc/oidc/key.go
generated
vendored
@@ -1,67 +0,0 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
phttp "github.com/coreos/go-oidc/http"
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
"github.com/coreos/go-oidc/key"
|
||||
)
|
||||
|
||||
// DefaultPublicKeySetTTL is the default TTL set on the PublicKeySet if no
|
||||
// Cache-Control header is provided by the JWK Set document endpoint.
|
||||
const DefaultPublicKeySetTTL = 24 * time.Hour
|
||||
|
||||
// NewRemotePublicKeyRepo is responsible for fetching the JWK Set document.
|
||||
func NewRemotePublicKeyRepo(hc phttp.Client, ep string) *remotePublicKeyRepo {
|
||||
return &remotePublicKeyRepo{hc: hc, ep: ep}
|
||||
}
|
||||
|
||||
type remotePublicKeyRepo struct {
|
||||
hc phttp.Client
|
||||
ep string
|
||||
}
|
||||
|
||||
// Get returns a PublicKeySet fetched from the JWK Set document endpoint. A TTL
|
||||
// is set on the Key Set to avoid it having to be re-retrieved for every
|
||||
// encryption event. This TTL is typically controlled by the endpoint returning
|
||||
// a Cache-Control header, but defaults to 24 hours if no Cache-Control header
|
||||
// is found.
|
||||
func (r *remotePublicKeyRepo) Get() (key.KeySet, error) {
|
||||
req, err := http.NewRequest("GET", r.ep, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := r.hc.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var d struct {
|
||||
Keys []jose.JWK `json:"keys"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(d.Keys) == 0 {
|
||||
return nil, errors.New("zero keys in response")
|
||||
}
|
||||
|
||||
ttl, ok, err := phttp.Cacheable(resp.Header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
ttl = DefaultPublicKeySetTTL
|
||||
}
|
||||
|
||||
exp := time.Now().UTC().Add(ttl)
|
||||
ks := key.NewPublicKeySet(d.Keys, exp)
|
||||
return ks, nil
|
||||
}
|
||||
687
vendor/github.com/coreos/go-oidc/oidc/provider.go
generated
vendored
687
vendor/github.com/coreos/go-oidc/oidc/provider.go
generated
vendored
@@ -1,687 +0,0 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/pkg/timeutil"
|
||||
"github.com/jonboulle/clockwork"
|
||||
|
||||
phttp "github.com/coreos/go-oidc/http"
|
||||
"github.com/coreos/go-oidc/oauth2"
|
||||
)
|
||||
|
||||
const (
|
||||
// Subject Identifier types defined by the OIDC spec. Specifies if the provider
|
||||
// should provide the same sub claim value to all clients (public) or a unique
|
||||
// value for each client (pairwise).
|
||||
//
|
||||
// See: http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
|
||||
SubjectTypePublic = "public"
|
||||
SubjectTypePairwise = "pairwise"
|
||||
)
|
||||
|
||||
var (
|
||||
// Default values for omitted provider config fields.
|
||||
//
|
||||
// Use ProviderConfig's Defaults method to fill a provider config with these values.
|
||||
DefaultGrantTypesSupported = []string{oauth2.GrantTypeAuthCode, oauth2.GrantTypeImplicit}
|
||||
DefaultResponseModesSupported = []string{"query", "fragment"}
|
||||
DefaultTokenEndpointAuthMethodsSupported = []string{oauth2.AuthMethodClientSecretBasic}
|
||||
DefaultClaimTypesSupported = []string{"normal"}
|
||||
)
|
||||
|
||||
const (
|
||||
MaximumProviderConfigSyncInterval = 24 * time.Hour
|
||||
MinimumProviderConfigSyncInterval = time.Minute
|
||||
|
||||
discoveryConfigPath = "/.well-known/openid-configuration"
|
||||
)
|
||||
|
||||
// internally configurable for tests
|
||||
var minimumProviderConfigSyncInterval = MinimumProviderConfigSyncInterval
|
||||
|
||||
var (
|
||||
// Ensure ProviderConfig satisfies these interfaces.
|
||||
_ json.Marshaler = &ProviderConfig{}
|
||||
_ json.Unmarshaler = &ProviderConfig{}
|
||||
)
|
||||
|
||||
// ProviderConfig represents the OpenID Provider Metadata specifying what
|
||||
// configurations a provider supports.
|
||||
//
|
||||
// See: http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
|
||||
type ProviderConfig struct {
|
||||
Issuer *url.URL // Required
|
||||
AuthEndpoint *url.URL // Required
|
||||
TokenEndpoint *url.URL // Required if grant types other than "implicit" are supported
|
||||
UserInfoEndpoint *url.URL
|
||||
KeysEndpoint *url.URL // Required
|
||||
RegistrationEndpoint *url.URL
|
||||
EndSessionEndpoint *url.URL
|
||||
CheckSessionIFrame *url.URL
|
||||
|
||||
// Servers MAY choose not to advertise some supported scope values even when this
|
||||
// parameter is used, although those defined in OpenID Core SHOULD be listed, if supported.
|
||||
ScopesSupported []string
|
||||
// OAuth2.0 response types supported.
|
||||
ResponseTypesSupported []string // Required
|
||||
// OAuth2.0 response modes supported.
|
||||
//
|
||||
// If omitted, defaults to DefaultResponseModesSupported.
|
||||
ResponseModesSupported []string
|
||||
// OAuth2.0 grant types supported.
|
||||
//
|
||||
// If omitted, defaults to DefaultGrantTypesSupported.
|
||||
GrantTypesSupported []string
|
||||
ACRValuesSupported []string
|
||||
// SubjectTypesSupported specifies strategies for providing values for the sub claim.
|
||||
SubjectTypesSupported []string // Required
|
||||
|
||||
// JWA signing and encryption algorith values supported for ID tokens.
|
||||
IDTokenSigningAlgValues []string // Required
|
||||
IDTokenEncryptionAlgValues []string
|
||||
IDTokenEncryptionEncValues []string
|
||||
|
||||
// JWA signing and encryption algorith values supported for user info responses.
|
||||
UserInfoSigningAlgValues []string
|
||||
UserInfoEncryptionAlgValues []string
|
||||
UserInfoEncryptionEncValues []string
|
||||
|
||||
// JWA signing and encryption algorith values supported for request objects.
|
||||
ReqObjSigningAlgValues []string
|
||||
ReqObjEncryptionAlgValues []string
|
||||
ReqObjEncryptionEncValues []string
|
||||
|
||||
TokenEndpointAuthMethodsSupported []string
|
||||
TokenEndpointAuthSigningAlgValuesSupported []string
|
||||
DisplayValuesSupported []string
|
||||
ClaimTypesSupported []string
|
||||
ClaimsSupported []string
|
||||
ServiceDocs *url.URL
|
||||
ClaimsLocalsSupported []string
|
||||
UILocalsSupported []string
|
||||
ClaimsParameterSupported bool
|
||||
RequestParameterSupported bool
|
||||
RequestURIParamaterSupported bool
|
||||
RequireRequestURIRegistration bool
|
||||
|
||||
Policy *url.URL
|
||||
TermsOfService *url.URL
|
||||
|
||||
// Not part of the OpenID Provider Metadata
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
// Defaults returns a shallow copy of ProviderConfig with default
|
||||
// values replacing omitted fields.
|
||||
//
|
||||
// var cfg oidc.ProviderConfig
|
||||
// // Fill provider config with default values for omitted fields.
|
||||
// cfg = cfg.Defaults()
|
||||
//
|
||||
func (p ProviderConfig) Defaults() ProviderConfig {
|
||||
setDefault := func(val *[]string, defaultVal []string) {
|
||||
if len(*val) == 0 {
|
||||
*val = defaultVal
|
||||
}
|
||||
}
|
||||
setDefault(&p.GrantTypesSupported, DefaultGrantTypesSupported)
|
||||
setDefault(&p.ResponseModesSupported, DefaultResponseModesSupported)
|
||||
setDefault(&p.TokenEndpointAuthMethodsSupported, DefaultTokenEndpointAuthMethodsSupported)
|
||||
setDefault(&p.ClaimTypesSupported, DefaultClaimTypesSupported)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *ProviderConfig) MarshalJSON() ([]byte, error) {
|
||||
e := p.toEncodableStruct()
|
||||
return json.Marshal(&e)
|
||||
}
|
||||
|
||||
func (p *ProviderConfig) UnmarshalJSON(data []byte) error {
|
||||
var e encodableProviderConfig
|
||||
if err := json.Unmarshal(data, &e); err != nil {
|
||||
return err
|
||||
}
|
||||
conf, err := e.toStruct()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := conf.Valid(); err != nil {
|
||||
return err
|
||||
}
|
||||
*p = conf
|
||||
return nil
|
||||
}
|
||||
|
||||
type encodableProviderConfig struct {
|
||||
Issuer string `json:"issuer"`
|
||||
AuthEndpoint string `json:"authorization_endpoint"`
|
||||
TokenEndpoint string `json:"token_endpoint"`
|
||||
UserInfoEndpoint string `json:"userinfo_endpoint,omitempty"`
|
||||
KeysEndpoint string `json:"jwks_uri"`
|
||||
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
|
||||
EndSessionEndpoint string `json:"end_session_endpoint,omitempty"`
|
||||
CheckSessionIFrame string `json:"check_session_iframe,omitempty"`
|
||||
|
||||
// Use 'omitempty' for all slices as per OIDC spec:
|
||||
// "Claims that return multiple values are represented as JSON arrays.
|
||||
// Claims with zero elements MUST be omitted from the response."
|
||||
// http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse
|
||||
|
||||
ScopesSupported []string `json:"scopes_supported,omitempty"`
|
||||
ResponseTypesSupported []string `json:"response_types_supported,omitempty"`
|
||||
ResponseModesSupported []string `json:"response_modes_supported,omitempty"`
|
||||
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
|
||||
ACRValuesSupported []string `json:"acr_values_supported,omitempty"`
|
||||
SubjectTypesSupported []string `json:"subject_types_supported,omitempty"`
|
||||
|
||||
IDTokenSigningAlgValues []string `json:"id_token_signing_alg_values_supported,omitempty"`
|
||||
IDTokenEncryptionAlgValues []string `json:"id_token_encryption_alg_values_supported,omitempty"`
|
||||
IDTokenEncryptionEncValues []string `json:"id_token_encryption_enc_values_supported,omitempty"`
|
||||
UserInfoSigningAlgValues []string `json:"userinfo_signing_alg_values_supported,omitempty"`
|
||||
UserInfoEncryptionAlgValues []string `json:"userinfo_encryption_alg_values_supported,omitempty"`
|
||||
UserInfoEncryptionEncValues []string `json:"userinfo_encryption_enc_values_supported,omitempty"`
|
||||
ReqObjSigningAlgValues []string `json:"request_object_signing_alg_values_supported,omitempty"`
|
||||
ReqObjEncryptionAlgValues []string `json:"request_object_encryption_alg_values_supported,omitempty"`
|
||||
ReqObjEncryptionEncValues []string `json:"request_object_encryption_enc_values_supported,omitempty"`
|
||||
|
||||
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
|
||||
TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
|
||||
|
||||
DisplayValuesSupported []string `json:"display_values_supported,omitempty"`
|
||||
ClaimTypesSupported []string `json:"claim_types_supported,omitempty"`
|
||||
ClaimsSupported []string `json:"claims_supported,omitempty"`
|
||||
ServiceDocs string `json:"service_documentation,omitempty"`
|
||||
ClaimsLocalsSupported []string `json:"claims_locales_supported,omitempty"`
|
||||
UILocalsSupported []string `json:"ui_locales_supported,omitempty"`
|
||||
ClaimsParameterSupported bool `json:"claims_parameter_supported,omitempty"`
|
||||
RequestParameterSupported bool `json:"request_parameter_supported,omitempty"`
|
||||
RequestURIParamaterSupported bool `json:"request_uri_parameter_supported,omitempty"`
|
||||
RequireRequestURIRegistration bool `json:"require_request_uri_registration,omitempty"`
|
||||
|
||||
Policy string `json:"op_policy_uri,omitempty"`
|
||||
TermsOfService string `json:"op_tos_uri,omitempty"`
|
||||
}
|
||||
|
||||
func (cfg ProviderConfig) toEncodableStruct() encodableProviderConfig {
|
||||
return encodableProviderConfig{
|
||||
Issuer: uriToString(cfg.Issuer),
|
||||
AuthEndpoint: uriToString(cfg.AuthEndpoint),
|
||||
TokenEndpoint: uriToString(cfg.TokenEndpoint),
|
||||
UserInfoEndpoint: uriToString(cfg.UserInfoEndpoint),
|
||||
KeysEndpoint: uriToString(cfg.KeysEndpoint),
|
||||
RegistrationEndpoint: uriToString(cfg.RegistrationEndpoint),
|
||||
EndSessionEndpoint: uriToString(cfg.EndSessionEndpoint),
|
||||
CheckSessionIFrame: uriToString(cfg.CheckSessionIFrame),
|
||||
ScopesSupported: cfg.ScopesSupported,
|
||||
ResponseTypesSupported: cfg.ResponseTypesSupported,
|
||||
ResponseModesSupported: cfg.ResponseModesSupported,
|
||||
GrantTypesSupported: cfg.GrantTypesSupported,
|
||||
ACRValuesSupported: cfg.ACRValuesSupported,
|
||||
SubjectTypesSupported: cfg.SubjectTypesSupported,
|
||||
IDTokenSigningAlgValues: cfg.IDTokenSigningAlgValues,
|
||||
IDTokenEncryptionAlgValues: cfg.IDTokenEncryptionAlgValues,
|
||||
IDTokenEncryptionEncValues: cfg.IDTokenEncryptionEncValues,
|
||||
UserInfoSigningAlgValues: cfg.UserInfoSigningAlgValues,
|
||||
UserInfoEncryptionAlgValues: cfg.UserInfoEncryptionAlgValues,
|
||||
UserInfoEncryptionEncValues: cfg.UserInfoEncryptionEncValues,
|
||||
ReqObjSigningAlgValues: cfg.ReqObjSigningAlgValues,
|
||||
ReqObjEncryptionAlgValues: cfg.ReqObjEncryptionAlgValues,
|
||||
ReqObjEncryptionEncValues: cfg.ReqObjEncryptionEncValues,
|
||||
TokenEndpointAuthMethodsSupported: cfg.TokenEndpointAuthMethodsSupported,
|
||||
TokenEndpointAuthSigningAlgValuesSupported: cfg.TokenEndpointAuthSigningAlgValuesSupported,
|
||||
DisplayValuesSupported: cfg.DisplayValuesSupported,
|
||||
ClaimTypesSupported: cfg.ClaimTypesSupported,
|
||||
ClaimsSupported: cfg.ClaimsSupported,
|
||||
ServiceDocs: uriToString(cfg.ServiceDocs),
|
||||
ClaimsLocalsSupported: cfg.ClaimsLocalsSupported,
|
||||
UILocalsSupported: cfg.UILocalsSupported,
|
||||
ClaimsParameterSupported: cfg.ClaimsParameterSupported,
|
||||
RequestParameterSupported: cfg.RequestParameterSupported,
|
||||
RequestURIParamaterSupported: cfg.RequestURIParamaterSupported,
|
||||
RequireRequestURIRegistration: cfg.RequireRequestURIRegistration,
|
||||
Policy: uriToString(cfg.Policy),
|
||||
TermsOfService: uriToString(cfg.TermsOfService),
|
||||
}
|
||||
}
|
||||
|
||||
func (e encodableProviderConfig) toStruct() (ProviderConfig, error) {
|
||||
p := stickyErrParser{}
|
||||
conf := ProviderConfig{
|
||||
Issuer: p.parseURI(e.Issuer, "issuer"),
|
||||
AuthEndpoint: p.parseURI(e.AuthEndpoint, "authorization_endpoint"),
|
||||
TokenEndpoint: p.parseURI(e.TokenEndpoint, "token_endpoint"),
|
||||
UserInfoEndpoint: p.parseURI(e.UserInfoEndpoint, "userinfo_endpoint"),
|
||||
KeysEndpoint: p.parseURI(e.KeysEndpoint, "jwks_uri"),
|
||||
RegistrationEndpoint: p.parseURI(e.RegistrationEndpoint, "registration_endpoint"),
|
||||
EndSessionEndpoint: p.parseURI(e.EndSessionEndpoint, "end_session_endpoint"),
|
||||
CheckSessionIFrame: p.parseURI(e.CheckSessionIFrame, "check_session_iframe"),
|
||||
ScopesSupported: e.ScopesSupported,
|
||||
ResponseTypesSupported: e.ResponseTypesSupported,
|
||||
ResponseModesSupported: e.ResponseModesSupported,
|
||||
GrantTypesSupported: e.GrantTypesSupported,
|
||||
ACRValuesSupported: e.ACRValuesSupported,
|
||||
SubjectTypesSupported: e.SubjectTypesSupported,
|
||||
IDTokenSigningAlgValues: e.IDTokenSigningAlgValues,
|
||||
IDTokenEncryptionAlgValues: e.IDTokenEncryptionAlgValues,
|
||||
IDTokenEncryptionEncValues: e.IDTokenEncryptionEncValues,
|
||||
UserInfoSigningAlgValues: e.UserInfoSigningAlgValues,
|
||||
UserInfoEncryptionAlgValues: e.UserInfoEncryptionAlgValues,
|
||||
UserInfoEncryptionEncValues: e.UserInfoEncryptionEncValues,
|
||||
ReqObjSigningAlgValues: e.ReqObjSigningAlgValues,
|
||||
ReqObjEncryptionAlgValues: e.ReqObjEncryptionAlgValues,
|
||||
ReqObjEncryptionEncValues: e.ReqObjEncryptionEncValues,
|
||||
TokenEndpointAuthMethodsSupported: e.TokenEndpointAuthMethodsSupported,
|
||||
TokenEndpointAuthSigningAlgValuesSupported: e.TokenEndpointAuthSigningAlgValuesSupported,
|
||||
DisplayValuesSupported: e.DisplayValuesSupported,
|
||||
ClaimTypesSupported: e.ClaimTypesSupported,
|
||||
ClaimsSupported: e.ClaimsSupported,
|
||||
ServiceDocs: p.parseURI(e.ServiceDocs, "service_documentation"),
|
||||
ClaimsLocalsSupported: e.ClaimsLocalsSupported,
|
||||
UILocalsSupported: e.UILocalsSupported,
|
||||
ClaimsParameterSupported: e.ClaimsParameterSupported,
|
||||
RequestParameterSupported: e.RequestParameterSupported,
|
||||
RequestURIParamaterSupported: e.RequestURIParamaterSupported,
|
||||
RequireRequestURIRegistration: e.RequireRequestURIRegistration,
|
||||
Policy: p.parseURI(e.Policy, "op_policy-uri"),
|
||||
TermsOfService: p.parseURI(e.TermsOfService, "op_tos_uri"),
|
||||
}
|
||||
if p.firstErr != nil {
|
||||
return ProviderConfig{}, p.firstErr
|
||||
}
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
// Empty returns if a ProviderConfig holds no information.
|
||||
//
|
||||
// This case generally indicates a ProviderConfigGetter has experienced an error
|
||||
// and has nothing to report.
|
||||
func (p ProviderConfig) Empty() bool {
|
||||
return p.Issuer == nil
|
||||
}
|
||||
|
||||
func contains(sli []string, ele string) bool {
|
||||
for _, s := range sli {
|
||||
if s == ele {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Valid determines if a ProviderConfig conforms with the OIDC specification.
|
||||
// If Valid returns successfully it guarantees required field are non-nil and
|
||||
// URLs are well formed.
|
||||
//
|
||||
// Valid is called by UnmarshalJSON.
|
||||
//
|
||||
// NOTE(ericchiang): For development purposes Valid does not mandate 'https' for
|
||||
// URLs fields where the OIDC spec requires it. This may change in future releases
|
||||
// of this package. See: https://github.com/coreos/go-oidc/issues/34
|
||||
func (p ProviderConfig) Valid() error {
|
||||
grantTypes := p.GrantTypesSupported
|
||||
if len(grantTypes) == 0 {
|
||||
grantTypes = DefaultGrantTypesSupported
|
||||
}
|
||||
implicitOnly := true
|
||||
for _, grantType := range grantTypes {
|
||||
if grantType != oauth2.GrantTypeImplicit {
|
||||
implicitOnly = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(p.SubjectTypesSupported) == 0 {
|
||||
return errors.New("missing required field subject_types_supported")
|
||||
}
|
||||
if len(p.IDTokenSigningAlgValues) == 0 {
|
||||
return errors.New("missing required field id_token_signing_alg_values_supported")
|
||||
}
|
||||
|
||||
if len(p.ScopesSupported) != 0 && !contains(p.ScopesSupported, "openid") {
|
||||
return errors.New("scoped_supported must be unspecified or include 'openid'")
|
||||
}
|
||||
|
||||
if !contains(p.IDTokenSigningAlgValues, "RS256") {
|
||||
return errors.New("id_token_signing_alg_values_supported must include 'RS256'")
|
||||
}
|
||||
|
||||
uris := []struct {
|
||||
val *url.URL
|
||||
name string
|
||||
required bool
|
||||
}{
|
||||
{p.Issuer, "issuer", true},
|
||||
{p.AuthEndpoint, "authorization_endpoint", true},
|
||||
{p.TokenEndpoint, "token_endpoint", !implicitOnly},
|
||||
{p.UserInfoEndpoint, "userinfo_endpoint", false},
|
||||
{p.KeysEndpoint, "jwks_uri", true},
|
||||
{p.RegistrationEndpoint, "registration_endpoint", false},
|
||||
{p.EndSessionEndpoint, "end_session_endpoint", false},
|
||||
{p.CheckSessionIFrame, "check_session_iframe", false},
|
||||
{p.ServiceDocs, "service_documentation", false},
|
||||
{p.Policy, "op_policy_uri", false},
|
||||
{p.TermsOfService, "op_tos_uri", false},
|
||||
}
|
||||
|
||||
for _, uri := range uris {
|
||||
if uri.val == nil {
|
||||
if !uri.required {
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("empty value for required uri field %s", uri.name)
|
||||
}
|
||||
if uri.val.Host == "" {
|
||||
return fmt.Errorf("no host for uri field %s", uri.name)
|
||||
}
|
||||
if uri.val.Scheme != "http" && uri.val.Scheme != "https" {
|
||||
return fmt.Errorf("uri field %s schemeis not http or https", uri.name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Supports determines if provider supports a client given their respective metadata.
|
||||
func (p ProviderConfig) Supports(c ClientMetadata) error {
|
||||
if err := p.Valid(); err != nil {
|
||||
return fmt.Errorf("invalid provider config: %v", err)
|
||||
}
|
||||
if err := c.Valid(); err != nil {
|
||||
return fmt.Errorf("invalid client config: %v", err)
|
||||
}
|
||||
|
||||
// Fill default values for omitted fields
|
||||
c = c.Defaults()
|
||||
p = p.Defaults()
|
||||
|
||||
// Do the supported values list the requested one?
|
||||
supports := []struct {
|
||||
supported []string
|
||||
requested string
|
||||
name string
|
||||
}{
|
||||
{p.IDTokenSigningAlgValues, c.IDTokenResponseOptions.SigningAlg, "id_token_signed_response_alg"},
|
||||
{p.IDTokenEncryptionAlgValues, c.IDTokenResponseOptions.EncryptionAlg, "id_token_encryption_response_alg"},
|
||||
{p.IDTokenEncryptionEncValues, c.IDTokenResponseOptions.EncryptionEnc, "id_token_encryption_response_enc"},
|
||||
{p.UserInfoSigningAlgValues, c.UserInfoResponseOptions.SigningAlg, "userinfo_signed_response_alg"},
|
||||
{p.UserInfoEncryptionAlgValues, c.UserInfoResponseOptions.EncryptionAlg, "userinfo_encryption_response_alg"},
|
||||
{p.UserInfoEncryptionEncValues, c.UserInfoResponseOptions.EncryptionEnc, "userinfo_encryption_response_enc"},
|
||||
{p.ReqObjSigningAlgValues, c.RequestObjectOptions.SigningAlg, "request_object_signing_alg"},
|
||||
{p.ReqObjEncryptionAlgValues, c.RequestObjectOptions.EncryptionAlg, "request_object_encryption_alg"},
|
||||
{p.ReqObjEncryptionEncValues, c.RequestObjectOptions.EncryptionEnc, "request_object_encryption_enc"},
|
||||
}
|
||||
for _, field := range supports {
|
||||
if field.requested == "" {
|
||||
continue
|
||||
}
|
||||
if !contains(field.supported, field.requested) {
|
||||
return fmt.Errorf("provider does not support requested value for field %s", field.name)
|
||||
}
|
||||
}
|
||||
|
||||
stringsEqual := func(s1, s2 string) bool { return s1 == s2 }
|
||||
|
||||
// For lists, are the list of requested values a subset of the supported ones?
|
||||
supportsAll := []struct {
|
||||
supported []string
|
||||
requested []string
|
||||
name string
|
||||
// OAuth2.0 response_type can be space separated lists where order doesn't matter.
|
||||
// For example "id_token token" is the same as "token id_token"
|
||||
// Support a custom compare method.
|
||||
comp func(s1, s2 string) bool
|
||||
}{
|
||||
{p.GrantTypesSupported, c.GrantTypes, "grant_types", stringsEqual},
|
||||
{p.ResponseTypesSupported, c.ResponseTypes, "response_type", oauth2.ResponseTypesEqual},
|
||||
}
|
||||
for _, field := range supportsAll {
|
||||
requestLoop:
|
||||
for _, req := range field.requested {
|
||||
for _, sup := range field.supported {
|
||||
if field.comp(req, sup) {
|
||||
continue requestLoop
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("provider does not support requested value for field %s", field.name)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(ericchiang): Are there more checks we feel comfortable with begin strict about?
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p ProviderConfig) SupportsGrantType(grantType string) bool {
|
||||
var supported []string
|
||||
if len(p.GrantTypesSupported) == 0 {
|
||||
supported = DefaultGrantTypesSupported
|
||||
} else {
|
||||
supported = p.GrantTypesSupported
|
||||
}
|
||||
|
||||
for _, t := range supported {
|
||||
if t == grantType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ProviderConfigGetter interface {
|
||||
Get() (ProviderConfig, error)
|
||||
}
|
||||
|
||||
type ProviderConfigSetter interface {
|
||||
Set(ProviderConfig) error
|
||||
}
|
||||
|
||||
type ProviderConfigSyncer struct {
|
||||
from ProviderConfigGetter
|
||||
to ProviderConfigSetter
|
||||
clock clockwork.Clock
|
||||
|
||||
initialSyncDone bool
|
||||
initialSyncWait sync.WaitGroup
|
||||
}
|
||||
|
||||
func NewProviderConfigSyncer(from ProviderConfigGetter, to ProviderConfigSetter) *ProviderConfigSyncer {
|
||||
return &ProviderConfigSyncer{
|
||||
from: from,
|
||||
to: to,
|
||||
clock: clockwork.NewRealClock(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ProviderConfigSyncer) Run() chan struct{} {
|
||||
stop := make(chan struct{})
|
||||
|
||||
var next pcsStepper
|
||||
next = &pcsStepNext{aft: time.Duration(0)}
|
||||
|
||||
s.initialSyncWait.Add(1)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-s.clock.After(next.after()):
|
||||
next = next.step(s.sync)
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return stop
|
||||
}
|
||||
|
||||
func (s *ProviderConfigSyncer) WaitUntilInitialSync() {
|
||||
s.initialSyncWait.Wait()
|
||||
}
|
||||
|
||||
func (s *ProviderConfigSyncer) sync() (time.Duration, error) {
|
||||
cfg, err := s.from.Get()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err = s.to.Set(cfg); err != nil {
|
||||
return 0, fmt.Errorf("error setting provider config: %v", err)
|
||||
}
|
||||
|
||||
if !s.initialSyncDone {
|
||||
s.initialSyncWait.Done()
|
||||
s.initialSyncDone = true
|
||||
}
|
||||
|
||||
return nextSyncAfter(cfg.ExpiresAt, s.clock), nil
|
||||
}
|
||||
|
||||
type pcsStepFunc func() (time.Duration, error)
|
||||
|
||||
type pcsStepper interface {
|
||||
after() time.Duration
|
||||
step(pcsStepFunc) pcsStepper
|
||||
}
|
||||
|
||||
type pcsStepNext struct {
|
||||
aft time.Duration
|
||||
}
|
||||
|
||||
func (n *pcsStepNext) after() time.Duration {
|
||||
return n.aft
|
||||
}
|
||||
|
||||
func (n *pcsStepNext) step(fn pcsStepFunc) (next pcsStepper) {
|
||||
ttl, err := fn()
|
||||
if err == nil {
|
||||
next = &pcsStepNext{aft: ttl}
|
||||
} else {
|
||||
next = &pcsStepRetry{aft: time.Second}
|
||||
log.Printf("go-oidc: provider config sync failed, retrying in %v: %v", next.after(), err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type pcsStepRetry struct {
|
||||
aft time.Duration
|
||||
}
|
||||
|
||||
func (r *pcsStepRetry) after() time.Duration {
|
||||
return r.aft
|
||||
}
|
||||
|
||||
func (r *pcsStepRetry) step(fn pcsStepFunc) (next pcsStepper) {
|
||||
ttl, err := fn()
|
||||
if err == nil {
|
||||
next = &pcsStepNext{aft: ttl}
|
||||
} else {
|
||||
next = &pcsStepRetry{aft: timeutil.ExpBackoff(r.aft, time.Minute)}
|
||||
log.Printf("go-oidc: provider config sync failed, retrying in %v: %v", next.after(), err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func nextSyncAfter(exp time.Time, clock clockwork.Clock) time.Duration {
|
||||
if exp.IsZero() {
|
||||
return MaximumProviderConfigSyncInterval
|
||||
}
|
||||
|
||||
t := exp.Sub(clock.Now()) / 2
|
||||
if t > MaximumProviderConfigSyncInterval {
|
||||
t = MaximumProviderConfigSyncInterval
|
||||
} else if t < minimumProviderConfigSyncInterval {
|
||||
t = minimumProviderConfigSyncInterval
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
type httpProviderConfigGetter struct {
|
||||
hc phttp.Client
|
||||
issuerURL string
|
||||
clock clockwork.Clock
|
||||
}
|
||||
|
||||
func NewHTTPProviderConfigGetter(hc phttp.Client, issuerURL string) *httpProviderConfigGetter {
|
||||
return &httpProviderConfigGetter{
|
||||
hc: hc,
|
||||
issuerURL: issuerURL,
|
||||
clock: clockwork.NewRealClock(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *httpProviderConfigGetter) Get() (cfg ProviderConfig, err error) {
|
||||
// If the Issuer value contains a path component, any terminating / MUST be removed before
|
||||
// appending /.well-known/openid-configuration.
|
||||
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest
|
||||
discoveryURL := strings.TrimSuffix(r.issuerURL, "/") + discoveryConfigPath
|
||||
req, err := http.NewRequest("GET", discoveryURL, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := r.hc.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if err = json.NewDecoder(resp.Body).Decode(&cfg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var ttl time.Duration
|
||||
var ok bool
|
||||
ttl, ok, err = phttp.Cacheable(resp.Header)
|
||||
if err != nil {
|
||||
return
|
||||
} else if ok {
|
||||
cfg.ExpiresAt = r.clock.Now().UTC().Add(ttl)
|
||||
}
|
||||
|
||||
// The issuer value returned MUST be identical to the Issuer URL that was directly used to retrieve the configuration information.
|
||||
// http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationValidation
|
||||
if !urlEqual(cfg.Issuer.String(), r.issuerURL) {
|
||||
err = fmt.Errorf(`"issuer" in config (%v) does not match provided issuer URL (%v)`, cfg.Issuer, r.issuerURL)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func FetchProviderConfig(hc phttp.Client, issuerURL string) (ProviderConfig, error) {
|
||||
if hc == nil {
|
||||
hc = http.DefaultClient
|
||||
}
|
||||
|
||||
g := NewHTTPProviderConfigGetter(hc, issuerURL)
|
||||
return g.Get()
|
||||
}
|
||||
|
||||
func WaitForProviderConfig(hc phttp.Client, issuerURL string) (pcfg ProviderConfig) {
|
||||
return waitForProviderConfig(hc, issuerURL, clockwork.NewRealClock())
|
||||
}
|
||||
|
||||
func waitForProviderConfig(hc phttp.Client, issuerURL string, clock clockwork.Clock) (pcfg ProviderConfig) {
|
||||
var sleep time.Duration
|
||||
var err error
|
||||
for {
|
||||
pcfg, err = FetchProviderConfig(hc, issuerURL)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
sleep = timeutil.ExpBackoff(sleep, time.Minute)
|
||||
fmt.Printf("Failed fetching provider config, trying again in %v: %v\n", sleep, err)
|
||||
time.Sleep(sleep)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
88
vendor/github.com/coreos/go-oidc/oidc/transport.go
generated
vendored
88
vendor/github.com/coreos/go-oidc/oidc/transport.go
generated
vendored
@@ -1,88 +0,0 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
phttp "github.com/coreos/go-oidc/http"
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
)
|
||||
|
||||
type TokenRefresher interface {
|
||||
// Verify checks if the provided token is currently valid or not.
|
||||
Verify(jose.JWT) error
|
||||
|
||||
// Refresh attempts to authenticate and retrieve a new token.
|
||||
Refresh() (jose.JWT, error)
|
||||
}
|
||||
|
||||
type ClientCredsTokenRefresher struct {
|
||||
Issuer string
|
||||
OIDCClient *Client
|
||||
}
|
||||
|
||||
func (c *ClientCredsTokenRefresher) Verify(jwt jose.JWT) (err error) {
|
||||
_, err = VerifyClientClaims(jwt, c.Issuer)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *ClientCredsTokenRefresher) Refresh() (jwt jose.JWT, err error) {
|
||||
if err = c.OIDCClient.Healthy(); err != nil {
|
||||
err = fmt.Errorf("unable to authenticate, unhealthy OIDC client: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
jwt, err = c.OIDCClient.ClientCredsToken([]string{"openid"})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to verify auth code with issuer: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type AuthenticatedTransport struct {
|
||||
TokenRefresher
|
||||
http.RoundTripper
|
||||
|
||||
mu sync.Mutex
|
||||
jwt jose.JWT
|
||||
}
|
||||
|
||||
func (t *AuthenticatedTransport) verifiedJWT() (jose.JWT, error) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
if t.TokenRefresher.Verify(t.jwt) == nil {
|
||||
return t.jwt, nil
|
||||
}
|
||||
|
||||
jwt, err := t.TokenRefresher.Refresh()
|
||||
if err != nil {
|
||||
return jose.JWT{}, fmt.Errorf("unable to acquire valid JWT: %v", err)
|
||||
}
|
||||
|
||||
t.jwt = jwt
|
||||
return t.jwt, nil
|
||||
}
|
||||
|
||||
// SetJWT sets the JWT held by the Transport.
|
||||
// This is useful for cases in which you want to set an initial JWT.
|
||||
func (t *AuthenticatedTransport) SetJWT(jwt jose.JWT) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
t.jwt = jwt
|
||||
}
|
||||
|
||||
func (t *AuthenticatedTransport) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||
jwt, err := t.verifiedJWT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := phttp.CopyRequest(r)
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", jwt.Encode()))
|
||||
return t.RoundTripper.RoundTrip(req)
|
||||
}
|
||||
109
vendor/github.com/coreos/go-oidc/oidc/util.go
generated
vendored
109
vendor/github.com/coreos/go-oidc/oidc/util.go
generated
vendored
@@ -1,109 +0,0 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
)
|
||||
|
||||
// RequestTokenExtractor funcs extract a raw encoded token from a request.
|
||||
type RequestTokenExtractor func(r *http.Request) (string, error)
|
||||
|
||||
// ExtractBearerToken is a RequestTokenExtractor which extracts a bearer token from a request's
|
||||
// Authorization header.
|
||||
func ExtractBearerToken(r *http.Request) (string, error) {
|
||||
ah := r.Header.Get("Authorization")
|
||||
if ah == "" {
|
||||
return "", errors.New("missing Authorization header")
|
||||
}
|
||||
|
||||
if len(ah) <= 6 || strings.ToUpper(ah[0:6]) != "BEARER" {
|
||||
return "", errors.New("should be a bearer token")
|
||||
}
|
||||
|
||||
val := ah[7:]
|
||||
if len(val) == 0 {
|
||||
return "", errors.New("bearer token is empty")
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// CookieTokenExtractor returns a RequestTokenExtractor which extracts a token from the named cookie in a request.
|
||||
func CookieTokenExtractor(cookieName string) RequestTokenExtractor {
|
||||
return func(r *http.Request) (string, error) {
|
||||
ck, err := r.Cookie(cookieName)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("token cookie not found in request: %v", err)
|
||||
}
|
||||
|
||||
if ck.Value == "" {
|
||||
return "", errors.New("token cookie found but is empty")
|
||||
}
|
||||
|
||||
return ck.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
func NewClaims(iss, sub string, aud interface{}, iat, exp time.Time) jose.Claims {
|
||||
return jose.Claims{
|
||||
// required
|
||||
"iss": iss,
|
||||
"sub": sub,
|
||||
"aud": aud,
|
||||
"iat": iat.Unix(),
|
||||
"exp": exp.Unix(),
|
||||
}
|
||||
}
|
||||
|
||||
func GenClientID(hostport string) (string, error) {
|
||||
b, err := randBytes(32)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var host string
|
||||
if strings.Contains(hostport, ":") {
|
||||
host, _, err = net.SplitHostPort(hostport)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
host = hostport
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s@%s", base64.URLEncoding.EncodeToString(b), host), nil
|
||||
}
|
||||
|
||||
func randBytes(n int) ([]byte, error) {
|
||||
b := make([]byte, n)
|
||||
got, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if n != got {
|
||||
return nil, errors.New("unable to generate enough random data")
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// urlEqual checks two urls for equality using only the host and path portions.
|
||||
func urlEqual(url1, url2 string) bool {
|
||||
u1, err := url.Parse(url1)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
u2, err := url.Parse(url2)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return strings.ToLower(u1.Host+u1.Path) == strings.ToLower(u2.Host+u2.Path)
|
||||
}
|
||||
190
vendor/github.com/coreos/go-oidc/oidc/verification.go
generated
vendored
190
vendor/github.com/coreos/go-oidc/oidc/verification.go
generated
vendored
@@ -1,190 +0,0 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jonboulle/clockwork"
|
||||
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
"github.com/coreos/go-oidc/key"
|
||||
)
|
||||
|
||||
func VerifySignature(jwt jose.JWT, keys []key.PublicKey) (bool, error) {
|
||||
jwtBytes := []byte(jwt.Data())
|
||||
for _, k := range keys {
|
||||
v, err := k.Verifier()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if v.Verify(jwt.Signature, jwtBytes) == nil {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// containsString returns true if the given string(needle) is found
|
||||
// in the string array(haystack).
|
||||
func containsString(needle string, haystack []string) bool {
|
||||
for _, v := range haystack {
|
||||
if v == needle {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify claims in accordance with OIDC spec
|
||||
// http://openid.net/specs/openid-connect-basic-1_0.html#IDTokenValidation
|
||||
func VerifyClaims(jwt jose.JWT, issuer, clientID string) error {
|
||||
now := time.Now().UTC()
|
||||
|
||||
claims, err := jwt.Claims()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ident, err := IdentityFromClaims(claims)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ident.ExpiresAt.Before(now) {
|
||||
return errors.New("token is expired")
|
||||
}
|
||||
|
||||
// iss REQUIRED. Issuer Identifier for the Issuer of the response.
|
||||
// The iss value is a case sensitive URL using the https scheme that contains scheme,
|
||||
// host, and optionally, port number and path components and no query or fragment components.
|
||||
if iss, exists := claims["iss"].(string); exists {
|
||||
if !urlEqual(iss, issuer) {
|
||||
return fmt.Errorf("invalid claim value: 'iss'. expected=%s, found=%s.", issuer, iss)
|
||||
}
|
||||
} else {
|
||||
return errors.New("missing claim: 'iss'")
|
||||
}
|
||||
|
||||
// iat REQUIRED. Time at which the JWT was issued.
|
||||
// Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z
|
||||
// as measured in UTC until the date/time.
|
||||
if _, exists := claims["iat"].(float64); !exists {
|
||||
return errors.New("missing claim: 'iat'")
|
||||
}
|
||||
|
||||
// aud REQUIRED. Audience(s) that this ID Token is intended for.
|
||||
// It MUST contain the OAuth 2.0 client_id of the Relying Party as an audience value.
|
||||
// It MAY also contain identifiers for other audiences. In the general case, the aud
|
||||
// value is an array of case sensitive strings. In the common special case when there
|
||||
// is one audience, the aud value MAY be a single case sensitive string.
|
||||
if aud, ok, err := claims.StringClaim("aud"); err == nil && ok {
|
||||
if aud != clientID {
|
||||
return fmt.Errorf("invalid claims, 'aud' claim and 'client_id' do not match, aud=%s, client_id=%s", aud, clientID)
|
||||
}
|
||||
} else if aud, ok, err := claims.StringsClaim("aud"); err == nil && ok {
|
||||
if !containsString(clientID, aud) {
|
||||
return fmt.Errorf("invalid claims, cannot find 'client_id' in 'aud' claim, aud=%v, client_id=%s", aud, clientID)
|
||||
}
|
||||
} else {
|
||||
return errors.New("invalid claim value: 'aud' is required, and should be either string or string array")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyClientClaims verifies all the required claims are valid for a "client credentials" JWT.
|
||||
// Returns the client ID if valid, or an error if invalid.
|
||||
func VerifyClientClaims(jwt jose.JWT, issuer string) (string, error) {
|
||||
claims, err := jwt.Claims()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse JWT claims: %v", err)
|
||||
}
|
||||
|
||||
iss, ok, err := claims.StringClaim("iss")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse 'iss' claim: %v", err)
|
||||
} else if !ok {
|
||||
return "", errors.New("missing required 'iss' claim")
|
||||
} else if !urlEqual(iss, issuer) {
|
||||
return "", fmt.Errorf("'iss' claim does not match expected issuer, iss=%s", iss)
|
||||
}
|
||||
|
||||
sub, ok, err := claims.StringClaim("sub")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse 'sub' claim: %v", err)
|
||||
} else if !ok {
|
||||
return "", errors.New("missing required 'sub' claim")
|
||||
}
|
||||
|
||||
if aud, ok, err := claims.StringClaim("aud"); err == nil && ok {
|
||||
if aud != sub {
|
||||
return "", fmt.Errorf("invalid claims, 'aud' claim and 'sub' claim do not match, aud=%s, sub=%s", aud, sub)
|
||||
}
|
||||
} else if aud, ok, err := claims.StringsClaim("aud"); err == nil && ok {
|
||||
if !containsString(sub, aud) {
|
||||
return "", fmt.Errorf("invalid claims, cannot find 'sud' in 'aud' claim, aud=%v, sub=%s", aud, sub)
|
||||
}
|
||||
} else {
|
||||
return "", errors.New("invalid claim value: 'aud' is required, and should be either string or string array")
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
exp, ok, err := claims.TimeClaim("exp")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse 'exp' claim: %v", err)
|
||||
} else if !ok {
|
||||
return "", errors.New("missing required 'exp' claim")
|
||||
} else if exp.Before(now) {
|
||||
return "", fmt.Errorf("token already expired at: %v", exp)
|
||||
}
|
||||
|
||||
return sub, nil
|
||||
}
|
||||
|
||||
type JWTVerifier struct {
|
||||
issuer string
|
||||
clientID string
|
||||
syncFunc func() error
|
||||
keysFunc func() []key.PublicKey
|
||||
clock clockwork.Clock
|
||||
}
|
||||
|
||||
func NewJWTVerifier(issuer, clientID string, syncFunc func() error, keysFunc func() []key.PublicKey) JWTVerifier {
|
||||
return JWTVerifier{
|
||||
issuer: issuer,
|
||||
clientID: clientID,
|
||||
syncFunc: syncFunc,
|
||||
keysFunc: keysFunc,
|
||||
clock: clockwork.NewRealClock(),
|
||||
}
|
||||
}
|
||||
|
||||
func (v *JWTVerifier) Verify(jwt jose.JWT) error {
|
||||
// Verify claims before verifying the signature. This is an optimization to throw out
|
||||
// tokens we know are invalid without undergoing an expensive signature check and
|
||||
// possibly a re-sync event.
|
||||
if err := VerifyClaims(jwt, v.issuer, v.clientID); err != nil {
|
||||
return fmt.Errorf("oidc: JWT claims invalid: %v", err)
|
||||
}
|
||||
|
||||
ok, err := VerifySignature(jwt, v.keysFunc())
|
||||
if err != nil {
|
||||
return fmt.Errorf("oidc: JWT signature verification failed: %v", err)
|
||||
} else if ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = v.syncFunc(); err != nil {
|
||||
return fmt.Errorf("oidc: failed syncing KeySet: %v", err)
|
||||
}
|
||||
|
||||
ok, err = VerifySignature(jwt, v.keysFunc())
|
||||
if err != nil {
|
||||
return fmt.Errorf("oidc: JWT signature verification failed: %v", err)
|
||||
} else if !ok {
|
||||
return errors.New("oidc: unable to verify JWT signature: no matching keys")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
202
vendor/github.com/coreos/pkg/LICENSE
generated
vendored
202
vendor/github.com/coreos/pkg/LICENSE
generated
vendored
@@ -1,202 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
|
||||
5
vendor/github.com/coreos/pkg/NOTICE
generated
vendored
5
vendor/github.com/coreos/pkg/NOTICE
generated
vendored
@@ -1,5 +0,0 @@
|
||||
CoreOS Project
|
||||
Copyright 2014 CoreOS, Inc
|
||||
|
||||
This product includes software developed at CoreOS, Inc.
|
||||
(http://www.coreos.com/).
|
||||
11
vendor/github.com/coreos/pkg/health/README.md
generated
vendored
11
vendor/github.com/coreos/pkg/health/README.md
generated
vendored
@@ -1,11 +0,0 @@
|
||||
health
|
||||
====
|
||||
|
||||
A simple framework for implementing an HTTP health check endpoint on servers.
|
||||
|
||||
Users implement their `health.Checkable` types, and create a `health.Checker`, from which they can get an `http.HandlerFunc` using `health.Checker.MakeHealthHandlerFunc`.
|
||||
|
||||
### Documentation
|
||||
|
||||
For more details, visit the docs on [gopkgdoc](http://godoc.org/github.com/coreos/pkg/health)
|
||||
|
||||
127
vendor/github.com/coreos/pkg/health/health.go
generated
vendored
127
vendor/github.com/coreos/pkg/health/health.go
generated
vendored
@@ -1,127 +0,0 @@
|
||||
package health
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/coreos/pkg/httputil"
|
||||
)
|
||||
|
||||
// Checkables should return nil when the thing they are checking is healthy, and an error otherwise.
|
||||
type Checkable interface {
|
||||
Healthy() error
|
||||
}
|
||||
|
||||
// Checker provides a way to make an endpoint which can be probed for system health.
|
||||
type Checker struct {
|
||||
// Checks are the Checkables to be checked when probing.
|
||||
Checks []Checkable
|
||||
|
||||
// Unhealthyhandler is called when one or more of the checks are unhealthy.
|
||||
// If not provided DefaultUnhealthyHandler is called.
|
||||
UnhealthyHandler UnhealthyHandler
|
||||
|
||||
// HealthyHandler is called when all checks are healthy.
|
||||
// If not provided, DefaultHealthyHandler is called.
|
||||
HealthyHandler http.HandlerFunc
|
||||
}
|
||||
|
||||
func (c Checker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
unhealthyHandler := c.UnhealthyHandler
|
||||
if unhealthyHandler == nil {
|
||||
unhealthyHandler = DefaultUnhealthyHandler
|
||||
}
|
||||
|
||||
successHandler := c.HealthyHandler
|
||||
if successHandler == nil {
|
||||
successHandler = DefaultHealthyHandler
|
||||
}
|
||||
|
||||
if r.Method != "GET" {
|
||||
w.Header().Set("Allow", "GET")
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
if err := Check(c.Checks); err != nil {
|
||||
unhealthyHandler(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
successHandler(w, r)
|
||||
}
|
||||
|
||||
type UnhealthyHandler func(w http.ResponseWriter, r *http.Request, err error)
|
||||
|
||||
type StatusResponse struct {
|
||||
Status string `json:"status"`
|
||||
Details *StatusResponseDetails `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
type StatusResponseDetails struct {
|
||||
Code int `json:"code,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func Check(checks []Checkable) (err error) {
|
||||
errs := []error{}
|
||||
for _, c := range checks {
|
||||
if e := c.Healthy(); e != nil {
|
||||
errs = append(errs, e)
|
||||
}
|
||||
}
|
||||
|
||||
switch len(errs) {
|
||||
case 0:
|
||||
err = nil
|
||||
case 1:
|
||||
err = errs[0]
|
||||
default:
|
||||
err = fmt.Errorf("multiple health check failure: %v", errs)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func DefaultHealthyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err := httputil.WriteJSONResponse(w, http.StatusOK, StatusResponse{
|
||||
Status: "ok",
|
||||
})
|
||||
if err != nil {
|
||||
// TODO(bobbyrullo): replace with logging from new logging pkg,
|
||||
// once it lands.
|
||||
log.Printf("Failed to write JSON response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultUnhealthyHandler(w http.ResponseWriter, r *http.Request, err error) {
|
||||
writeErr := httputil.WriteJSONResponse(w, http.StatusInternalServerError, StatusResponse{
|
||||
Status: "error",
|
||||
Details: &StatusResponseDetails{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: err.Error(),
|
||||
},
|
||||
})
|
||||
if writeErr != nil {
|
||||
// TODO(bobbyrullo): replace with logging from new logging pkg,
|
||||
// once it lands.
|
||||
log.Printf("Failed to write JSON response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ExpvarHandler is copied from https://golang.org/src/expvar/expvar.go, where it's sadly unexported.
|
||||
func ExpvarHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
fmt.Fprintf(w, "{\n")
|
||||
first := true
|
||||
expvar.Do(func(kv expvar.KeyValue) {
|
||||
if !first {
|
||||
fmt.Fprintf(w, ",\n")
|
||||
}
|
||||
first = false
|
||||
fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
|
||||
})
|
||||
fmt.Fprintf(w, "\n}\n")
|
||||
}
|
||||
13
vendor/github.com/coreos/pkg/httputil/README.md
generated
vendored
13
vendor/github.com/coreos/pkg/httputil/README.md
generated
vendored
@@ -1,13 +0,0 @@
|
||||
httputil
|
||||
====
|
||||
|
||||
Common code for dealing with HTTP.
|
||||
|
||||
Includes:
|
||||
|
||||
* Code for returning JSON responses.
|
||||
|
||||
### Documentation
|
||||
|
||||
Visit the docs on [gopkgdoc](http://godoc.org/github.com/coreos/pkg/httputil)
|
||||
|
||||
21
vendor/github.com/coreos/pkg/httputil/cookie.go
generated
vendored
21
vendor/github.com/coreos/pkg/httputil/cookie.go
generated
vendored
@@ -1,21 +0,0 @@
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DeleteCookies effectively deletes all named cookies
|
||||
// by wiping all data and setting to expire immediately.
|
||||
func DeleteCookies(w http.ResponseWriter, cookieNames ...string) {
|
||||
for _, n := range cookieNames {
|
||||
c := &http.Cookie{
|
||||
Name: n,
|
||||
Value: "",
|
||||
Path: "/",
|
||||
MaxAge: -1,
|
||||
Expires: time.Time{},
|
||||
}
|
||||
http.SetCookie(w, c)
|
||||
}
|
||||
}
|
||||
27
vendor/github.com/coreos/pkg/httputil/json.go
generated
vendored
27
vendor/github.com/coreos/pkg/httputil/json.go
generated
vendored
@@ -1,27 +0,0 @@
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
JSONContentType = "application/json"
|
||||
)
|
||||
|
||||
func WriteJSONResponse(w http.ResponseWriter, code int, resp interface{}) error {
|
||||
enc, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return err
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", JSONContentType)
|
||||
w.WriteHeader(code)
|
||||
|
||||
_, err = w.Write(enc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
15
vendor/github.com/coreos/pkg/timeutil/backoff.go
generated
vendored
15
vendor/github.com/coreos/pkg/timeutil/backoff.go
generated
vendored
@@ -1,15 +0,0 @@
|
||||
package timeutil
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExpBackoff(prev, max time.Duration) time.Duration {
|
||||
if prev == 0 {
|
||||
return time.Second
|
||||
}
|
||||
if prev > max/2 {
|
||||
return max
|
||||
}
|
||||
return 2 * prev
|
||||
}
|
||||
13
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
13
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
@@ -1,13 +0,0 @@
|
||||
Copyright (c) 2012-2013 Dave Collins <dave@davec.name>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
151
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
151
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
@@ -1,151 +0,0 @@
|
||||
// Copyright (c) 2015 Dave Collins <dave@davec.name>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||
// when the code is not running on Google App Engine and "-tags disableunsafe"
|
||||
// is not added to the go build command line.
|
||||
// +build !appengine,!disableunsafe
|
||||
|
||||
package spew
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// UnsafeDisabled is a build-time constant which specifies whether or
|
||||
// not access to the unsafe package is available.
|
||||
UnsafeDisabled = false
|
||||
|
||||
// ptrSize is the size of a pointer on the current arch.
|
||||
ptrSize = unsafe.Sizeof((*byte)(nil))
|
||||
)
|
||||
|
||||
var (
|
||||
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
|
||||
// internal reflect.Value fields. These values are valid before golang
|
||||
// commit ecccf07e7f9d which changed the format. The are also valid
|
||||
// after commit 82f48826c6c7 which changed the format again to mirror
|
||||
// the original format. Code in the init function updates these offsets
|
||||
// as necessary.
|
||||
offsetPtr = uintptr(ptrSize)
|
||||
offsetScalar = uintptr(0)
|
||||
offsetFlag = uintptr(ptrSize * 2)
|
||||
|
||||
// flagKindWidth and flagKindShift indicate various bits that the
|
||||
// reflect package uses internally to track kind information.
|
||||
//
|
||||
// flagRO indicates whether or not the value field of a reflect.Value is
|
||||
// read-only.
|
||||
//
|
||||
// flagIndir indicates whether the value field of a reflect.Value is
|
||||
// the actual data or a pointer to the data.
|
||||
//
|
||||
// These values are valid before golang commit 90a7c3c86944 which
|
||||
// changed their positions. Code in the init function updates these
|
||||
// flags as necessary.
|
||||
flagKindWidth = uintptr(5)
|
||||
flagKindShift = uintptr(flagKindWidth - 1)
|
||||
flagRO = uintptr(1 << 0)
|
||||
flagIndir = uintptr(1 << 1)
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Older versions of reflect.Value stored small integers directly in the
|
||||
// ptr field (which is named val in the older versions). Versions
|
||||
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
|
||||
// scalar for this purpose which unfortunately came before the flag
|
||||
// field, so the offset of the flag field is different for those
|
||||
// versions.
|
||||
//
|
||||
// This code constructs a new reflect.Value from a known small integer
|
||||
// and checks if the size of the reflect.Value struct indicates it has
|
||||
// the scalar field. When it does, the offsets are updated accordingly.
|
||||
vv := reflect.ValueOf(0xf00)
|
||||
if unsafe.Sizeof(vv) == (ptrSize * 4) {
|
||||
offsetScalar = ptrSize * 2
|
||||
offsetFlag = ptrSize * 3
|
||||
}
|
||||
|
||||
// Commit 90a7c3c86944 changed the flag positions such that the low
|
||||
// order bits are the kind. This code extracts the kind from the flags
|
||||
// field and ensures it's the correct type. When it's not, the flag
|
||||
// order has been changed to the newer format, so the flags are updated
|
||||
// accordingly.
|
||||
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
|
||||
upfv := *(*uintptr)(upf)
|
||||
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
|
||||
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
|
||||
flagKindShift = 0
|
||||
flagRO = 1 << 5
|
||||
flagIndir = 1 << 6
|
||||
|
||||
// Commit adf9b30e5594 modified the flags to separate the
|
||||
// flagRO flag into two bits which specifies whether or not the
|
||||
// field is embedded. This causes flagIndir to move over a bit
|
||||
// and means that flagRO is the combination of either of the
|
||||
// original flagRO bit and the new bit.
|
||||
//
|
||||
// This code detects the change by extracting what used to be
|
||||
// the indirect bit to ensure it's set. When it's not, the flag
|
||||
// order has been changed to the newer format, so the flags are
|
||||
// updated accordingly.
|
||||
if upfv&flagIndir == 0 {
|
||||
flagRO = 3 << 5
|
||||
flagIndir = 1 << 7
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
|
||||
// the typical safety restrictions preventing access to unaddressable and
|
||||
// unexported data. It works by digging the raw pointer to the underlying
|
||||
// value out of the protected value and generating a new unprotected (unsafe)
|
||||
// reflect.Value to it.
|
||||
//
|
||||
// This allows us to check for implementations of the Stringer and error
|
||||
// interfaces to be used for pretty printing ordinarily unaddressable and
|
||||
// inaccessible values such as unexported struct fields.
|
||||
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
|
||||
indirects := 1
|
||||
vt := v.Type()
|
||||
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
|
||||
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
|
||||
if rvf&flagIndir != 0 {
|
||||
vt = reflect.PtrTo(v.Type())
|
||||
indirects++
|
||||
} else if offsetScalar != 0 {
|
||||
// The value is in the scalar field when it's not one of the
|
||||
// reference types.
|
||||
switch vt.Kind() {
|
||||
case reflect.Uintptr:
|
||||
case reflect.Chan:
|
||||
case reflect.Func:
|
||||
case reflect.Map:
|
||||
case reflect.Ptr:
|
||||
case reflect.UnsafePointer:
|
||||
default:
|
||||
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
|
||||
offsetScalar)
|
||||
}
|
||||
}
|
||||
|
||||
pv := reflect.NewAt(vt, upv)
|
||||
rv = pv
|
||||
for i := 0; i < indirects; i++ {
|
||||
rv = rv.Elem()
|
||||
}
|
||||
return rv
|
||||
}
|
||||
37
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
37
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
@@ -1,37 +0,0 @@
|
||||
// Copyright (c) 2015 Dave Collins <dave@davec.name>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||
// when either the code is running on Google App Engine or "-tags disableunsafe"
|
||||
// is added to the go build command line.
|
||||
// +build appengine disableunsafe
|
||||
|
||||
package spew
|
||||
|
||||
import "reflect"
|
||||
|
||||
const (
|
||||
// UnsafeDisabled is a build-time constant which specifies whether or
|
||||
// not access to the unsafe package is available.
|
||||
UnsafeDisabled = true
|
||||
)
|
||||
|
||||
// unsafeReflectValue typically converts the passed reflect.Value into a one
|
||||
// that bypasses the typical safety restrictions preventing access to
|
||||
// unaddressable and unexported data. However, doing this relies on access to
|
||||
// the unsafe package. This is a stub version which simply returns the passed
|
||||
// reflect.Value when the unsafe package is not available.
|
||||
func unsafeReflectValue(v reflect.Value) reflect.Value {
|
||||
return v
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user