mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-12 02:15:01 +00:00
Update github.com/russellhaering/goxmldsig to v1.1.0
See https://github.com/russellhaering/goxmldsig/security/advisories/GHSA-q547-gmf8-8jr7
This commit is contained in:
committed by
Andrew Lytvynov
parent
b2faac1d0d
commit
8aacdc1b0f
@@ -11,7 +11,7 @@ require (
|
||||
github.com/alecthomas/repr v0.0.0-20200325044227-4184120f674c // indirect
|
||||
github.com/armon/go-radix v1.0.0
|
||||
github.com/aws/aws-sdk-go v1.32.7
|
||||
github.com/beevik/etree v0.0.0-20170418002358-cda1c0026246
|
||||
github.com/beevik/etree v1.1.0
|
||||
github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26 // indirect
|
||||
github.com/cjbassi/drawille-go v0.1.0 // indirect
|
||||
github.com/codahale/hdrhistogram v0.0.0-20150708134006-954f16e8b9ef
|
||||
@@ -44,7 +44,7 @@ require (
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/iovisor/gobpf v0.0.1
|
||||
github.com/johannesboyne/gofakes3 v0.0.0-20191228161223-9aee1c78a252
|
||||
github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1
|
||||
github.com/jonboulle/clockwork v0.2.1
|
||||
github.com/json-iterator/go v1.1.9
|
||||
github.com/julienschmidt/httprouter v1.2.0
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
||||
@@ -66,7 +66,7 @@ require (
|
||||
github.com/prometheus/common v0.6.0
|
||||
github.com/prometheus/procfs v0.0.4 // indirect
|
||||
github.com/russellhaering/gosaml2 v0.0.0-20170515204909-8908227c114a
|
||||
github.com/russellhaering/goxmldsig v0.0.0-20170515183101-605161228693
|
||||
github.com/russellhaering/goxmldsig v1.1.0
|
||||
github.com/satori/go.uuid v1.1.1-0.20170321230731-5bf94b69c6b6 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 // indirect
|
||||
|
||||
@@ -42,8 +42,8 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI
|
||||
github.com/aws/aws-sdk-go v1.17.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.32.7 h1:H4VgdCSF1cHw0VD8zGc98T1bGdACoLkh/vK2L6wgOUU=
|
||||
github.com/aws/aws-sdk-go v1.32.7/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/beevik/etree v0.0.0-20170418002358-cda1c0026246 h1:ug+AeM+Rh5O1beNwuhXlR29jr11nUuB7ZB+X9SzPSJQ=
|
||||
github.com/beevik/etree v0.0.0-20170418002358-cda1c0026246/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
||||
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -201,8 +201,10 @@ github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeY
|
||||
github.com/johannesboyne/gofakes3 v0.0.0-20191228161223-9aee1c78a252 h1:ZABLXRnnFNP5nkVzVBx2kQ/4GvSLUqcD2YUc+9Uc2Mo=
|
||||
github.com/johannesboyne/gofakes3 v0.0.0-20191228161223-9aee1c78a252/go.mod h1:cPDudDcSR9fls3ZmrXgt0GU2QpQGQRJc4JBNtKyNr1s=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1 h1:qBCV/RLV02TSfQa7tFmxTihnG+u+7JXByOkhlkR5rmQ=
|
||||
github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jonboulle/clockwork v0.2.0 h1:J2SLSdy7HgElq8ekSl2Mxh6vrRNFxqbXGenYH2I02Vs=
|
||||
github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/jonboulle/clockwork v0.2.1 h1:S/EaQvW6FpWMYAvYvY+OBDvpaM+izu0oiwo5y0MH7U0=
|
||||
github.com/jonboulle/clockwork v0.2.1/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
@@ -299,8 +301,8 @@ github.com/prometheus/procfs v0.0.4/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/russellhaering/gosaml2 v0.0.0-20170515204909-8908227c114a h1:t10m/WbIQiAAggqE6J2401FInpp50XPi249G7nE45tc=
|
||||
github.com/russellhaering/gosaml2 v0.0.0-20170515204909-8908227c114a/go.mod h1:niieRtQaw+opTVp9jzZo1nAAoksI2eNpd+weDcjZ+Mk=
|
||||
github.com/russellhaering/goxmldsig v0.0.0-20170515183101-605161228693 h1:N6BLFjXGfV1dGbLqHVVqe7u6ii+JHrl7L2lRZK7JzrY=
|
||||
github.com/russellhaering/goxmldsig v0.0.0-20170515183101-605161228693/go.mod h1:Oz4y6ImuOQZxynhbSXk7btjEfNBtGlj2dcaOvXl2FSM=
|
||||
github.com/russellhaering/goxmldsig v1.1.0 h1:lK/zeJie2sqG52ZAlPNn1oBBqsIsEKypUUBGpYYF6lk=
|
||||
github.com/russellhaering/goxmldsig v1.1.0/go.mod h1:QK8GhXPB3+AfuCrfo0oRISa9NfzeCpWmxeGnqEpDF9o=
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
||||
github.com/satori/go.uuid v1.1.1-0.20170321230731-5bf94b69c6b6 h1:oZag5hylqWwZrDdj/laMwWQnXaeWBQf66qm4PGQI6Wc=
|
||||
|
||||
+10
-8
@@ -561,15 +561,17 @@ func (o *SAMLConnectorV2) GetServiceProvider(clock clockwork.Clock) (*saml2.SAML
|
||||
}
|
||||
|
||||
for _, kd := range metadata.IDPSSODescriptor.KeyDescriptors {
|
||||
certData, err := base64.StdEncoding.DecodeString(strings.TrimSpace(kd.KeyInfo.X509Data.X509Certificate.Data))
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
for _, samlCert := range kd.KeyInfo.X509Data.X509Certificates {
|
||||
certData, err := base64.StdEncoding.DecodeString(strings.TrimSpace(samlCert.Data))
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
cert, err := x509.ParseCertificate(certData)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "failed to parse certificate in metadata")
|
||||
}
|
||||
certStore.Roots = append(certStore.Roots, cert)
|
||||
}
|
||||
cert, err := x509.ParseCertificate(certData)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "failed to parse certificate in metadata")
|
||||
}
|
||||
certStore.Roots = append(certStore.Roots, cert)
|
||||
}
|
||||
o.Spec.Issuer = metadata.EntityID
|
||||
o.Spec.SSO = metadata.IDPSSODescriptor.SingleSignOnService.Location
|
||||
|
||||
+1
-3
@@ -2,9 +2,7 @@ language: go
|
||||
sudo: false
|
||||
|
||||
go:
|
||||
- 1.4.2
|
||||
- 1.5.1
|
||||
- 1.6
|
||||
- 1.11.x
|
||||
- tip
|
||||
|
||||
matrix:
|
||||
|
||||
+2
@@ -6,3 +6,5 @@ Matt Smith (ma314smith)
|
||||
Michal Jemala (michaljemala)
|
||||
Nicolas Piganeau (npiganeau)
|
||||
Chris Brown (ccbrown)
|
||||
Earncef Sequeira (earncef)
|
||||
Gabriel de Labachelerie (wuzuf)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
Copyright 2015 Brett Vickers. All rights reserved.
|
||||
Copyright 2015-2019 Brett Vickers. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
||||
+3
-1
@@ -7,7 +7,9 @@ etree
|
||||
The etree package is a lightweight, pure go package that expresses XML in
|
||||
the form of an element tree. Its design was inspired by the Python
|
||||
[ElementTree](http://docs.python.org/2/library/xml.etree.elementtree.html)
|
||||
module. Some of the package's features include:
|
||||
module.
|
||||
|
||||
Some of the package's capabilities and features:
|
||||
|
||||
* Represents XML documents as trees of elements for easy traversal.
|
||||
* Imports, serializes, modifies or creates XML documents from scratch.
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
Release v1.1.0
|
||||
==============
|
||||
|
||||
**New Features**
|
||||
|
||||
* New attribute helpers.
|
||||
* Added the `Element.SortAttrs` method, which lexicographically sorts an
|
||||
element's attributes by key.
|
||||
* New `ReadSettings` properties.
|
||||
* Added `Entity` for the support of custom entity maps.
|
||||
* New `WriteSettings` properties.
|
||||
* Added `UseCRLF` to allow the output of CR-LF newlines instead of the
|
||||
default LF newlines. This is useful on Windows systems.
|
||||
* Additional support for text and CDATA sections.
|
||||
* The `Element.Text` method now returns the concatenation of all consecutive
|
||||
character data tokens immediately following an element's opening tag.
|
||||
* Added `Element.SetCData` to replace the character data immediately
|
||||
following an element's opening tag with a CDATA section.
|
||||
* Added `Element.CreateCData` to create and add a CDATA section child
|
||||
`CharData` token to an element.
|
||||
* Added `Element.CreateText` to create and add a child text `CharData` token
|
||||
to an element.
|
||||
* Added `NewCData` to create a parentless CDATA section `CharData` token.
|
||||
* Added `NewText` to create a parentless text `CharData`
|
||||
token.
|
||||
* Added `CharData.IsCData` to detect if the token contains a CDATA section.
|
||||
* Added `CharData.IsWhitespace` to detect if the token contains whitespace
|
||||
inserted by one of the document Indent functions.
|
||||
* Modified `Element.SetText` so that it replaces a run of consecutive
|
||||
character data tokens following the element's opening tag (instead of just
|
||||
the first one).
|
||||
* New "tail text" support.
|
||||
* Added the `Element.Tail` method, which returns the text immediately
|
||||
following an element's closing tag.
|
||||
* Added the `Element.SetTail` method, which modifies the text immediately
|
||||
following an element's closing tag.
|
||||
* New element child insertion and removal methods.
|
||||
* Added the `Element.InsertChildAt` method, which inserts a new child token
|
||||
before the specified child token index.
|
||||
* Added the `Element.RemoveChildAt` method, which removes the child token at
|
||||
the specified child token index.
|
||||
* New element and attribute queries.
|
||||
* Added the `Element.Index` method, which returns the element's index within
|
||||
its parent element's child token list.
|
||||
* Added the `Element.NamespaceURI` method to return the namespace URI
|
||||
associated with an element.
|
||||
* Added the `Attr.NamespaceURI` method to return the namespace URI
|
||||
associated with an element.
|
||||
* Added the `Attr.Element` method to return the element that an attribute
|
||||
belongs to.
|
||||
* New Path filter functions.
|
||||
* Added `[local-name()='val']` to keep elements whose unprefixed tag matches
|
||||
the desired value.
|
||||
* Added `[name()='val']` to keep elements whose full tag matches the desired
|
||||
value.
|
||||
* Added `[namespace-prefix()='val']` to keep elements whose namespace prefix
|
||||
matches the desired value.
|
||||
* Added `[namespace-uri()='val']` to keep elements whose namespace URI
|
||||
matches the desired value.
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
* A default XML `CharSetReader` is now used to prevent failed parsing of XML
|
||||
documents using certain encodings.
|
||||
([Issue](https://github.com/beevik/etree/issues/53)).
|
||||
* All characters are now properly escaped according to XML parsing rules.
|
||||
([Issue](https://github.com/beevik/etree/issues/55)).
|
||||
* The `Document.Indent` and `Document.IndentTabs` functions no longer insert
|
||||
empty string `CharData` tokens.
|
||||
|
||||
**Deprecated**
|
||||
|
||||
* `Element`
|
||||
* The `InsertChild` method is deprecated. Use `InsertChildAt` instead.
|
||||
* The `CreateCharData` method is deprecated. Use `CreateText` instead.
|
||||
* `CharData`
|
||||
* The `NewCharData` method is deprecated. Use `NewText` instead.
|
||||
|
||||
|
||||
Release v1.0.1
|
||||
==============
|
||||
|
||||
**Changes**
|
||||
|
||||
* Added support for absolute etree Path queries. An absolute path begins with
|
||||
`/` or `//` and begins its search from the element's document root.
|
||||
* Added [`GetPath`](https://godoc.org/github.com/beevik/etree#Element.GetPath)
|
||||
and [`GetRelativePath`](https://godoc.org/github.com/beevik/etree#Element.GetRelativePath)
|
||||
functions to the [`Element`](https://godoc.org/github.com/beevik/etree#Element)
|
||||
type.
|
||||
|
||||
**Breaking changes**
|
||||
|
||||
* A path starting with `//` is now interpreted as an absolute path.
|
||||
Previously, it was interpreted as a relative path starting from the element
|
||||
whose
|
||||
[`FindElement`](https://godoc.org/github.com/beevik/etree#Element.FindElement)
|
||||
method was called. To remain compatible with this release, all paths
|
||||
prefixed with `//` should be prefixed with `.//` when called from any
|
||||
element other than the document's root.
|
||||
* [**edit 2/1/2019**]: Minor releases should not contain breaking changes.
|
||||
Even though this breaking change was very minor, it was a mistake to include
|
||||
it in this minor release. In the future, all breaking changes will be
|
||||
limited to major releases (e.g., version 2.0.0).
|
||||
|
||||
Release v1.0.0
|
||||
==============
|
||||
|
||||
Initial release.
|
||||
+656
-146
File diff suppressed because it is too large
Load Diff
+99
-11
@@ -1,12 +1,14 @@
|
||||
// Copyright 2015 Brett Vickers.
|
||||
// Copyright 2015-2019 Brett Vickers.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package etree
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// A simple stack
|
||||
@@ -147,22 +149,35 @@ func spaceDecompose(str string) (space, key string) {
|
||||
return str[:colon], str[colon+1:]
|
||||
}
|
||||
|
||||
// Strings used by crIndent
|
||||
// Strings used by indentCRLF and indentLF
|
||||
const (
|
||||
crsp = "\n "
|
||||
crtab = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
|
||||
indentSpaces = "\r\n "
|
||||
indentTabs = "\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
|
||||
)
|
||||
|
||||
// crIndent returns a carriage return followed by n copies of the
|
||||
// first non-CR character in the source string.
|
||||
func crIndent(n int, source string) string {
|
||||
// indentCRLF returns a CRLF newline followed by n copies of the first
|
||||
// non-CRLF character in the source string.
|
||||
func indentCRLF(n int, source string) string {
|
||||
switch {
|
||||
case n < 0:
|
||||
return source[:1]
|
||||
case n < len(source):
|
||||
return source[:n+1]
|
||||
return source[:2]
|
||||
case n < len(source)-1:
|
||||
return source[:n+2]
|
||||
default:
|
||||
return source + strings.Repeat(source[1:2], n-len(source)+1)
|
||||
return source + strings.Repeat(source[2:3], n-len(source)+2)
|
||||
}
|
||||
}
|
||||
|
||||
// indentLF returns a LF newline followed by n copies of the first non-LF
|
||||
// character in the source string.
|
||||
func indentLF(n int, source string) string {
|
||||
switch {
|
||||
case n < 0:
|
||||
return source[1:2]
|
||||
case n < len(source)-1:
|
||||
return source[1 : n+2]
|
||||
default:
|
||||
return source[1:] + strings.Repeat(source[2:3], n-len(source)+2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,3 +201,76 @@ func isInteger(s string) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type escapeMode byte
|
||||
|
||||
const (
|
||||
escapeNormal escapeMode = iota
|
||||
escapeCanonicalText
|
||||
escapeCanonicalAttr
|
||||
)
|
||||
|
||||
// escapeString writes an escaped version of a string to the writer.
|
||||
func escapeString(w *bufio.Writer, s string, m escapeMode) {
|
||||
var esc []byte
|
||||
last := 0
|
||||
for i := 0; i < len(s); {
|
||||
r, width := utf8.DecodeRuneInString(s[i:])
|
||||
i += width
|
||||
switch r {
|
||||
case '&':
|
||||
esc = []byte("&")
|
||||
case '<':
|
||||
esc = []byte("<")
|
||||
case '>':
|
||||
if m == escapeCanonicalAttr {
|
||||
continue
|
||||
}
|
||||
esc = []byte(">")
|
||||
case '\'':
|
||||
if m != escapeNormal {
|
||||
continue
|
||||
}
|
||||
esc = []byte("'")
|
||||
case '"':
|
||||
if m == escapeCanonicalText {
|
||||
continue
|
||||
}
|
||||
esc = []byte(""")
|
||||
case '\t':
|
||||
if m != escapeCanonicalAttr {
|
||||
continue
|
||||
}
|
||||
esc = []byte("	")
|
||||
case '\n':
|
||||
if m != escapeCanonicalAttr {
|
||||
continue
|
||||
}
|
||||
esc = []byte("
")
|
||||
case '\r':
|
||||
if m == escapeNormal {
|
||||
continue
|
||||
}
|
||||
esc = []byte("
")
|
||||
default:
|
||||
if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) {
|
||||
esc = []byte("\uFFFD")
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
w.WriteString(s[last : i-width])
|
||||
w.Write(esc)
|
||||
last = i
|
||||
}
|
||||
w.WriteString(s[last:])
|
||||
}
|
||||
|
||||
func isInCharacterRange(r rune) bool {
|
||||
return r == 0x09 ||
|
||||
r == 0x0A ||
|
||||
r == 0x0D ||
|
||||
r >= 0x20 && r <= 0xD7FF ||
|
||||
r >= 0xE000 && r <= 0xFFFD ||
|
||||
r >= 0x10000 && r <= 0x10FFFF
|
||||
}
|
||||
|
||||
+153
-41
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015 Brett Vickers.
|
||||
// Copyright 2015-2019 Brett Vickers.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
@@ -10,40 +10,75 @@ import (
|
||||
)
|
||||
|
||||
/*
|
||||
A Path is an object that represents an optimized version of an
|
||||
XPath-like search string. Although path strings are XPath-like,
|
||||
only the following limited syntax is supported:
|
||||
A Path is a string that represents a search path through an etree starting
|
||||
from the document root or an arbitrary element. Paths are used with the
|
||||
Element object's Find* methods to locate and return desired elements.
|
||||
|
||||
. Selects the current element
|
||||
.. Selects the parent of the current element
|
||||
* Selects all child elements
|
||||
// Selects all descendants of the current element
|
||||
tag Selects all child elements with the given tag
|
||||
[#] Selects the element of the given index (1-based,
|
||||
negative starts from the end)
|
||||
[@attrib] Selects all elements with the given attribute
|
||||
[@attrib='val'] Selects all elements with the given attribute set to val
|
||||
[tag] Selects all elements with a child element named tag
|
||||
[tag='val'] Selects all elements with a child element named tag
|
||||
and text equal to val
|
||||
A Path consists of a series of slash-separated "selectors", each of which may
|
||||
be modified by one or more bracket-enclosed "filters". Selectors are used to
|
||||
traverse the etree from element to element, while filters are used to narrow
|
||||
the list of candidate elements at each node.
|
||||
|
||||
Examples:
|
||||
Although etree Path strings are similar to XPath strings
|
||||
(https://www.w3.org/TR/1999/REC-xpath-19991116/), they have a more limited set
|
||||
of selectors and filtering options.
|
||||
|
||||
Select the title elements of all descendant book elements having a
|
||||
'category' attribute of 'WEB':
|
||||
The following selectors are supported by etree Path strings:
|
||||
|
||||
. Select the current element.
|
||||
.. Select the parent of the current element.
|
||||
* Select all child elements of the current element.
|
||||
/ Select the root element when used at the start of a path.
|
||||
// Select all descendants of the current element.
|
||||
tag Select all child elements with a name matching the tag.
|
||||
|
||||
The following basic filters are supported by etree Path strings:
|
||||
|
||||
[@attrib] Keep elements with an attribute named attrib.
|
||||
[@attrib='val'] Keep elements with an attribute named attrib and value matching val.
|
||||
[tag] Keep elements with a child element named tag.
|
||||
[tag='val'] Keep elements with a child element named tag and text matching val.
|
||||
[n] Keep the n-th element, where n is a numeric index starting from 1.
|
||||
|
||||
The following function filters are also supported:
|
||||
|
||||
[text()] Keep elements with non-empty text.
|
||||
[text()='val'] Keep elements whose text matches val.
|
||||
[local-name()='val'] Keep elements whose un-prefixed tag matches val.
|
||||
[name()='val'] Keep elements whose full tag exactly matches val.
|
||||
[namespace-prefix()='val'] Keep elements whose namespace prefix matches val.
|
||||
[namespace-uri()='val'] Keep elements whose namespace URI matches val.
|
||||
|
||||
Here are some examples of Path strings:
|
||||
|
||||
- Select the bookstore child element of the root element:
|
||||
/bookstore
|
||||
|
||||
- Beginning from the root element, select the title elements of all
|
||||
descendant book elements having a 'category' attribute of 'WEB':
|
||||
//book[@category='WEB']/title
|
||||
|
||||
Select the first book element with a title child containing the text
|
||||
'Great Expectations':
|
||||
- Beginning from the current element, select the first descendant
|
||||
book element with a title child element containing the text 'Great
|
||||
Expectations':
|
||||
.//book[title='Great Expectations'][1]
|
||||
|
||||
Starting from the current element, select all children of book elements
|
||||
with an attribute 'language' set to 'english':
|
||||
- Beginning from the current element, select all child elements of
|
||||
book elements with an attribute 'language' set to 'english':
|
||||
./book/*[@language='english']
|
||||
|
||||
Select all descendant book elements whose title element has an attribute
|
||||
'language' set to 'french':
|
||||
//book/title[@language='french']/..
|
||||
- Beginning from the current element, select all child elements of
|
||||
book elements containing the text 'special':
|
||||
./book/*[text()='special']
|
||||
|
||||
- Beginning from the current element, select all descendant book
|
||||
elements whose title child element has a 'language' attribute of 'french':
|
||||
.//book/title[@language='french']/..
|
||||
|
||||
- Beginning from the current element, select all book elements
|
||||
belonging to the http://www.w3.org/TR/html4/ namespace:
|
||||
.//book[namespace-uri()='http://www.w3.org/TR/html4/']
|
||||
|
||||
*/
|
||||
type Path struct {
|
||||
segments []segment
|
||||
@@ -173,22 +208,20 @@ type compiler struct {
|
||||
// through an element tree and returns a slice of segment
|
||||
// descriptors.
|
||||
func (c *compiler) parsePath(path string) []segment {
|
||||
// If path starts or ends with //, fix it
|
||||
if strings.HasPrefix(path, "//") {
|
||||
path = "." + path
|
||||
}
|
||||
// If path ends with //, fix it
|
||||
if strings.HasSuffix(path, "//") {
|
||||
path = path + "*"
|
||||
}
|
||||
|
||||
// Paths cannot be absolute
|
||||
var segments []segment
|
||||
|
||||
// Check for an absolute path
|
||||
if strings.HasPrefix(path, "/") {
|
||||
c.err = ErrPath("paths cannot be absolute.")
|
||||
return nil
|
||||
segments = append(segments, segment{new(selectRoot), []filter{}})
|
||||
path = path[1:]
|
||||
}
|
||||
|
||||
// Split path into segment objects
|
||||
var segments []segment
|
||||
// Split path into segments
|
||||
for _, s := range splitPath(path) {
|
||||
segments = append(segments, c.parseSegment(s))
|
||||
if c.err != ErrPath("") {
|
||||
@@ -218,7 +251,7 @@ func (c *compiler) parseSegment(path string) segment {
|
||||
pieces := strings.Split(path, "[")
|
||||
seg := segment{
|
||||
sel: c.parseSelector(pieces[0]),
|
||||
filters: make([]filter, 0),
|
||||
filters: []filter{},
|
||||
}
|
||||
for i := 1; i < len(pieces); i++ {
|
||||
fpath := pieces[i]
|
||||
@@ -247,6 +280,17 @@ func (c *compiler) parseSelector(path string) selector {
|
||||
}
|
||||
}
|
||||
|
||||
var fnTable = map[string]struct {
|
||||
hasFn func(e *Element) bool
|
||||
getValFn func(e *Element) string
|
||||
}{
|
||||
"local-name": {nil, (*Element).name},
|
||||
"name": {nil, (*Element).FullTag},
|
||||
"namespace-prefix": {nil, (*Element).namespacePrefix},
|
||||
"namespace-uri": {nil, (*Element).NamespaceURI},
|
||||
"text": {(*Element).hasText, (*Element).Text},
|
||||
}
|
||||
|
||||
// parseFilter parses a path filter contained within [brackets].
|
||||
func (c *compiler) parseFilter(path string) filter {
|
||||
if len(path) == 0 {
|
||||
@@ -254,7 +298,7 @@ func (c *compiler) parseFilter(path string) filter {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Filter contains [@attr='val'] or [tag='val']?
|
||||
// Filter contains [@attr='val'], [fn()='val'], or [tag='val']?
|
||||
eqindex := strings.Index(path, "='")
|
||||
if eqindex >= 0 {
|
||||
rindex := nextIndex(path, "'", eqindex+2)
|
||||
@@ -262,18 +306,36 @@ func (c *compiler) parseFilter(path string) filter {
|
||||
c.err = ErrPath("path has mismatched filter quotes.")
|
||||
return nil
|
||||
}
|
||||
|
||||
key := path[:eqindex]
|
||||
value := path[eqindex+2 : rindex]
|
||||
|
||||
switch {
|
||||
case path[0] == '@':
|
||||
return newFilterAttrVal(path[1:eqindex], path[eqindex+2:rindex])
|
||||
case key[0] == '@':
|
||||
return newFilterAttrVal(key[1:], value)
|
||||
case strings.HasSuffix(key, "()"):
|
||||
fn := key[:len(key)-2]
|
||||
if t, ok := fnTable[fn]; ok && t.getValFn != nil {
|
||||
return newFilterFuncVal(t.getValFn, value)
|
||||
}
|
||||
c.err = ErrPath("path has unknown function " + fn)
|
||||
return nil
|
||||
default:
|
||||
return newFilterChildText(path[:eqindex], path[eqindex+2:rindex])
|
||||
return newFilterChildText(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Filter contains [@attr], [N] or [tag]
|
||||
// Filter contains [@attr], [N], [tag] or [fn()]
|
||||
switch {
|
||||
case path[0] == '@':
|
||||
return newFilterAttr(path[1:])
|
||||
case strings.HasSuffix(path, "()"):
|
||||
fn := path[:len(path)-2]
|
||||
if t, ok := fnTable[fn]; ok && t.hasFn != nil {
|
||||
return newFilterFunc(t.hasFn)
|
||||
}
|
||||
c.err = ErrPath("path has unknown function " + fn)
|
||||
return nil
|
||||
case isInteger(path):
|
||||
pos, _ := strconv.Atoi(path)
|
||||
switch {
|
||||
@@ -294,6 +356,17 @@ func (s *selectSelf) apply(e *Element, p *pather) {
|
||||
p.candidates = append(p.candidates, e)
|
||||
}
|
||||
|
||||
// selectRoot selects the element's root node.
|
||||
type selectRoot struct{}
|
||||
|
||||
func (s *selectRoot) apply(e *Element, p *pather) {
|
||||
root := e
|
||||
for root.parent != nil {
|
||||
root = root.parent
|
||||
}
|
||||
p.candidates = append(p.candidates, root)
|
||||
}
|
||||
|
||||
// selectParent selects the element's parent into the candidate list.
|
||||
type selectParent struct{}
|
||||
|
||||
@@ -420,6 +493,45 @@ func (f *filterAttrVal) apply(p *pather) {
|
||||
p.candidates, p.scratch = p.scratch, p.candidates[0:0]
|
||||
}
|
||||
|
||||
// filterFunc filters the candidate list for elements satisfying a custom
|
||||
// boolean function.
|
||||
type filterFunc struct {
|
||||
fn func(e *Element) bool
|
||||
}
|
||||
|
||||
func newFilterFunc(fn func(e *Element) bool) *filterFunc {
|
||||
return &filterFunc{fn}
|
||||
}
|
||||
|
||||
func (f *filterFunc) apply(p *pather) {
|
||||
for _, c := range p.candidates {
|
||||
if f.fn(c) {
|
||||
p.scratch = append(p.scratch, c)
|
||||
}
|
||||
}
|
||||
p.candidates, p.scratch = p.scratch, p.candidates[0:0]
|
||||
}
|
||||
|
||||
// filterFuncVal filters the candidate list for elements containing a value
|
||||
// matching the result of a custom function.
|
||||
type filterFuncVal struct {
|
||||
fn func(e *Element) string
|
||||
val string
|
||||
}
|
||||
|
||||
func newFilterFuncVal(fn func(e *Element) string, value string) *filterFuncVal {
|
||||
return &filterFuncVal{fn, value}
|
||||
}
|
||||
|
||||
func (f *filterFuncVal) apply(p *pather) {
|
||||
for _, c := range p.candidates {
|
||||
if f.fn(c) == f.val {
|
||||
p.scratch = append(p.scratch, c)
|
||||
}
|
||||
}
|
||||
p.candidates, p.scratch = p.scratch, p.candidates[0:0]
|
||||
}
|
||||
|
||||
// filterChild filters the candidate list for elements having
|
||||
// a child element with the specified tag.
|
||||
type filterChild struct {
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
@@ -1,3 +1,5 @@
|
||||
/.idea/
|
||||
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- "1.10"
|
||||
- master
|
||||
|
||||
sudo: false
|
||||
+17
-7
@@ -1,12 +1,16 @@
|
||||
clockwork
|
||||
=========
|
||||
# clockwork
|
||||
|
||||
[](https://travis-ci.org/jonboulle/clockwork)
|
||||
[](http://godoc.org/github.com/jonboulle/clockwork)
|
||||
[](https://github.com/avelino/awesome-go#utilities)
|
||||
|
||||
a simple fake clock for golang
|
||||
[](https://github.com/jonboulle/clockwork/actions?query=workflow%3ACI)
|
||||
[](https://goreportcard.com/report/github.com/jonboulle/clockwork)
|
||||

|
||||
[](https://pkg.go.dev/mod/github.com/jonboulle/clockwork)
|
||||
|
||||
# Usage
|
||||
**A simple fake clock for Go.**
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Replace uses of the `time` package with the `clockwork.Clock` interface instead.
|
||||
|
||||
@@ -19,7 +23,7 @@ func myFunc() {
|
||||
}
|
||||
```
|
||||
|
||||
inject a clock and use its `Sleep` method instead:
|
||||
Inject a clock and use its `Sleep` method instead:
|
||||
|
||||
```go
|
||||
func myFunc(clock clockwork.Clock) {
|
||||
@@ -65,6 +69,12 @@ myFunc(clockwork.NewRealClock())
|
||||
|
||||
See [example_test.go](example_test.go) for a full example.
|
||||
|
||||
|
||||
# Credits
|
||||
|
||||
clockwork is inspired by @wickman's [threaded fake clock](https://gist.github.com/wickman/3840816), and the [Golang playground](https://blog.golang.org/playground#TOC_3.1.)
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Apache License, Version 2.0. Please see [License File](LICENSE) for more information.
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ func (fc *fakeClock) After(d time.Duration) <-chan time.Time {
|
||||
defer fc.l.Unlock()
|
||||
now := fc.time
|
||||
done := make(chan time.Time, 1)
|
||||
if d.Nanoseconds() == 0 {
|
||||
if d.Nanoseconds() <= 0 {
|
||||
// special case - trigger immediately
|
||||
done <- now
|
||||
} else {
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
module github.com/jonboulle/clockwork
|
||||
|
||||
go 1.13
|
||||
@@ -0,0 +1 @@
|
||||
*.test
|
||||
+4
-3
@@ -1,6 +1,7 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
- "1.13.x"
|
||||
- "1.14.x"
|
||||
- "1.15.x"
|
||||
- master
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ XML Digital Signatures implemented in pure Go.
|
||||
|
||||
## Installation
|
||||
|
||||
Install `goxmldsig` into your `$GOPATH` using `go get`:
|
||||
Install `goxmldsig` using `go get`:
|
||||
|
||||
```
|
||||
$ go get github.com/russellhaering/goxmldsig
|
||||
|
||||
+34
@@ -56,6 +56,40 @@ func (c *c14N11Canonicalizer) Algorithm() AlgorithmID {
|
||||
return CanonicalXML11AlgorithmId
|
||||
}
|
||||
|
||||
type c14N10RecCanonicalizer struct{}
|
||||
|
||||
// MakeC14N10RecCanonicalizer constructs an inclusive canonicalizer.
|
||||
func MakeC14N10RecCanonicalizer() Canonicalizer {
|
||||
return &c14N10RecCanonicalizer{}
|
||||
}
|
||||
|
||||
// Canonicalize transforms the input Element into a serialized XML document in canonical form.
|
||||
func (c *c14N10RecCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
|
||||
scope := make(map[string]struct{})
|
||||
return canonicalSerialize(canonicalPrep(el, scope))
|
||||
}
|
||||
|
||||
func (c *c14N10RecCanonicalizer) Algorithm() AlgorithmID {
|
||||
return CanonicalXML10RecAlgorithmId
|
||||
}
|
||||
|
||||
type c14N10CommentCanonicalizer struct{}
|
||||
|
||||
// MakeC14N10CommentCanonicalizer constructs an inclusive canonicalizer.
|
||||
func MakeC14N10CommentCanonicalizer() Canonicalizer {
|
||||
return &c14N10CommentCanonicalizer{}
|
||||
}
|
||||
|
||||
// Canonicalize transforms the input Element into a serialized XML document in canonical form.
|
||||
func (c *c14N10CommentCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
|
||||
scope := make(map[string]struct{})
|
||||
return canonicalSerialize(canonicalPrep(el, scope))
|
||||
}
|
||||
|
||||
func (c *c14N10CommentCanonicalizer) Algorithm() AlgorithmID {
|
||||
return CanonicalXML10CommentAlgorithmId
|
||||
}
|
||||
|
||||
func composeAttr(space, key string) string {
|
||||
if space != "" {
|
||||
return space + ":" + key
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ func TransformExcC14n(el *etree.Element, inclusiveNamespacesPrefixList string) e
|
||||
prefixSet[prefix] = struct{}{}
|
||||
}
|
||||
|
||||
err := transformExcC14n(DefaultNSContext, EmptyNSContext, el, prefixSet)
|
||||
err := transformExcC14n(DefaultNSContext, DefaultNSContext, el, prefixSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+80
-1
@@ -266,7 +266,12 @@ func NSFindIterate(el *etree.Element, namespace, tag string, handle NSIterHandle
|
||||
// returned by NSFindIterate.
|
||||
func NSFindIterateCtx(ctx NSContext, el *etree.Element, namespace, tag string, handle NSIterHandler) error {
|
||||
err := NSTraverse(ctx, el, func(ctx NSContext, el *etree.Element) error {
|
||||
currentNS, err := ctx.LookupPrefix(el.Space)
|
||||
_ctx, err := ctx.SubContext(el)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
currentNS, err := _ctx.LookupPrefix(el.Space)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -309,6 +314,80 @@ func NSFindOneCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*etr
|
||||
return found, nil
|
||||
}
|
||||
|
||||
// NSIterateChildren iterates the children of an element, invoking the passed
|
||||
// handler with each direct child of the element, and the context surrounding
|
||||
// that child.
|
||||
func NSIterateChildren(ctx NSContext, el *etree.Element, handle NSIterHandler) error {
|
||||
ctx, err := ctx.SubContext(el)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Iterate the child elements.
|
||||
for _, child := range el.ChildElements() {
|
||||
err = handle(ctx, child)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NSFindIterateChildrenCtx takes an element and its surrounding context, and iterates
|
||||
// the children of that element searching for an element matching the passed namespace
|
||||
// and tag. For each such element that is found, handle is invoked with the matched
|
||||
// element and its own surrounding context.
|
||||
func NSFindChildrenIterateCtx(ctx NSContext, el *etree.Element, namespace, tag string, handle NSIterHandler) error {
|
||||
err := NSIterateChildren(ctx, el, func(ctx NSContext, el *etree.Element) error {
|
||||
_ctx, err := ctx.SubContext(el)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
currentNS, err := _ctx.LookupPrefix(el.Space)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Base case, el is the sought after element.
|
||||
if currentNS == namespace && el.Tag == tag {
|
||||
return handle(ctx, el)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil && err != ErrTraversalHalted {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NSFindOneChild behaves identically to NSFindOneChildCtx, but uses
|
||||
// DefaultNSContext for context.
|
||||
func NSFindOneChild(el *etree.Element, namespace, tag string) (*etree.Element, error) {
|
||||
return NSFindOneChildCtx(DefaultNSContext, el, namespace, tag)
|
||||
}
|
||||
|
||||
// NSFindOneCtx conducts a depth-first search for the specified element. If such an
|
||||
// element is found a reference to it is returned.
|
||||
func NSFindOneChildCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*etree.Element, error) {
|
||||
var found *etree.Element
|
||||
|
||||
err := NSFindChildrenIterateCtx(ctx, el, namespace, tag, func(ctx NSContext, el *etree.Element) error {
|
||||
found = el
|
||||
return ErrTraversalHalted
|
||||
})
|
||||
|
||||
if err != nil && err != ErrTraversalHalted {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return found, nil
|
||||
}
|
||||
|
||||
// NSBuildParentContext recurses upward from an element in order to build an NSContext
|
||||
// for its immediate parent. If the element has no parent DefaultNSContext
|
||||
// is returned.
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
module github.com/russellhaering/goxmldsig
|
||||
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/beevik/etree v1.1.0
|
||||
github.com/jonboulle/clockwork v0.2.0
|
||||
github.com/stretchr/testify v1.6.1
|
||||
)
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
||||
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/jonboulle/clockwork v0.2.0 h1:J2SLSdy7HgElq8ekSl2Mxh6vrRNFxqbXGenYH2I02Vs=
|
||||
github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
+4
@@ -12,6 +12,10 @@ type X509KeyStore interface {
|
||||
GetKeyPair() (privateKey *rsa.PrivateKey, cert []byte, err error)
|
||||
}
|
||||
|
||||
type X509ChainStore interface {
|
||||
GetChain() (certs [][]byte, err error)
|
||||
}
|
||||
|
||||
type X509CertificateStore interface {
|
||||
Certificates() (roots []*x509.Certificate, err error)
|
||||
}
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
cd `dirname $0`
|
||||
DIRS=`git grep -l 'func Test' | xargs dirname | sort -u`
|
||||
for DIR in $DIRS
|
||||
do
|
||||
echo
|
||||
echo "dir: $DIR"
|
||||
echo "======================================"
|
||||
pushd $DIR >/dev/null
|
||||
go test -v || exit 1
|
||||
popd >/dev/null
|
||||
done
|
||||
+51
-6
@@ -59,13 +59,13 @@ func (ctx *SigningContext) digest(el *etree.Element) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (ctx *SigningContext) constructSignedInfo(el *etree.Element, enveloped bool) (*etree.Element, error) {
|
||||
digestAlgorithmIdentifier, ok := digestAlgorithmIdentifiers[ctx.Hash]
|
||||
if !ok {
|
||||
digestAlgorithmIdentifier := ctx.GetDigestAlgorithmIdentifier()
|
||||
if digestAlgorithmIdentifier == "" {
|
||||
return nil, errors.New("unsupported hash mechanism")
|
||||
}
|
||||
|
||||
signatureMethodIdentifier, ok := signatureMethodIdentifiers[ctx.Hash]
|
||||
if !ok {
|
||||
signatureMethodIdentifier := ctx.GetSignatureMethodIdentifier()
|
||||
if signatureMethodIdentifier == "" {
|
||||
return nil, errors.New("unsupported signature method")
|
||||
}
|
||||
|
||||
@@ -176,6 +176,14 @@ func (ctx *SigningContext) ConstructSignature(el *etree.Element, enveloped bool)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certs := [][]byte{cert}
|
||||
if cs, ok := ctx.KeyStore.(X509ChainStore); ok {
|
||||
certs, err = cs.GetChain()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
rawSignature, err := rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -186,8 +194,10 @@ func (ctx *SigningContext) ConstructSignature(el *etree.Element, enveloped bool)
|
||||
|
||||
keyInfo := ctx.createNamespacedElement(sig, KeyInfoTag)
|
||||
x509Data := ctx.createNamespacedElement(keyInfo, X509DataTag)
|
||||
x509Certificate := ctx.createNamespacedElement(x509Data, X509CertificateTag)
|
||||
x509Certificate.SetText(base64.StdEncoding.EncodeToString(cert))
|
||||
for _, cert := range certs {
|
||||
x509Certificate := ctx.createNamespacedElement(x509Data, X509CertificateTag)
|
||||
x509Certificate.SetText(base64.StdEncoding.EncodeToString(cert))
|
||||
}
|
||||
|
||||
return sig, nil
|
||||
}
|
||||
@@ -209,3 +219,38 @@ func (ctx *SigningContext) SignEnveloped(el *etree.Element) (*etree.Element, err
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (ctx *SigningContext) GetSignatureMethodIdentifier() string {
|
||||
if ident, ok := signatureMethodIdentifiers[ctx.Hash]; ok {
|
||||
return ident
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ctx *SigningContext) GetDigestAlgorithmIdentifier() string {
|
||||
if ident, ok := digestAlgorithmIdentifiers[ctx.Hash]; ok {
|
||||
return ident
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Useful for signing query string (including DEFLATED AuthnRequest) when
|
||||
// using HTTP-Redirect to make a signed request.
|
||||
// See 3.4.4.1 DEFLATE Encoding of https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf
|
||||
func (ctx *SigningContext) SignString(content string) ([]byte, error) {
|
||||
hash := ctx.Hash.New()
|
||||
if ln, err := hash.Write([]byte(content)); err != nil {
|
||||
return nil, fmt.Errorf("error calculating hash: %v", err)
|
||||
} else if ln < 1 {
|
||||
return nil, fmt.Errorf("zero length hash")
|
||||
}
|
||||
digest := hash.Sum(nil)
|
||||
|
||||
var signature []byte
|
||||
if key, _, err := ctx.KeyStore.GetKeyPair(); err != nil {
|
||||
return nil, fmt.Errorf("unable to fetch key for signing: %v", err)
|
||||
} else if signature, err = rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest); err != nil {
|
||||
return nil, fmt.Errorf("error signing: %v", err)
|
||||
}
|
||||
return signature, nil
|
||||
}
|
||||
|
||||
+5
@@ -32,3 +32,8 @@ func (d TLSCertKeyStore) GetKeyPair() (*rsa.PrivateKey, []byte, error) {
|
||||
|
||||
return pk, crt, nil
|
||||
}
|
||||
|
||||
//GetChain impliments X509ChainStore using the underlying tls.Certificate
|
||||
func (d TLSCertKeyStore) GetChain() ([][]byte, error) {
|
||||
return d.Certificate, nil
|
||||
}
|
||||
|
||||
+2
-2
@@ -63,8 +63,8 @@ type KeyInfo struct {
|
||||
}
|
||||
|
||||
type X509Data struct {
|
||||
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"`
|
||||
X509Certificate X509Certificate `xml:"X509Certificate"`
|
||||
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"`
|
||||
X509Certificates []X509Certificate `xml:"X509Certificate"`
|
||||
}
|
||||
|
||||
type X509Certificate struct {
|
||||
|
||||
+105
-32
@@ -15,11 +15,13 @@ import (
|
||||
)
|
||||
|
||||
var uriRegexp = regexp.MustCompile("^#[a-zA-Z_][\\w.-]*$")
|
||||
var whiteSpace = regexp.MustCompile("\\s+")
|
||||
|
||||
var (
|
||||
// ErrMissingSignature indicates that no enveloped signature was found referencing
|
||||
// the top level element passed for signature verification.
|
||||
ErrMissingSignature = errors.New("Missing signature referencing the top-level element")
|
||||
ErrInvalidSignature = errors.New( "Invalid Signature")
|
||||
)
|
||||
|
||||
type ValidationContext struct {
|
||||
@@ -58,31 +60,51 @@ func childPath(space, tag string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// The RemoveElement method on etree.Element isn't recursive...
|
||||
func recursivelyRemoveElement(tree, el *etree.Element) bool {
|
||||
if tree.RemoveChild(el) != nil {
|
||||
return true
|
||||
func mapPathToElement(tree, el *etree.Element) []int {
|
||||
for i, child := range tree.Child {
|
||||
if child == el {
|
||||
return []int{i}
|
||||
}
|
||||
}
|
||||
|
||||
for _, child := range tree.Child {
|
||||
for i, child := range tree.Child {
|
||||
if childElement, ok := child.(*etree.Element); ok {
|
||||
if recursivelyRemoveElement(childElement, el) {
|
||||
return true
|
||||
childPath := mapPathToElement(childElement, el)
|
||||
if childElement != nil {
|
||||
return append([]int{i}, childPath...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
|
||||
// transform applies the passed set of transforms to the specified root element.
|
||||
func removeElementAtPath(el *etree.Element, path []int) bool {
|
||||
if len(path) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(el.Child) <= path[0] {
|
||||
return false
|
||||
}
|
||||
|
||||
childElement, ok := el.Child[path[0]].(*etree.Element)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(path) == 1 {
|
||||
el.RemoveChild(childElement)
|
||||
return true
|
||||
}
|
||||
|
||||
return removeElementAtPath(childElement, path[1:])
|
||||
}
|
||||
|
||||
// Transform returns a new element equivalent to the passed root el, but with
|
||||
// the set of transformations described by the ref applied.
|
||||
//
|
||||
// The functionality of transform is currently very limited and purpose-specific.
|
||||
//
|
||||
// NOTE(russell_h): Ideally this wouldn't mutate the root passed to it, and would
|
||||
// instead return a copy. Unfortunately copying the tree makes it difficult to
|
||||
// correctly locate the signature. I'm opting, for now, to simply mutate the root
|
||||
// parameter.
|
||||
func (ctx *ValidationContext) transform(
|
||||
el *etree.Element,
|
||||
sig *types.Signature,
|
||||
@@ -93,6 +115,14 @@ func (ctx *ValidationContext) transform(
|
||||
return nil, nil, errors.New("Expected Enveloped and C14N transforms")
|
||||
}
|
||||
|
||||
// map the path to the passed signature relative to the passed root, in
|
||||
// order to enable removal of the signature by an enveloped signature
|
||||
// transform
|
||||
signaturePath := mapPathToElement(el, sig.UnderlyingElement())
|
||||
|
||||
// make a copy of the passed root
|
||||
el = el.Copy()
|
||||
|
||||
var canonicalizer Canonicalizer
|
||||
|
||||
for _, transform := range transforms {
|
||||
@@ -100,7 +130,7 @@ func (ctx *ValidationContext) transform(
|
||||
|
||||
switch AlgorithmID(algo) {
|
||||
case EnvelopedSignatureAltorithmId:
|
||||
if !recursivelyRemoveElement(el, sig.UnderlyingElement()) {
|
||||
if !removeElementAtPath(el, signaturePath) {
|
||||
return nil, nil, errors.New("Error applying canonicalization transform: Signature not found")
|
||||
}
|
||||
|
||||
@@ -115,6 +145,12 @@ func (ctx *ValidationContext) transform(
|
||||
case CanonicalXML11AlgorithmId:
|
||||
canonicalizer = MakeC14N11Canonicalizer()
|
||||
|
||||
case CanonicalXML10RecAlgorithmId:
|
||||
canonicalizer = MakeC14N10RecCanonicalizer()
|
||||
|
||||
case CanonicalXML10CommentAlgorithmId:
|
||||
canonicalizer = MakeC14N10CommentCanonicalizer()
|
||||
|
||||
default:
|
||||
return nil, nil, errors.New("Unknown Transform Algorithm: " + algo)
|
||||
}
|
||||
@@ -150,7 +186,16 @@ func (ctx *ValidationContext) digest(el *etree.Element, digestAlgorithmId string
|
||||
func (ctx *ValidationContext) verifySignedInfo(sig *types.Signature, canonicalizer Canonicalizer, signatureMethodId string, cert *x509.Certificate, decodedSignature []byte) error {
|
||||
signatureElement := sig.UnderlyingElement()
|
||||
|
||||
signedInfo := signatureElement.FindElement(childPath(signatureElement.Space, SignedInfoTag))
|
||||
nsCtx, err := etreeutils.NSBuildParentContext(signatureElement)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
signedInfo, err := etreeutils.NSFindOneChildCtx(nsCtx, signatureElement, Namespace, SignedInfoTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if signedInfo == nil {
|
||||
return errors.New("Missing SignedInfo")
|
||||
}
|
||||
@@ -252,9 +297,28 @@ func contains(roots []*x509.Certificate, cert *x509.Certificate) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// In most places, we use etree Elements, but while deserializing the Signature, we use
|
||||
// encoding/xml unmarshal directly to convert to a convenient go struct. This presents a problem in some cases because
|
||||
// when an xml element repeats under the parent, the last element will win and/or be appended. We need to assert that
|
||||
// the Signature object matches the expected shape of a Signature object.
|
||||
func validateShape(signatureEl *etree.Element) error {
|
||||
children := signatureEl.ChildElements()
|
||||
|
||||
childCounts := map[string]int{}
|
||||
for _, child := range children {
|
||||
childCounts[child.Tag]++
|
||||
}
|
||||
|
||||
validateCount := childCounts[SignedInfoTag] == 1 && childCounts[KeyInfoTag] <= 1 && childCounts[SignatureValueTag] == 1
|
||||
if !validateCount {
|
||||
return ErrInvalidSignature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// findSignature searches for a Signature element referencing the passed root element.
|
||||
func (ctx *ValidationContext) findSignature(el *etree.Element) (*types.Signature, error) {
|
||||
idAttr := el.SelectAttr(ctx.IdAttribute)
|
||||
func (ctx *ValidationContext) findSignature(root *etree.Element) (*types.Signature, error) {
|
||||
idAttr := root.SelectAttr(ctx.IdAttribute)
|
||||
if idAttr == nil || idAttr.Value == "" {
|
||||
return nil, errors.New("Missing ID attribute")
|
||||
}
|
||||
@@ -262,22 +326,24 @@ func (ctx *ValidationContext) findSignature(el *etree.Element) (*types.Signature
|
||||
var sig *types.Signature
|
||||
|
||||
// Traverse the tree looking for a Signature element
|
||||
err := etreeutils.NSFindIterate(el, Namespace, SignatureTag, func(ctx etreeutils.NSContext, el *etree.Element) error {
|
||||
|
||||
err := etreeutils.NSFindIterate(root, Namespace, SignatureTag, func(ctx etreeutils.NSContext, signatureEl *etree.Element) error {
|
||||
err := validateShape(signatureEl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
found := false
|
||||
err := etreeutils.NSFindIterateCtx(ctx, el, Namespace, SignedInfoTag,
|
||||
err = etreeutils.NSFindChildrenIterateCtx(ctx, signatureEl, Namespace, SignedInfoTag,
|
||||
func(ctx etreeutils.NSContext, signedInfo *etree.Element) error {
|
||||
// Ignore any SignedInfo that isn't an immediate descendent of Signature.
|
||||
if signedInfo.Parent() != el {
|
||||
return nil
|
||||
}
|
||||
|
||||
detachedSignedInfo, err := etreeutils.NSDetatch(ctx, signedInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c14NMethod := detachedSignedInfo.FindElement(childPath(detachedSignedInfo.Space, CanonicalizationMethodTag))
|
||||
c14NMethod, err := etreeutils.NSFindOneChildCtx(ctx, detachedSignedInfo, Namespace, CanonicalizationMethodTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c14NMethod == nil {
|
||||
return errors.New("missing CanonicalizationMethod on Signature")
|
||||
}
|
||||
@@ -302,12 +368,18 @@ func (ctx *ValidationContext) findSignature(el *etree.Element) (*types.Signature
|
||||
case CanonicalXML11AlgorithmId:
|
||||
canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{})
|
||||
|
||||
case CanonicalXML10RecAlgorithmId:
|
||||
canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{})
|
||||
|
||||
case CanonicalXML10CommentAlgorithmId:
|
||||
canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{})
|
||||
|
||||
default:
|
||||
return fmt.Errorf("invalid CanonicalizationMethod on Signature: %s", c14NAlgorithm)
|
||||
}
|
||||
|
||||
el.RemoveChild(signedInfo)
|
||||
el.AddChild(canonicalSignedInfo)
|
||||
signatureEl.RemoveChild(signedInfo)
|
||||
signatureEl.AddChild(canonicalSignedInfo)
|
||||
|
||||
found = true
|
||||
|
||||
@@ -323,7 +395,7 @@ func (ctx *ValidationContext) findSignature(el *etree.Element) (*types.Signature
|
||||
|
||||
// Unmarshal the signature into a structured Signature type
|
||||
_sig := &types.Signature{}
|
||||
err = etreeutils.NSUnmarshalElement(ctx, el, _sig)
|
||||
err = etreeutils.NSUnmarshalElement(ctx, signatureEl, _sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -363,11 +435,12 @@ func (ctx *ValidationContext) verifyCertificate(sig *types.Signature) (*x509.Cer
|
||||
|
||||
if sig.KeyInfo != nil {
|
||||
// If the Signature includes KeyInfo, extract the certificate from there
|
||||
if sig.KeyInfo.X509Data.X509Certificate.Data == "" {
|
||||
if len(sig.KeyInfo.X509Data.X509Certificates) == 0 || sig.KeyInfo.X509Data.X509Certificates[0].Data == "" {
|
||||
return nil, errors.New("missing X509Certificate within KeyInfo")
|
||||
}
|
||||
|
||||
certData, err := base64.StdEncoding.DecodeString(sig.KeyInfo.X509Data.X509Certificate.Data)
|
||||
certData, err := base64.StdEncoding.DecodeString(
|
||||
whiteSpace.ReplaceAllString(sig.KeyInfo.X509Data.X509Certificates[0].Data, ""))
|
||||
if err != nil {
|
||||
return nil, errors.New("Failed to parse certificate")
|
||||
}
|
||||
|
||||
+3
@@ -50,6 +50,9 @@ const (
|
||||
CanonicalXML10ExclusiveAlgorithmId AlgorithmID = "http://www.w3.org/2001/10/xml-exc-c14n#"
|
||||
CanonicalXML11AlgorithmId AlgorithmID = "http://www.w3.org/2006/12/xml-c14n11"
|
||||
|
||||
CanonicalXML10RecAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
|
||||
CanonicalXML10CommentAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
|
||||
|
||||
EnvelopedSignatureAltorithmId AlgorithmID = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
|
||||
)
|
||||
|
||||
|
||||
-2
@@ -1,7 +1,5 @@
|
||||
module google.golang.org/grpc
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.26.0 // indirect
|
||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||
|
||||
Vendored
+3
-3
@@ -96,7 +96,7 @@ github.com/aws/aws-sdk-go/service/s3/s3iface
|
||||
github.com/aws/aws-sdk-go/service/s3/s3manager
|
||||
github.com/aws/aws-sdk-go/service/sts
|
||||
github.com/aws/aws-sdk-go/service/sts/stsiface
|
||||
# github.com/beevik/etree v0.0.0-20170418002358-cda1c0026246
|
||||
# github.com/beevik/etree v1.1.0
|
||||
## explicit
|
||||
github.com/beevik/etree
|
||||
# github.com/beorn7/perks v1.0.1
|
||||
@@ -262,7 +262,7 @@ github.com/johannesboyne/gofakes3
|
||||
github.com/johannesboyne/gofakes3/backend/s3mem
|
||||
github.com/johannesboyne/gofakes3/internal/goskipiter
|
||||
github.com/johannesboyne/gofakes3/internal/s3io
|
||||
# github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1
|
||||
# github.com/jonboulle/clockwork v0.2.1
|
||||
## explicit
|
||||
github.com/jonboulle/clockwork
|
||||
# github.com/json-iterator/go v1.1.9
|
||||
@@ -354,7 +354,7 @@ github.com/prometheus/procfs/internal/util
|
||||
## explicit
|
||||
github.com/russellhaering/gosaml2
|
||||
github.com/russellhaering/gosaml2/types
|
||||
# github.com/russellhaering/goxmldsig v0.0.0-20170515183101-605161228693
|
||||
# github.com/russellhaering/goxmldsig v1.1.0
|
||||
## explicit
|
||||
github.com/russellhaering/goxmldsig
|
||||
github.com/russellhaering/goxmldsig/etreeutils
|
||||
|
||||
Reference in New Issue
Block a user