MM-19872: Update dependencies for enterprise implementation of new SAML2 golib. (#13298)

* Update dependencies for enterprise implementation of new SAML2 golib.

* add indirect
Этот коммит содержится в:
Scott Bishel
2019-12-19 08:27:34 -07:00
коммит произвёл GitHub
родитель 155ada09fb
Коммит 3bccc03df3
53 изменённых файлов: 7563 добавлений и 0 удалений

Просмотреть файл

@@ -18,6 +18,7 @@ import (
_ "github.com/gorilla/handlers"
_ "github.com/hako/durafmt"
_ "github.com/hashicorp/memberlist"
_ "github.com/mattermost/gosaml2"
_ "github.com/mattermost/ldap"
_ "github.com/mattermost/rsc/qr"
_ "github.com/prometheus/client_golang/prometheus"

4
go.mod
Просмотреть файл

@@ -7,6 +7,7 @@ require (
github.com/NYTimes/gziphandler v1.1.1
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect
github.com/avct/uasurfer v0.0.0-20190821150637-906cc7dc6197
github.com/beevik/etree v1.1.0 // indirect
github.com/blang/semver v3.5.1+incompatible
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/corpix/uarand v0.1.1 // indirect
@@ -38,12 +39,14 @@ require (
github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428
github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43
github.com/jmoiron/sqlx v1.2.0
github.com/jonboulle/clockwork v0.1.0 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/lib/pq v1.2.0
github.com/magiconair/properties v1.8.1 // indirect
github.com/mailru/easyjson v0.7.0 // indirect
github.com/mattermost/go-i18n v1.11.0
github.com/mattermost/gorp v2.0.1-0.20190301154413-3b31e9a39d05+incompatible
github.com/mattermost/gosaml2 v0.3.2
github.com/mattermost/ldap v0.0.0-20191128190019-9f62ba4b8d4d
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0
github.com/mattermost/viper v1.0.4
@@ -65,6 +68,7 @@ require (
github.com/prometheus/common v0.7.0 // indirect
github.com/prometheus/procfs v0.0.5 // indirect
github.com/rs/cors v1.7.0
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7 // indirect
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd
github.com/segmentio/analytics-go v3.1.0+incompatible
github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c // indirect

8
go.sum
Просмотреть файл

@@ -35,6 +35,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
github.com/avct/uasurfer v0.0.0-20190821150637-906cc7dc6197 h1:E7XoJNlFlrtC6dlRG9SoGBwJpX8vD7fNTKRmgSwAj5I=
github.com/avct/uasurfer v0.0.0-20190821150637-906cc7dc6197/go.mod h1:noBAuukeYOXa0aXGqxr24tADqkwDO2KRD15FsuaZ5a8=
github.com/aws/aws-sdk-go v1.19.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
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 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
@@ -207,6 +209,8 @@ github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
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=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
@@ -244,6 +248,8 @@ github.com/mattermost/go-i18n v1.11.0 h1:1hLKqn/ZvhZ80OekjVPGYcCrBfMz+YxNNgqS+be
github.com/mattermost/go-i18n v1.11.0/go.mod h1:RyS7FDNQlzF1PsjbJWHRI35exqaKGSO9qD4iv8QjE34=
github.com/mattermost/gorp v2.0.1-0.20190301154413-3b31e9a39d05+incompatible h1:FN4zK2wNig7MVVsOsGEZ+LeIq0gUcudn3LEGgbodMq8=
github.com/mattermost/gorp v2.0.1-0.20190301154413-3b31e9a39d05+incompatible/go.mod h1:0kX1qa3DOpaPJyOdMLeo7TcBN0QmUszj9a/VygOhDe0=
github.com/mattermost/gosaml2 v0.3.2 h1:kq2dY5qUe6fPPHra171GVlgo+ycBsEog0gZMetxL8ow=
github.com/mattermost/gosaml2 v0.3.2/go.mod h1:Z429EIOiEi9kbq6yHoApfzlcXpa6dzRDc6pO+Vy2Ksk=
github.com/mattermost/ldap v0.0.0-20191128190019-9f62ba4b8d4d h1:2DV7VIlEv6J5R5o6tUcb3ZMKJYeeZuWZL7Rv1m23TgQ=
github.com/mattermost/ldap v0.0.0-20191128190019-9f62ba4b8d4d/go.mod h1:HLbgMEI5K131jpxGazJ97AxfPDt31osq36YS1oxFQPQ=
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0 h1:G9tL6JXRBMzjuD1kkBtcnd42kUiT6QDwxfFYu7adM6o=
@@ -360,6 +366,8 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7 h1:J4AOUcOh/t1XbQcJfkEqhzgvMJ2tDxdCVvmHxW5QXao=
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7/go.mod h1:Oz4y6ImuOQZxynhbSXk7btjEfNBtGlj2dcaOvXl2FSM=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/rwcarlsen/goexif v0.0.0-20190318171057-76e3344f7516 h1:unvLzUrgn54Nhn5yJB8qUBr/a7wiZHQaJ/8Y4yTGAjE=
github.com/rwcarlsen/goexif v0.0.0-20190318171057-76e3344f7516/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=

14
vendor/github.com/beevik/etree/.travis.yml сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,14 @@
language: go
sudo: false
go:
- 1.11.x
- tip
matrix:
allow_failures:
- go: tip
script:
- go vet ./...
- go test -v ./...

10
vendor/github.com/beevik/etree/CONTRIBUTORS сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,10 @@
Brett Vickers (beevik)
Felix Geisendörfer (felixge)
Kamil Kisiel (kisielk)
Graham King (grahamking)
Matt Smith (ma314smith)
Michal Jemala (michaljemala)
Nicolas Piganeau (npiganeau)
Chris Brown (ccbrown)
Earncef Sequeira (earncef)
Gabriel de Labachelerie (wuzuf)

24
vendor/github.com/beevik/etree/LICENSE сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,24 @@
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
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. 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.
THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER ``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 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.

205
vendor/github.com/beevik/etree/README.md сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,205 @@
[![Build Status](https://travis-ci.org/beevik/etree.svg?branch=master)](https://travis-ci.org/beevik/etree)
[![GoDoc](https://godoc.org/github.com/beevik/etree?status.svg)](https://godoc.org/github.com/beevik/etree)
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 capabilities and features:
* Represents XML documents as trees of elements for easy traversal.
* Imports, serializes, modifies or creates XML documents from scratch.
* Writes and reads XML to/from files, byte slices, strings and io interfaces.
* Performs simple or complex searches with lightweight XPath-like query APIs.
* Auto-indents XML using spaces or tabs for better readability.
* Implemented in pure go; depends only on standard go libraries.
* Built on top of the go [encoding/xml](http://golang.org/pkg/encoding/xml)
package.
### Creating an XML document
The following example creates an XML document from scratch using the etree
package and outputs its indented contents to stdout.
```go
doc := etree.NewDocument()
doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`)
doc.CreateProcInst("xml-stylesheet", `type="text/xsl" href="style.xsl"`)
people := doc.CreateElement("People")
people.CreateComment("These are all known people")
jon := people.CreateElement("Person")
jon.CreateAttr("name", "Jon")
sally := people.CreateElement("Person")
sally.CreateAttr("name", "Sally")
doc.Indent(2)
doc.WriteTo(os.Stdout)
```
Output:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="style.xsl"?>
<People>
<!--These are all known people-->
<Person name="Jon"/>
<Person name="Sally"/>
</People>
```
### Reading an XML file
Suppose you have a file on disk called `bookstore.xml` containing the
following data:
```xml
<bookstore xmlns:p="urn:schemas-books-com:prices">
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<p:price>30.00</p:price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<p:price>29.99</p:price>
</book>
<book category="WEB">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<p:price>49.99</p:price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<p:price>39.95</p:price>
</book>
</bookstore>
```
This code reads the file's contents into an etree document.
```go
doc := etree.NewDocument()
if err := doc.ReadFromFile("bookstore.xml"); err != nil {
panic(err)
}
```
You can also read XML from a string, a byte slice, or an `io.Reader`.
### Processing elements and attributes
This example illustrates several ways to access elements and attributes using
etree selection queries.
```go
root := doc.SelectElement("bookstore")
fmt.Println("ROOT element:", root.Tag)
for _, book := range root.SelectElements("book") {
fmt.Println("CHILD element:", book.Tag)
if title := book.SelectElement("title"); title != nil {
lang := title.SelectAttrValue("lang", "unknown")
fmt.Printf(" TITLE: %s (%s)\n", title.Text(), lang)
}
for _, attr := range book.Attr {
fmt.Printf(" ATTR: %s=%s\n", attr.Key, attr.Value)
}
}
```
Output:
```
ROOT element: bookstore
CHILD element: book
TITLE: Everyday Italian (en)
ATTR: category=COOKING
CHILD element: book
TITLE: Harry Potter (en)
ATTR: category=CHILDREN
CHILD element: book
TITLE: XQuery Kick Start (en)
ATTR: category=WEB
CHILD element: book
TITLE: Learning XML (en)
ATTR: category=WEB
```
### Path queries
This example uses etree's path functions to select all book titles that fall
into the category of 'WEB'. The double-slash prefix in the path causes the
search for book elements to occur recursively; book elements may appear at any
level of the XML hierarchy.
```go
for _, t := range doc.FindElements("//book[@category='WEB']/title") {
fmt.Println("Title:", t.Text())
}
```
Output:
```
Title: XQuery Kick Start
Title: Learning XML
```
This example finds the first book element under the root bookstore element and
outputs the tag and text of each of its child elements.
```go
for _, e := range doc.FindElements("./bookstore/book[1]/*") {
fmt.Printf("%s: %s\n", e.Tag, e.Text())
}
```
Output:
```
title: Everyday Italian
author: Giada De Laurentiis
year: 2005
price: 30.00
```
This example finds all books with a price of 49.99 and outputs their titles.
```go
path := etree.MustCompilePath("./bookstore/book[p:price='49.99']/title")
for _, e := range doc.FindElementsPath(path) {
fmt.Println(e.Text())
}
```
Output:
```
XQuery Kick Start
```
Note that this example uses the FindElementsPath function, which takes as an
argument a pre-compiled path object. Use precompiled paths when you plan to
search with the same path more than once.
### Other features
These are just a few examples of the things the etree package can do. See the
[documentation](http://godoc.org/github.com/beevik/etree) for a complete
description of its capabilities.
### Contributing
This project accepts contributions. Just fork the repo and submit a pull
request!

109
vendor/github.com/beevik/etree/RELEASE_NOTES.md сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -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.

1453
vendor/github.com/beevik/etree/etree.go сгенерированный поставляемый Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

276
vendor/github.com/beevik/etree/helpers.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,276 @@
// 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
type stack struct {
data []interface{}
}
func (s *stack) empty() bool {
return len(s.data) == 0
}
func (s *stack) push(value interface{}) {
s.data = append(s.data, value)
}
func (s *stack) pop() interface{} {
value := s.data[len(s.data)-1]
s.data[len(s.data)-1] = nil
s.data = s.data[:len(s.data)-1]
return value
}
func (s *stack) peek() interface{} {
return s.data[len(s.data)-1]
}
// A fifo is a simple first-in-first-out queue.
type fifo struct {
data []interface{}
head, tail int
}
func (f *fifo) add(value interface{}) {
if f.len()+1 >= len(f.data) {
f.grow()
}
f.data[f.tail] = value
if f.tail++; f.tail == len(f.data) {
f.tail = 0
}
}
func (f *fifo) remove() interface{} {
value := f.data[f.head]
f.data[f.head] = nil
if f.head++; f.head == len(f.data) {
f.head = 0
}
return value
}
func (f *fifo) len() int {
if f.tail >= f.head {
return f.tail - f.head
}
return len(f.data) - f.head + f.tail
}
func (f *fifo) grow() {
c := len(f.data) * 2
if c == 0 {
c = 4
}
buf, count := make([]interface{}, c), f.len()
if f.tail >= f.head {
copy(buf[0:count], f.data[f.head:f.tail])
} else {
hindex := len(f.data) - f.head
copy(buf[0:hindex], f.data[f.head:])
copy(buf[hindex:count], f.data[:f.tail])
}
f.data, f.head, f.tail = buf, 0, count
}
// countReader implements a proxy reader that counts the number of
// bytes read from its encapsulated reader.
type countReader struct {
r io.Reader
bytes int64
}
func newCountReader(r io.Reader) *countReader {
return &countReader{r: r}
}
func (cr *countReader) Read(p []byte) (n int, err error) {
b, err := cr.r.Read(p)
cr.bytes += int64(b)
return b, err
}
// countWriter implements a proxy writer that counts the number of
// bytes written by its encapsulated writer.
type countWriter struct {
w io.Writer
bytes int64
}
func newCountWriter(w io.Writer) *countWriter {
return &countWriter{w: w}
}
func (cw *countWriter) Write(p []byte) (n int, err error) {
b, err := cw.w.Write(p)
cw.bytes += int64(b)
return b, err
}
// isWhitespace returns true if the byte slice contains only
// whitespace characters.
func isWhitespace(s string) bool {
for i := 0; i < len(s); i++ {
if c := s[i]; c != ' ' && c != '\t' && c != '\n' && c != '\r' {
return false
}
}
return true
}
// spaceMatch returns true if namespace a is the empty string
// or if namespace a equals namespace b.
func spaceMatch(a, b string) bool {
switch {
case a == "":
return true
default:
return a == b
}
}
// spaceDecompose breaks a namespace:tag identifier at the ':'
// and returns the two parts.
func spaceDecompose(str string) (space, key string) {
colon := strings.IndexByte(str, ':')
if colon == -1 {
return "", str
}
return str[:colon], str[colon+1:]
}
// Strings used by indentCRLF and indentLF
const (
indentSpaces = "\r\n "
indentTabs = "\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
)
// 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[:2]
case n < len(source)-1:
return source[:n+2]
default:
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)
}
}
// nextIndex returns the index of the next occurrence of sep in s,
// starting from offset. It returns -1 if the sep string is not found.
func nextIndex(s, sep string, offset int) int {
switch i := strings.Index(s[offset:], sep); i {
case -1:
return -1
default:
return offset + i
}
}
// isInteger returns true if the string s contains an integer.
func isInteger(s string) bool {
for i := 0; i < len(s); i++ {
if (s[i] < '0' || s[i] > '9') && !(i == 0 && s[i] == '-') {
return false
}
}
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("&amp;")
case '<':
esc = []byte("&lt;")
case '>':
if m == escapeCanonicalAttr {
continue
}
esc = []byte("&gt;")
case '\'':
if m != escapeNormal {
continue
}
esc = []byte("&apos;")
case '"':
if m == escapeCanonicalText {
continue
}
esc = []byte("&quot;")
case '\t':
if m != escapeCanonicalAttr {
continue
}
esc = []byte("&#x9;")
case '\n':
if m != escapeCanonicalAttr {
continue
}
esc = []byte("&#xA;")
case '\r':
if m == escapeNormal {
continue
}
esc = []byte("&#xD;")
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
}

582
vendor/github.com/beevik/etree/path.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,582 @@
// 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 (
"strconv"
"strings"
)
/*
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.
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.
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.
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
- 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]
- Beginning from the current element, select all child elements of
book elements with an attribute 'language' set to 'english':
./book/*[@language='english']
- 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
}
// ErrPath is returned by path functions when an invalid etree path is provided.
type ErrPath string
// Error returns the string describing a path error.
func (err ErrPath) Error() string {
return "etree: " + string(err)
}
// CompilePath creates an optimized version of an XPath-like string that
// can be used to query elements in an element tree.
func CompilePath(path string) (Path, error) {
var comp compiler
segments := comp.parsePath(path)
if comp.err != ErrPath("") {
return Path{nil}, comp.err
}
return Path{segments}, nil
}
// MustCompilePath creates an optimized version of an XPath-like string that
// can be used to query elements in an element tree. Panics if an error
// occurs. Use this function to create Paths when you know the path is
// valid (i.e., if it's hard-coded).
func MustCompilePath(path string) Path {
p, err := CompilePath(path)
if err != nil {
panic(err)
}
return p
}
// A segment is a portion of a path between "/" characters.
// It contains one selector and zero or more [filters].
type segment struct {
sel selector
filters []filter
}
func (seg *segment) apply(e *Element, p *pather) {
seg.sel.apply(e, p)
for _, f := range seg.filters {
f.apply(p)
}
}
// A selector selects XML elements for consideration by the
// path traversal.
type selector interface {
apply(e *Element, p *pather)
}
// A filter pares down a list of candidate XML elements based
// on a path filter in [brackets].
type filter interface {
apply(p *pather)
}
// A pather is helper object that traverses an element tree using
// a Path object. It collects and deduplicates all elements matching
// the path query.
type pather struct {
queue fifo
results []*Element
inResults map[*Element]bool
candidates []*Element
scratch []*Element // used by filters
}
// A node represents an element and the remaining path segments that
// should be applied against it by the pather.
type node struct {
e *Element
segments []segment
}
func newPather() *pather {
return &pather{
results: make([]*Element, 0),
inResults: make(map[*Element]bool),
candidates: make([]*Element, 0),
scratch: make([]*Element, 0),
}
}
// traverse follows the path from the element e, collecting
// and then returning all elements that match the path's selectors
// and filters.
func (p *pather) traverse(e *Element, path Path) []*Element {
for p.queue.add(node{e, path.segments}); p.queue.len() > 0; {
p.eval(p.queue.remove().(node))
}
return p.results
}
// eval evalutes the current path node by applying the remaining
// path's selector rules against the node's element.
func (p *pather) eval(n node) {
p.candidates = p.candidates[0:0]
seg, remain := n.segments[0], n.segments[1:]
seg.apply(n.e, p)
if len(remain) == 0 {
for _, c := range p.candidates {
if in := p.inResults[c]; !in {
p.inResults[c] = true
p.results = append(p.results, c)
}
}
} else {
for _, c := range p.candidates {
p.queue.add(node{c, remain})
}
}
}
// A compiler generates a compiled path from a path string.
type compiler struct {
err ErrPath
}
// parsePath parses an XPath-like string describing a path
// through an element tree and returns a slice of segment
// descriptors.
func (c *compiler) parsePath(path string) []segment {
// If path ends with //, fix it
if strings.HasSuffix(path, "//") {
path = path + "*"
}
var segments []segment
// Check for an absolute path
if strings.HasPrefix(path, "/") {
segments = append(segments, segment{new(selectRoot), []filter{}})
path = path[1:]
}
// Split path into segments
for _, s := range splitPath(path) {
segments = append(segments, c.parseSegment(s))
if c.err != ErrPath("") {
break
}
}
return segments
}
func splitPath(path string) []string {
pieces := make([]string, 0)
start := 0
inquote := false
for i := 0; i+1 <= len(path); i++ {
if path[i] == '\'' {
inquote = !inquote
} else if path[i] == '/' && !inquote {
pieces = append(pieces, path[start:i])
start = i + 1
}
}
return append(pieces, path[start:])
}
// parseSegment parses a path segment between / characters.
func (c *compiler) parseSegment(path string) segment {
pieces := strings.Split(path, "[")
seg := segment{
sel: c.parseSelector(pieces[0]),
filters: []filter{},
}
for i := 1; i < len(pieces); i++ {
fpath := pieces[i]
if fpath[len(fpath)-1] != ']' {
c.err = ErrPath("path has invalid filter [brackets].")
break
}
seg.filters = append(seg.filters, c.parseFilter(fpath[:len(fpath)-1]))
}
return seg
}
// parseSelector parses a selector at the start of a path segment.
func (c *compiler) parseSelector(path string) selector {
switch path {
case ".":
return new(selectSelf)
case "..":
return new(selectParent)
case "*":
return new(selectChildren)
case "":
return new(selectDescendants)
default:
return newSelectChildrenByTag(path)
}
}
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 {
c.err = ErrPath("path contains an empty filter expression.")
return nil
}
// Filter contains [@attr='val'], [fn()='val'], or [tag='val']?
eqindex := strings.Index(path, "='")
if eqindex >= 0 {
rindex := nextIndex(path, "'", eqindex+2)
if rindex != len(path)-1 {
c.err = ErrPath("path has mismatched filter quotes.")
return nil
}
key := path[:eqindex]
value := path[eqindex+2 : rindex]
switch {
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(key, value)
}
}
// 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 {
case pos > 0:
return newFilterPos(pos - 1)
default:
return newFilterPos(pos)
}
default:
return newFilterChild(path)
}
}
// selectSelf selects the current element into the candidate list.
type selectSelf struct{}
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{}
func (s *selectParent) apply(e *Element, p *pather) {
if e.parent != nil {
p.candidates = append(p.candidates, e.parent)
}
}
// selectChildren selects the element's child elements into the
// candidate list.
type selectChildren struct{}
func (s *selectChildren) apply(e *Element, p *pather) {
for _, c := range e.Child {
if c, ok := c.(*Element); ok {
p.candidates = append(p.candidates, c)
}
}
}
// selectDescendants selects all descendant child elements
// of the element into the candidate list.
type selectDescendants struct{}
func (s *selectDescendants) apply(e *Element, p *pather) {
var queue fifo
for queue.add(e); queue.len() > 0; {
e := queue.remove().(*Element)
p.candidates = append(p.candidates, e)
for _, c := range e.Child {
if c, ok := c.(*Element); ok {
queue.add(c)
}
}
}
}
// selectChildrenByTag selects into the candidate list all child
// elements of the element having the specified tag.
type selectChildrenByTag struct {
space, tag string
}
func newSelectChildrenByTag(path string) *selectChildrenByTag {
s, l := spaceDecompose(path)
return &selectChildrenByTag{s, l}
}
func (s *selectChildrenByTag) apply(e *Element, p *pather) {
for _, c := range e.Child {
if c, ok := c.(*Element); ok && spaceMatch(s.space, c.Space) && s.tag == c.Tag {
p.candidates = append(p.candidates, c)
}
}
}
// filterPos filters the candidate list, keeping only the
// candidate at the specified index.
type filterPos struct {
index int
}
func newFilterPos(pos int) *filterPos {
return &filterPos{pos}
}
func (f *filterPos) apply(p *pather) {
if f.index >= 0 {
if f.index < len(p.candidates) {
p.scratch = append(p.scratch, p.candidates[f.index])
}
} else {
if -f.index <= len(p.candidates) {
p.scratch = append(p.scratch, p.candidates[len(p.candidates)+f.index])
}
}
p.candidates, p.scratch = p.scratch, p.candidates[0:0]
}
// filterAttr filters the candidate list for elements having
// the specified attribute.
type filterAttr struct {
space, key string
}
func newFilterAttr(str string) *filterAttr {
s, l := spaceDecompose(str)
return &filterAttr{s, l}
}
func (f *filterAttr) apply(p *pather) {
for _, c := range p.candidates {
for _, a := range c.Attr {
if spaceMatch(f.space, a.Space) && f.key == a.Key {
p.scratch = append(p.scratch, c)
break
}
}
}
p.candidates, p.scratch = p.scratch, p.candidates[0:0]
}
// filterAttrVal filters the candidate list for elements having
// the specified attribute with the specified value.
type filterAttrVal struct {
space, key, val string
}
func newFilterAttrVal(str, value string) *filterAttrVal {
s, l := spaceDecompose(str)
return &filterAttrVal{s, l, value}
}
func (f *filterAttrVal) apply(p *pather) {
for _, c := range p.candidates {
for _, a := range c.Attr {
if spaceMatch(f.space, a.Space) && f.key == a.Key && f.val == a.Value {
p.scratch = append(p.scratch, c)
break
}
}
}
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 {
space, tag string
}
func newFilterChild(str string) *filterChild {
s, l := spaceDecompose(str)
return &filterChild{s, l}
}
func (f *filterChild) apply(p *pather) {
for _, c := range p.candidates {
for _, cc := range c.Child {
if cc, ok := cc.(*Element); ok &&
spaceMatch(f.space, cc.Space) &&
f.tag == cc.Tag {
p.scratch = append(p.scratch, c)
}
}
}
p.candidates, p.scratch = p.scratch, p.candidates[0:0]
}
// filterChildText filters the candidate list for elements having
// a child element with the specified tag and text.
type filterChildText struct {
space, tag, text string
}
func newFilterChildText(str, text string) *filterChildText {
s, l := spaceDecompose(str)
return &filterChildText{s, l, text}
}
func (f *filterChildText) apply(p *pather) {
for _, c := range p.candidates {
for _, cc := range c.Child {
if cc, ok := cc.(*Element); ok &&
spaceMatch(f.space, cc.Space) &&
f.tag == cc.Tag &&
f.text == cc.Text() {
p.scratch = append(p.scratch, c)
}
}
}
p.candidates, p.scratch = p.scratch, p.candidates[0:0]
}

25
vendor/github.com/jonboulle/clockwork/.gitignore сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,25 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.swp

5
vendor/github.com/jonboulle/clockwork/.travis.yml сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,5 @@
language: go
go:
- 1.3
sudo: false

201
vendor/github.com/jonboulle/clockwork/LICENSE сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,201 @@
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.

61
vendor/github.com/jonboulle/clockwork/README.md сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,61 @@
clockwork
=========
[![Build Status](https://travis-ci.org/jonboulle/clockwork.png?branch=master)](https://travis-ci.org/jonboulle/clockwork)
[![godoc](https://godoc.org/github.com/jonboulle/clockwork?status.svg)](http://godoc.org/github.com/jonboulle/clockwork)
a simple fake clock for golang
# Usage
Replace uses of the `time` package with the `clockwork.Clock` interface instead.
For example, instead of using `time.Sleep` directly:
```
func my_func() {
time.Sleep(3 * time.Second)
do_something()
}
```
inject a clock and use its `Sleep` method instead:
```
func my_func(clock clockwork.Clock) {
clock.Sleep(3 * time.Second)
do_something()
}
```
Now you can easily test `my_func` with a `FakeClock`:
```
func TestMyFunc(t *testing.T) {
c := clockwork.NewFakeClock()
// Start our sleepy function
my_func(c)
// Ensure we wait until my_func is sleeping
c.BlockUntil(1)
assert_state()
// Advance the FakeClock forward in time
c.Advance(3)
assert_state()
}
```
and in production builds, simply inject the real clock instead:
```
my_func(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](http://blog.golang.org/playground#Faking time)

169
vendor/github.com/jonboulle/clockwork/clockwork.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,169 @@
package clockwork
import (
"sync"
"time"
)
// Clock provides an interface that packages can use instead of directly
// using the time module, so that chronology-related behavior can be tested
type Clock interface {
After(d time.Duration) <-chan time.Time
Sleep(d time.Duration)
Now() time.Time
}
// FakeClock provides an interface for a clock which can be
// manually advanced through time
type FakeClock interface {
Clock
// Advance advances the FakeClock to a new point in time, ensuring any existing
// sleepers are notified appropriately before returning
Advance(d time.Duration)
// BlockUntil will block until the FakeClock has the given number of
// sleepers (callers of Sleep or After)
BlockUntil(n int)
}
// NewRealClock returns a Clock which simply delegates calls to the actual time
// package; it should be used by packages in production.
func NewRealClock() Clock {
return &realClock{}
}
// NewFakeClock returns a FakeClock implementation which can be
// manually advanced through time for testing. The initial time of the
// FakeClock will be an arbitrary non-zero time.
func NewFakeClock() FakeClock {
// use a fixture that does not fulfill Time.IsZero()
return NewFakeClockAt(time.Date(1984, time.April, 4, 0, 0, 0, 0, time.UTC))
}
// NewFakeClockAt returns a FakeClock initialised at the given time.Time.
func NewFakeClockAt(t time.Time) FakeClock {
return &fakeClock{
time: t,
}
}
type realClock struct{}
func (rc *realClock) After(d time.Duration) <-chan time.Time {
return time.After(d)
}
func (rc *realClock) Sleep(d time.Duration) {
time.Sleep(d)
}
func (rc *realClock) Now() time.Time {
return time.Now()
}
type fakeClock struct {
sleepers []*sleeper
blockers []*blocker
time time.Time
l sync.RWMutex
}
// sleeper represents a caller of After or Sleep
type sleeper struct {
until time.Time
done chan time.Time
}
// blocker represents a caller of BlockUntil
type blocker struct {
count int
ch chan struct{}
}
// After mimics time.After; it waits for the given duration to elapse on the
// fakeClock, then sends the current time on the returned channel.
func (fc *fakeClock) After(d time.Duration) <-chan time.Time {
fc.l.Lock()
defer fc.l.Unlock()
now := fc.time
done := make(chan time.Time, 1)
if d.Nanoseconds() == 0 {
// special case - trigger immediately
done <- now
} else {
// otherwise, add to the set of sleepers
s := &sleeper{
until: now.Add(d),
done: done,
}
fc.sleepers = append(fc.sleepers, s)
// and notify any blockers
fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
}
return done
}
// notifyBlockers notifies all the blockers waiting until the
// given number of sleepers are waiting on the fakeClock. It
// returns an updated slice of blockers (i.e. those still waiting)
func notifyBlockers(blockers []*blocker, count int) (newBlockers []*blocker) {
for _, b := range blockers {
if b.count == count {
close(b.ch)
} else {
newBlockers = append(newBlockers, b)
}
}
return
}
// Sleep blocks until the given duration has passed on the fakeClock
func (fc *fakeClock) Sleep(d time.Duration) {
<-fc.After(d)
}
// Time returns the current time of the fakeClock
func (fc *fakeClock) Now() time.Time {
fc.l.RLock()
t := fc.time
fc.l.RUnlock()
return t
}
// Advance advances fakeClock to a new point in time, ensuring channels from any
// previous invocations of After are notified appropriately before returning
func (fc *fakeClock) Advance(d time.Duration) {
fc.l.Lock()
defer fc.l.Unlock()
end := fc.time.Add(d)
var newSleepers []*sleeper
for _, s := range fc.sleepers {
if end.Sub(s.until) >= 0 {
s.done <- end
} else {
newSleepers = append(newSleepers, s)
}
}
fc.sleepers = newSleepers
fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
fc.time = end
}
// BlockUntil will block until the fakeClock has the given number of sleepers
// (callers of Sleep or After)
func (fc *fakeClock) BlockUntil(n int) {
fc.l.Lock()
// Fast path: current number of sleepers is what we're looking for
if len(fc.sleepers) == n {
fc.l.Unlock()
return
}
// Otherwise, set up a new blocker
b := &blocker{
count: n,
ch: make(chan struct{}),
}
fc.blockers = append(fc.blockers, b)
fc.l.Unlock()
<-b.ch
}

1
vendor/github.com/mattermost/gosaml2/.gitignore сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1 @@
*.test

15
vendor/github.com/mattermost/gosaml2/.travis.yml сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,15 @@
language: go
go:
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- tip
matrix:
allow_failures:
- go: tip

175
vendor/github.com/mattermost/gosaml2/LICENSE сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,175 @@
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.

34
vendor/github.com/mattermost/gosaml2/README.md сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,34 @@
# gosaml2
[![Build Status](https://travis-ci.org/russellhaering/gosaml2.svg?branch=master)](https://travis-ci.org/russellhaering/gosaml2)
[![GoDoc](https://godoc.org/github.com/russellhaering/gosaml2?status.svg)](https://godoc.org/github.com/russellhaering/gosaml2)
SAML 2.0 implemementation for Service Providers based on [etree](https://github.com/beevik/etree)
and [goxmldsig](https://github.com/russellhaering/goxmldsig), a pure Go
implementation of XML digital signatures.
## Installation
Install `gosaml2` into your `$GOPATH` using `go get`:
```
go get github.com/russellhaering/gosaml2
```
## Example
See [demo.go](s2example/demo.go).
## Supported Identity Providers
This library is meant to be a generic SAML implementation. If you find a
standards compliant identity provider that it doesn't work with please
submit a bug or pull request.
The following identity providers have been tested:
* Okta
* Auth0
* Shibboleth
* Ipsilon
* OneLogin

19
vendor/github.com/mattermost/gosaml2/attribute.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,19 @@
package saml2
import "github.com/mattermost/gosaml2/types"
// Values is a convenience wrapper for a map of strings to Attributes, which
// can be used for easy access to the string values of Attribute lists.
type Values map[string]types.Attribute
// Get is a safe method (nil maps will not panic) for returning the first value
// for an attribute at a key, or the empty string if none exists.
func (vals Values) Get(k string) string {
if vals == nil {
return ""
}
if v, ok := vals[k]; ok && len(v.Values) > 0 {
return string(v.Values[0].Value)
}
return ""
}

16
vendor/github.com/mattermost/gosaml2/authn_request.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,16 @@
package saml2
import "time"
// AuthNRequest is the go struct representation of an authentication request
type AuthNRequest struct {
ID string `xml:",attr"`
Version string `xml:",attr"`
ProtocolBinding string `xml:",attr"`
AssertionConsumerServiceURL string `xml:",attr"`
IssueInstant time.Time `xml:",attr"`
Destination string `xml:",attr"`
Issuer string
}

226
vendor/github.com/mattermost/gosaml2/build_request.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,226 @@
package saml2
import (
"bytes"
"compress/flate"
"encoding/base64"
"fmt"
"net/http"
"net/url"
"github.com/beevik/etree"
"github.com/mattermost/gosaml2/uuid"
)
const issueInstantFormat = "2006-01-02T15:04:05Z"
func (sp *SAMLServiceProvider) buildAuthnRequest(includeSig bool) (*etree.Document, error) {
authnRequest := &etree.Element{
Space: "samlp",
Tag: "AuthnRequest",
}
authnRequest.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol")
authnRequest.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion")
arId := uuid.NewV4()
authnRequest.CreateAttr("ID", "_"+arId.String())
authnRequest.CreateAttr("Version", "2.0")
authnRequest.CreateAttr("ProtocolBinding", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")
authnRequest.CreateAttr("AssertionConsumerServiceURL", sp.AssertionConsumerServiceURL)
authnRequest.CreateAttr("IssueInstant", sp.Clock.Now().UTC().Format(issueInstantFormat))
authnRequest.CreateAttr("Destination", sp.IdentityProviderSSOURL)
// NOTE(russell_h): In earlier versions we mistakenly sent the IdentityProviderIssuer
// in the AuthnRequest. For backwards compatibility we will fall back to that
// behavior when ServiceProviderIssuer isn't set.
if sp.ServiceProviderIssuer != "" {
authnRequest.CreateElement("saml:Issuer").SetText(sp.ServiceProviderIssuer)
} else {
authnRequest.CreateElement("saml:Issuer").SetText(sp.IdentityProviderIssuer)
}
nameIdPolicy := authnRequest.CreateElement("samlp:NameIDPolicy")
nameIdPolicy.CreateAttr("AllowCreate", "true")
nameIdPolicy.CreateAttr("Format", sp.NameIdFormat)
if sp.RequestedAuthnContext != nil {
requestedAuthnContext := authnRequest.CreateElement("samlp:RequestedAuthnContext")
requestedAuthnContext.CreateAttr("Comparison", sp.RequestedAuthnContext.Comparison)
for _, context := range sp.RequestedAuthnContext.Contexts {
authnContextClassRef := requestedAuthnContext.CreateElement("saml:AuthnContextClassRef")
authnContextClassRef.SetText(context)
}
}
if sp.ScopingIDPProviderId != "" && sp.ScopingIDPProviderName != "" {
scoping := authnRequest.CreateElement("samlp:Scoping")
idpList := scoping.CreateElement("samlp:IDPList")
idpEntry := idpList.CreateElement("samlp:IDPEntry")
idpEntry.CreateAttr("ProviderID", sp.ScopingIDPProviderId)
idpEntry.CreateAttr("Name", sp.ScopingIDPProviderName)
}
doc := etree.NewDocument()
// Only POST binding includes <Signature> in <AuthnRequest> (includeSig)
if sp.SignAuthnRequests && includeSig {
signed, err := sp.SignAuthnRequest(authnRequest)
if err != nil {
return nil, err
}
doc.SetRoot(signed)
} else {
doc.SetRoot(authnRequest)
}
return doc, nil
}
func (sp *SAMLServiceProvider) BuildAuthRequestDocument() (*etree.Document, error) {
return sp.buildAuthnRequest(true)
}
func (sp *SAMLServiceProvider) BuildAuthRequestDocumentNoSig() (*etree.Document, error) {
return sp.buildAuthnRequest(false)
}
// SignAuthnRequest takes a document, builds a signature, creates another document
// and inserts the signature in it. According to the schema, the position of the
// signature is right after the Issuer [1] then all other children.
//
// [1] https://docs.oasis-open.org/security/saml/v2.0/saml-schema-protocol-2.0.xsd
func (sp *SAMLServiceProvider) SignAuthnRequest(el *etree.Element) (*etree.Element, error) {
ctx := sp.SigningContext()
sig, err := ctx.ConstructSignature(el, true)
if err != nil {
return nil, err
}
ret := el.Copy()
var children []etree.Token
children = append(children, ret.Child[0]) // issuer is always first
children = append(children, sig) // next is the signature
children = append(children, ret.Child[1:]...) // then all other children
ret.Child = children
return ret, nil
}
// BuildAuthRequest builds <AuthnRequest> for identity provider
func (sp *SAMLServiceProvider) BuildAuthRequest() (string, error) {
doc, err := sp.BuildAuthRequestDocument()
if err != nil {
return "", err
}
return doc.WriteToString()
}
func (sp *SAMLServiceProvider) buildAuthURLFromDocument(relayState, binding string, doc *etree.Document) (string, error) {
parsedUrl, err := url.Parse(sp.IdentityProviderSSOURL)
if err != nil {
return "", err
}
authnRequest, err := doc.WriteToString()
if err != nil {
return "", err
}
buf := &bytes.Buffer{}
fw, err := flate.NewWriter(buf, flate.DefaultCompression)
if err != nil {
return "", fmt.Errorf("flate NewWriter error: %v", err)
}
_, err = fw.Write([]byte(authnRequest))
if err != nil {
return "", fmt.Errorf("flate.Writer Write error: %v", err)
}
err = fw.Close()
if err != nil {
return "", fmt.Errorf("flate.Writer Close error: %v", err)
}
qs := parsedUrl.Query()
qs.Add("SAMLRequest", base64.StdEncoding.EncodeToString(buf.Bytes()))
if relayState != "" {
qs.Add("RelayState", relayState)
}
if sp.SignAuthnRequests && binding == BindingHttpRedirect {
// Sign URL encoded query (see Section 3.4.4.1 DEFLATE Encoding of saml-bindings-2.0-os.pdf)
ctx := sp.SigningContext()
qs.Add("SigAlg", ctx.GetSignatureMethodIdentifier())
var rawSignature []byte
if rawSignature, err = ctx.SignString(signatureInputString(qs.Get("SAMLRequest"), qs.Get("RelayState"), qs.Get("SigAlg"))); err != nil {
return "", fmt.Errorf("unable to sign query string of redirect URL: %v", err)
}
// Now add base64 encoded Signature
qs.Add("Signature", base64.StdEncoding.EncodeToString(rawSignature))
}
parsedUrl.RawQuery = qs.Encode()
return parsedUrl.String(), nil
}
func (sp *SAMLServiceProvider) BuildAuthURLFromDocument(relayState string, doc *etree.Document) (string, error) {
return sp.buildAuthURLFromDocument(relayState, BindingHttpPost, doc)
}
func (sp *SAMLServiceProvider) BuildAuthURLRedirect(relayState string, doc *etree.Document) (string, error) {
return sp.buildAuthURLFromDocument(relayState, BindingHttpRedirect, doc)
}
// BuildAuthURL builds redirect URL to be sent to principal
func (sp *SAMLServiceProvider) BuildAuthURL(relayState string) (string, error) {
doc, err := sp.BuildAuthRequestDocument()
if err != nil {
return "", err
}
return sp.BuildAuthURLFromDocument(relayState, doc)
}
// AuthRedirect takes a ResponseWriter and Request from an http interaction and
// redirects to the SAMLServiceProvider's configured IdP, including the
// relayState provided, if any.
func (sp *SAMLServiceProvider) AuthRedirect(w http.ResponseWriter, r *http.Request, relayState string) (err error) {
url, err := sp.BuildAuthURL(relayState)
if err != nil {
return err
}
http.Redirect(w, r, url, http.StatusFound)
return nil
}
// signatureInputString constructs the string to be fed into the signature algorithm, as described
// in section 3.4.4.1 of
// https://www.oasis-open.org/committees/download.php/56779/sstc-saml-bindings-errata-2.0-wd-06.pdf
func signatureInputString(samlRequest, relayState, sigAlg string) string {
var params [][2]string
if relayState == "" {
params = [][2]string{{"SAMLRequest", samlRequest}, {"SigAlg", sigAlg}}
} else {
params = [][2]string{{"SAMLRequest", samlRequest}, {"RelayState", relayState}, {"SigAlg", sigAlg}}
}
var buf bytes.Buffer
for _, kv := range params {
k, v := kv[0], kv[1]
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(url.QueryEscape(k) + "=" + url.QueryEscape(v))
}
return buf.String()
}

337
vendor/github.com/mattermost/gosaml2/decode_response.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,337 @@
package saml2
import (
"bytes"
"compress/flate"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"fmt"
"io/ioutil"
"encoding/xml"
"github.com/beevik/etree"
"github.com/mattermost/gosaml2/types"
dsig "github.com/russellhaering/goxmldsig"
"github.com/russellhaering/goxmldsig/etreeutils"
)
func (sp *SAMLServiceProvider) validationContext() *dsig.ValidationContext {
ctx := dsig.NewDefaultValidationContext(sp.IDPCertificateStore)
ctx.Clock = sp.Clock
return ctx
}
// validateResponseAttributes validates a SAML Response's tag and attributes. It does
// not inspect child elements of the Response at all.
func (sp *SAMLServiceProvider) validateResponseAttributes(response *types.Response) error {
if response.Destination != "" && response.Destination != sp.AssertionConsumerServiceURL {
return ErrInvalidValue{
Key: DestinationAttr,
Expected: sp.AssertionConsumerServiceURL,
Actual: response.Destination,
}
}
if response.Version != "2.0" {
return ErrInvalidValue{
Reason: ReasonUnsupported,
Key: "SAML version",
Expected: "2.0",
Actual: response.Version,
}
}
return nil
}
func xmlUnmarshalElement(el *etree.Element, obj interface{}) error {
doc := etree.NewDocument()
doc.SetRoot(el)
data, err := doc.WriteToBytes()
if err != nil {
return err
}
err = xml.Unmarshal(data, obj)
if err != nil {
return err
}
return nil
}
func (sp *SAMLServiceProvider) getDecryptCert() (*tls.Certificate, error) {
if sp.SPKeyStore == nil {
return nil, fmt.Errorf("no decryption certs available")
}
//This is the tls.Certificate we'll use to decrypt any encrypted assertions
var decryptCert tls.Certificate
switch crt := sp.SPKeyStore.(type) {
case dsig.TLSCertKeyStore:
// Get the tls.Certificate directly if possible
decryptCert = tls.Certificate(crt)
default:
//Otherwise, construct one from the results of GetKeyPair
pk, cert, err := sp.SPKeyStore.GetKeyPair()
if err != nil {
return nil, fmt.Errorf("error getting keypair: %v", err)
}
decryptCert = tls.Certificate{
Certificate: [][]byte{cert},
PrivateKey: pk,
}
}
if sp.ValidateEncryptionCert {
// Check Validity period of certificate
if len(decryptCert.Certificate) < 1 || len(decryptCert.Certificate[0]) < 1 {
return nil, fmt.Errorf("empty decryption cert")
} else if cert, err := x509.ParseCertificate(decryptCert.Certificate[0]); err != nil {
return nil, fmt.Errorf("invalid x509 decryption cert: %v", err)
} else {
now := sp.Clock.Now()
if now.Before(cert.NotBefore) || now.After(cert.NotAfter) {
return nil, fmt.Errorf("decryption cert is not valid at this time")
}
}
}
return &decryptCert, nil
}
func (sp *SAMLServiceProvider) decryptAssertions(el *etree.Element) error {
var decryptCert *tls.Certificate
decryptAssertion := func(ctx etreeutils.NSContext, encryptedElement *etree.Element) error {
if encryptedElement.Parent() != el {
return fmt.Errorf("found encrypted assertion with unexpected parent element: %s", encryptedElement.Parent().Tag)
}
detached, err := etreeutils.NSDetatch(ctx, encryptedElement) // make a detached copy
if err != nil {
return fmt.Errorf("unable to detach encrypted assertion: %v", err)
}
encryptedAssertion := &types.EncryptedAssertion{}
err = xmlUnmarshalElement(detached, encryptedAssertion)
if err != nil {
return fmt.Errorf("unable to unmarshal encrypted assertion: %v", err)
}
if decryptCert == nil {
decryptCert, err = sp.getDecryptCert()
if err != nil {
return fmt.Errorf("unable to get decryption certificate: %v", err)
}
}
raw, derr := encryptedAssertion.DecryptBytes(decryptCert)
if derr != nil {
return fmt.Errorf("unable to decrypt encrypted assertion: %v", derr)
}
doc, _, err := parseResponse(raw)
if err != nil {
return fmt.Errorf("unable to create element from decrypted assertion bytes: %v", derr)
}
// Replace the original encrypted assertion with the decrypted one.
if el.RemoveChild(encryptedElement) == nil {
// Out of an abundance of caution, make sure removed worked
panic("unable to remove encrypted assertion")
}
el.AddChild(doc.Root())
return nil
}
if err := etreeutils.NSFindIterate(el, SAMLAssertionNamespace, EncryptedAssertionTag, decryptAssertion); err != nil {
return err
} else {
return nil
}
}
func (sp *SAMLServiceProvider) validateElementSignature(el *etree.Element) (*etree.Element, error) {
return sp.validationContext().Validate(el)
}
func (sp *SAMLServiceProvider) validateAssertionSignatures(el *etree.Element) error {
signedAssertions := 0
unsignedAssertions := 0
validateAssertion := func(ctx etreeutils.NSContext, unverifiedAssertion *etree.Element) error {
if unverifiedAssertion.Parent() != el {
return fmt.Errorf("found assertion with unexpected parent element: %s", unverifiedAssertion.Parent().Tag)
}
detached, err := etreeutils.NSDetatch(ctx, unverifiedAssertion) // make a detached copy
if err != nil {
return fmt.Errorf("unable to detach unverified assertion: %v", err)
}
assertion, err := sp.validationContext().Validate(detached)
if err == dsig.ErrMissingSignature {
unsignedAssertions++
return nil
} else if err != nil {
return err
}
// Replace the original unverified Assertion with the verified one. Note that
// if the Response is not signed, only signed Assertions (and not the parent Response) can be trusted.
if el.RemoveChild(unverifiedAssertion) == nil {
// Out of an abundance of caution, check to make sure an Assertion was actually
// removed. If it wasn't a programming error has occurred.
panic("unable to remove assertion")
}
el.AddChild(assertion)
signedAssertions++
return nil
}
if err := etreeutils.NSFindIterate(el, SAMLAssertionNamespace, AssertionTag, validateAssertion); err != nil {
return err
} else if signedAssertions > 0 && unsignedAssertions > 0 {
return fmt.Errorf("invalid to have both signed and unsigned assertions")
} else if signedAssertions < 1 {
return dsig.ErrMissingSignature
} else {
return nil
}
}
//ValidateEncodedResponse both decodes and validates, based on SP
//configuration, an encoded, signed response. It will also appropriately
//decrypt a response if the assertion was encrypted
func (sp *SAMLServiceProvider) ValidateEncodedResponse(encodedResponse string) (*types.Response, error) {
raw, err := base64.StdEncoding.DecodeString(encodedResponse)
if err != nil {
return nil, err
}
// Parse the raw response
doc, el, err := parseResponse(raw)
if err != nil {
return nil, err
}
var responseSignatureValidated bool
if !sp.SkipSignatureValidation {
el, err = sp.validateElementSignature(el)
if err == dsig.ErrMissingSignature {
// Unfortunately we just blew away our Response
el = doc.Root()
} else if err != nil {
return nil, err
} else if el == nil {
return nil, fmt.Errorf("missing transformed response")
} else {
responseSignatureValidated = true
}
}
err = sp.decryptAssertions(el)
if err != nil {
return nil, err
}
var assertionSignaturesValidated bool
if !sp.SkipSignatureValidation {
err = sp.validateAssertionSignatures(el)
if err == dsig.ErrMissingSignature {
if !responseSignatureValidated {
return nil, fmt.Errorf("response and/or assertions must be signed")
}
} else if err != nil {
return nil, err
} else {
assertionSignaturesValidated = true
}
}
decodedResponse := &types.Response{}
err = xmlUnmarshalElement(el, decodedResponse)
if err != nil {
return nil, fmt.Errorf("unable to unmarshal response: %v", err)
}
decodedResponse.SignatureValidated = responseSignatureValidated
if assertionSignaturesValidated {
for idx := 0; idx < len(decodedResponse.Assertions); idx++ {
decodedResponse.Assertions[idx].SignatureValidated = true
}
}
err = sp.Validate(decodedResponse)
if err != nil {
return nil, err
}
return decodedResponse, nil
}
// DecodeUnverifiedBaseResponse decodes several attributes from a SAML response for the purpose
// of determining how to validate the response. This is useful for Service Providers which
// expose a single Assertion Consumer Service URL but consume Responses from many IdPs.
func DecodeUnverifiedBaseResponse(encodedResponse string) (*types.UnverifiedBaseResponse, error) {
raw, err := base64.StdEncoding.DecodeString(encodedResponse)
if err != nil {
return nil, err
}
var response *types.UnverifiedBaseResponse
err = maybeDeflate(raw, func(maybeXML []byte) error {
response = &types.UnverifiedBaseResponse{}
return xml.Unmarshal(maybeXML, response)
})
if err != nil {
return nil, err
}
return response, nil
}
// maybeDeflate invokes the passed decoder over the passed data. If an error is
// returned, it then attempts to deflate the passed data before re-invoking
// the decoder over the deflated data.
func maybeDeflate(data []byte, decoder func([]byte) error) error {
err := decoder(data)
if err == nil {
return nil
}
deflated, err := ioutil.ReadAll(flate.NewReader(bytes.NewReader(data)))
if err != nil {
return err
}
return decoder(deflated)
}
// parseResponse is a helper function that was refactored out so that the XML parsing behavior can be isolated and unit tested
func parseResponse(xml []byte) (*etree.Document, *etree.Element, error) {
var doc *etree.Document
err := maybeDeflate(xml, func(xml []byte) error {
doc = etree.NewDocument()
return doc.ReadFromBytes(xml)
})
if err != nil {
return nil, nil, err
}
el := doc.Root()
if el == nil {
return nil, nil, fmt.Errorf("unable to parse response")
}
return doc, el, nil
}

95
vendor/github.com/mattermost/gosaml2/retrieve_assertion.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,95 @@
package saml2
import "fmt"
//ErrMissingElement is the error type that indicates an element and/or attribute is
//missing. It provides a structured error that can be more appropriately acted
//upon.
type ErrMissingElement struct {
Tag, Attribute string
}
type ErrVerification struct {
Cause error
}
func (e ErrVerification) Error() string {
return fmt.Sprintf("error validating response: %s", e.Cause.Error())
}
//ErrMissingAssertion indicates that an appropriate assertion element could not
//be found in the SAML Response
var (
ErrMissingAssertion = ErrMissingElement{Tag: AssertionTag}
)
func (e ErrMissingElement) Error() string {
if e.Attribute != "" {
return fmt.Sprintf("missing %s attribute on %s element", e.Attribute, e.Tag)
}
return fmt.Sprintf("missing %s element", e.Tag)
}
//RetrieveAssertionInfo takes an encoded response and returns the AssertionInfo
//contained, or an error message if an error has been encountered.
func (sp *SAMLServiceProvider) RetrieveAssertionInfo(encodedResponse string) (*AssertionInfo, error) {
assertionInfo := &AssertionInfo{
Values: make(Values),
}
response, err := sp.ValidateEncodedResponse(encodedResponse)
if err != nil {
return nil, ErrVerification{Cause: err}
}
// TODO: Support multiple assertions
if len(response.Assertions) == 0 {
return nil, ErrMissingAssertion
}
assertion := response.Assertions[0]
assertionInfo.Assertions = response.Assertions
assertionInfo.ResponseSignatureValidated = response.SignatureValidated
warningInfo, err := sp.VerifyAssertionConditions(&assertion)
if err != nil {
return nil, err
}
//Get the NameID
subject := assertion.Subject
if subject == nil {
return nil, ErrMissingElement{Tag: SubjectTag}
}
nameID := subject.NameID
if nameID == nil {
return nil, ErrMissingElement{Tag: NameIdTag}
}
assertionInfo.NameID = nameID.Value
//Get the actual assertion attributes
attributeStatement := assertion.AttributeStatement
if attributeStatement == nil && !sp.AllowMissingAttributes {
return nil, ErrMissingElement{Tag: AttributeStatementTag}
}
if attributeStatement != nil {
for _, attribute := range attributeStatement.Attributes {
assertionInfo.Values[attribute.Name] = attribute
}
}
if assertion.AuthnStatement != nil {
if assertion.AuthnStatement.AuthnInstant != nil {
assertionInfo.AuthnInstant = assertion.AuthnStatement.AuthnInstant
}
if assertion.AuthnStatement.SessionNotOnOrAfter != nil {
assertionInfo.SessionNotOnOrAfter = assertion.AuthnStatement.SessionNotOnOrAfter
}
}
assertionInfo.WarningInfo = warningInfo
return assertionInfo, nil
}

12
vendor/github.com/mattermost/gosaml2/run_test.sh сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -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

196
vendor/github.com/mattermost/gosaml2/saml.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,196 @@
package saml2
import (
"encoding/base64"
"sync"
"time"
"github.com/mattermost/gosaml2/types"
dsig "github.com/russellhaering/goxmldsig"
dsigtypes "github.com/russellhaering/goxmldsig/types"
)
type ErrSaml struct {
Message string
System error
}
func (serr ErrSaml) Error() string {
if serr.Message != "" {
return serr.Message
}
return "SAML error"
}
type SAMLServiceProvider struct {
IdentityProviderSSOURL string
IdentityProviderIssuer string
AssertionConsumerServiceURL string
ServiceProviderIssuer string
SignAuthnRequests bool
SignAuthnRequestsAlgorithm string
SignAuthnRequestsCanonicalizer dsig.Canonicalizer
// RequestedAuthnContext allows service providers to require that the identity
// provider use specific authentication mechanisms. Leaving this unset will
// permit the identity provider to choose the auth method. To maximize compatibility
// with identity providers it is recommended to leave this unset.
RequestedAuthnContext *RequestedAuthnContext
AudienceURI string
IDPCertificateStore dsig.X509CertificateStore
SPKeyStore dsig.X509KeyStore // Required encryption key, default signing key
SPSigningKeyStore dsig.X509KeyStore // Optional signing key
NameIdFormat string
ValidateEncryptionCert bool
SkipSignatureValidation bool
AllowMissingAttributes bool
ScopingIDPProviderId string
ScopingIDPProviderName string
Clock *dsig.Clock
signingContextMu sync.RWMutex
signingContext *dsig.SigningContext
}
// RequestedAuthnContext controls which authentication mechanisms are requested of
// the identity provider. It is generally sufficient to omit this and let the
// identity provider select an authentication mechansim.
type RequestedAuthnContext struct {
// The RequestedAuthnContext comparison policy to use. See the section 3.3.2.2.1
// of the SAML 2.0 specification for details. Constants named AuthnPolicyMatch*
// contain standardized values.
Comparison string
// Contexts will be passed as AuthnContextClassRefs. For example, to force password
// authentication on some identity providers, Contexts should have a value of
// []string{AuthnContextPasswordProtectedTransport}, and Comparison should have a
// value of AuthnPolicyMatchExact.
Contexts []string
}
func (sp *SAMLServiceProvider) Metadata() (*types.EntityDescriptor, error) {
signingCertBytes, err := sp.GetSigningCertBytes()
if err != nil {
return nil, err
}
encryptionCertBytes, err := sp.GetEncryptionCertBytes()
if err != nil {
return nil, err
}
return &types.EntityDescriptor{
ValidUntil: time.Now().UTC().Add(time.Hour * 24 * 7), // 7 days
EntityID: sp.ServiceProviderIssuer,
SPSSODescriptor: &types.SPSSODescriptor{
AuthnRequestsSigned: sp.SignAuthnRequests,
WantAssertionsSigned: !sp.SkipSignatureValidation,
ProtocolSupportEnumeration: SAMLProtocolNamespace,
KeyDescriptors: []types.KeyDescriptor{
{
Use: "signing",
KeyInfo: dsigtypes.KeyInfo{
X509Data: dsigtypes.X509Data{
X509Certificates: []dsigtypes.X509Certificate{dsigtypes.X509Certificate{
Data: base64.StdEncoding.EncodeToString(signingCertBytes),
}},
},
},
},
{
Use: "encryption",
KeyInfo: dsigtypes.KeyInfo{
X509Data: dsigtypes.X509Data{
X509Certificates: []dsigtypes.X509Certificate{dsigtypes.X509Certificate{
Data: base64.StdEncoding.EncodeToString(encryptionCertBytes),
}},
},
},
EncryptionMethods: []types.EncryptionMethod{
{Algorithm: types.MethodAES128GCM},
{Algorithm: types.MethodAES128CBC},
{Algorithm: types.MethodAES256CBC},
},
},
},
AssertionConsumerServices: []types.IndexedEndpoint{{
Binding: BindingHttpPost,
Location: sp.AssertionConsumerServiceURL,
Index: 1,
}},
},
}, nil
}
func (sp *SAMLServiceProvider) GetEncryptionKey() dsig.X509KeyStore {
return sp.SPKeyStore
}
func (sp *SAMLServiceProvider) GetSigningKey() dsig.X509KeyStore {
if sp.SPSigningKeyStore == nil {
return sp.GetEncryptionKey() // Default is signing key is same as encryption key
}
return sp.SPSigningKeyStore
}
func (sp *SAMLServiceProvider) GetEncryptionCertBytes() ([]byte, error) {
if _, encryptionCert, err := sp.GetEncryptionKey().GetKeyPair(); err != nil {
return nil, ErrSaml{Message: "no SP encryption certificate", System: err}
} else if len(encryptionCert) < 1 {
return nil, ErrSaml{Message: "empty SP encryption certificate"}
} else {
return encryptionCert, nil
}
}
func (sp *SAMLServiceProvider) GetSigningCertBytes() ([]byte, error) {
if _, signingCert, err := sp.GetSigningKey().GetKeyPair(); err != nil {
return nil, ErrSaml{Message: "no SP signing certificate", System: err}
} else if len(signingCert) < 1 {
return nil, ErrSaml{Message: "empty SP signing certificate"}
} else {
return signingCert, nil
}
}
func (sp *SAMLServiceProvider) SigningContext() *dsig.SigningContext {
sp.signingContextMu.RLock()
signingContext := sp.signingContext
sp.signingContextMu.RUnlock()
if signingContext != nil {
return signingContext
}
sp.signingContextMu.Lock()
defer sp.signingContextMu.Unlock()
sp.signingContext = dsig.NewDefaultSigningContext(sp.GetSigningKey())
sp.signingContext.SetSignatureMethod(sp.SignAuthnRequestsAlgorithm)
if sp.SignAuthnRequestsCanonicalizer != nil {
sp.signingContext.Canonicalizer = sp.SignAuthnRequestsCanonicalizer
}
return sp.signingContext
}
type ProxyRestriction struct {
Count int
Audience []string
}
type WarningInfo struct {
OneTimeUse bool
ProxyRestriction *ProxyRestriction
NotInAudience bool
InvalidTime bool
}
type AssertionInfo struct {
NameID string
Values Values
WarningInfo *WarningInfo
AuthnInstant *time.Time
SessionNotOnOrAfter *time.Time
Assertions []types.Assertion
ResponseSignatureValidated bool
}

395
vendor/github.com/mattermost/gosaml2/test_constants.go сгенерированный поставляемый Обычный файл

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

83
vendor/github.com/mattermost/gosaml2/types/encrypted_assertion.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,83 @@
package types
import (
"bytes"
"crypto/cipher"
"crypto/tls"
"encoding/base64"
"encoding/xml"
"fmt"
)
type EncryptedAssertion struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion EncryptedAssertion"`
EncryptionMethod EncryptionMethod `xml:"EncryptedData>EncryptionMethod"`
EncryptedKey EncryptedKey `xml:"EncryptedData>KeyInfo>EncryptedKey"`
DetEncryptedKey EncryptedKey `xml:"EncryptedKey"` // detached EncryptedKey element
CipherValue string `xml:"EncryptedData>CipherData>CipherValue"`
}
func (ea *EncryptedAssertion) DecryptBytes(cert *tls.Certificate) ([]byte, error) {
data, err := base64.StdEncoding.DecodeString(ea.CipherValue)
if err != nil {
return nil, err
}
// EncryptedKey must include CipherValue. EncryptedKey may be part of EncryptedData.
ek := &ea.EncryptedKey
if ek.CipherValue == "" {
// Use detached EncryptedKey element (sibling of EncryptedData). See:
// https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html#sec-Extensions-to-KeyInfo
ek = &ea.DetEncryptedKey
}
k, err := ek.DecryptSymmetricKey(cert)
if err != nil {
return nil, fmt.Errorf("cannot decrypt, error retrieving private key: %s", err)
}
switch ea.EncryptionMethod.Algorithm {
case MethodAES128GCM:
c, err := cipher.NewGCM(k)
if err != nil {
return nil, fmt.Errorf("cannot create AES-GCM: %s", err)
}
nonce, data := data[:c.NonceSize()], data[c.NonceSize():]
plainText, err := c.Open(nil, nonce, data, nil)
if err != nil {
return nil, fmt.Errorf("cannot open AES-GCM: %s", err)
}
return plainText, nil
case MethodAES128CBC, MethodAES256CBC:
nonce, data := data[:k.BlockSize()], data[k.BlockSize():]
c := cipher.NewCBCDecrypter(k, nonce)
c.CryptBlocks(data, data)
// Remove zero bytes
data = bytes.TrimRight(data, "\x00")
// Calculate index to remove based on padding
padLength := data[len(data)-1]
lastGoodIndex := len(data) - int(padLength)
return data[:lastGoodIndex], nil
default:
return nil, fmt.Errorf("unknown symmetric encryption method %#v", ea.EncryptionMethod.Algorithm)
}
}
// Decrypt decrypts and unmarshals the EncryptedAssertion.
func (ea *EncryptedAssertion) Decrypt(cert *tls.Certificate) (*Assertion, error) {
plaintext, err := ea.DecryptBytes(cert)
if err != nil {
return nil, fmt.Errorf("Error decrypting assertion: %v", err)
}
assertion := &Assertion{}
err = xml.Unmarshal(plaintext, assertion)
if err != nil {
return nil, fmt.Errorf("Error unmarshaling assertion: %v", err)
}
return assertion, nil
}

140
vendor/github.com/mattermost/gosaml2/types/encrypted_key.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,140 @@
package types
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"crypto/tls"
"encoding/base64"
"encoding/hex"
"fmt"
"hash"
"strings"
)
//EncryptedKey contains the decryption key data from the saml2 core and xmlenc
//standards.
type EncryptedKey struct {
// EncryptionMethod string `xml:"EncryptionMethod>Algorithm"`
X509Data string `xml:"KeyInfo>X509Data>X509Certificate"`
CipherValue string `xml:"CipherData>CipherValue"`
EncryptionMethod EncryptionMethod
}
//EncryptionMethod specifies the type of encryption that was used.
type EncryptionMethod struct {
Algorithm string `xml:",attr,omitempty"`
DigestMethod DigestMethod `xml:",omitempty"`
}
//DigestMethod is a digest type specification
type DigestMethod struct {
Algorithm string `xml:",attr,omitempty"`
}
//Well-known public-key encryption methods
const (
MethodRSAOAEP = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"
MethodRSAOAEP2 = "http://www.w3.org/2009/xmlenc11#rsa-oaep"
)
//Well-known private key encryption methods
const (
MethodAES128GCM = "http://www.w3.org/2009/xmlenc11#aes128-gcm"
MethodAES128CBC = "http://www.w3.org/2001/04/xmlenc#aes128-cbc"
MethodAES256CBC = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
)
//Well-known hash methods
const (
MethodSHA1 = "http://www.w3.org/2000/09/xmldsig#sha1"
MethodSHA256 = "http://www.w3.org/2000/09/xmldsig#sha256"
MethodSHA512 = "http://www.w3.org/2000/09/xmldsig#sha512"
)
//SHA-1 is commonly used for certificate fingerprints (openssl -fingerprint and ADFS thumbprint).
//SHA-1 is sufficient for our purposes here (error message).
func debugKeyFp(keyBytes []byte) string {
if len(keyBytes) < 1 {
return ""
}
hashFunc := sha1.New()
hashFunc.Write(keyBytes)
sum := strings.ToLower(hex.EncodeToString(hashFunc.Sum(nil)))
var ret string
for idx := 0; idx+1 < len(sum); idx += 2 {
if idx == 0 {
ret += sum[idx : idx+2]
} else {
ret += ":" + sum[idx:idx+2]
}
}
return ret
}
//DecryptSymmetricKey returns the private key contained in the EncryptedKey document
func (ek *EncryptedKey) DecryptSymmetricKey(cert *tls.Certificate) (cipher.Block, error) {
if len(cert.Certificate) < 1 {
return nil, fmt.Errorf("decryption tls.Certificate has no public certs attached")
}
// The EncryptedKey may or may not include X509Data (certificate).
// If included, the EncryptedKey certificate:
// - is FYI only (fail if it does not match the SP certificate)
// - is NOT used to decrypt CipherData
if ek.X509Data != "" {
if encCert, err := base64.StdEncoding.DecodeString(ek.X509Data); err != nil {
return nil, fmt.Errorf("error decoding EncryptedKey certificate: %v", err)
} else if !bytes.Equal(cert.Certificate[0], encCert) {
return nil, fmt.Errorf("key decryption attempted with mismatched cert, SP cert(%.11s), assertion cert(%.11s)",
debugKeyFp(cert.Certificate[0]), debugKeyFp(encCert))
}
}
cipherText, err := base64.StdEncoding.DecodeString(ek.CipherValue)
if err != nil {
return nil, err
}
switch pk := cert.PrivateKey.(type) {
case *rsa.PrivateKey:
var h hash.Hash
switch ek.EncryptionMethod.DigestMethod.Algorithm {
case "", MethodSHA1:
h = sha1.New() // default
case MethodSHA256:
h = sha256.New()
case MethodSHA512:
h = sha512.New()
default:
return nil, fmt.Errorf("unsupported digest algorithm: %v",
ek.EncryptionMethod.DigestMethod.Algorithm)
}
switch ek.EncryptionMethod.Algorithm {
case "":
return nil, fmt.Errorf("missing encryption algorithm")
case MethodRSAOAEP, MethodRSAOAEP2:
pt, err := rsa.DecryptOAEP(h, rand.Reader, pk, cipherText, nil)
if err != nil {
return nil, fmt.Errorf("rsa internal error: %v", err)
}
b, err := aes.NewCipher(pt)
if err != nil {
return nil, err
}
return b, nil
default:
return nil, fmt.Errorf("unsupported encryption algorithm: %s", ek.EncryptionMethod.Algorithm)
}
}
return nil, fmt.Errorf("no cipher for decoding symmetric key")
}

67
vendor/github.com/mattermost/gosaml2/types/metadata.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,67 @@
package types
import (
"encoding/xml"
"time"
dsigtypes "github.com/russellhaering/goxmldsig/types"
)
type EntityDescriptor struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntityDescriptor"`
ValidUntil time.Time `xml:"validUntil,attr"`
// SAML 2.0 8.3.6 Entity Identifier could be used to represent issuer
EntityID string `xml:"entityID,attr"`
SPSSODescriptor *SPSSODescriptor `xml:"SPSSODescriptor,omitempty"`
IDPSSODescriptor *IDPSSODescriptor `xml:"IDPSSODescriptor,omitempty"`
}
type Endpoint struct {
Binding string `xml:"Binding,attr"`
Location string `xml:"Location,attr"`
ResponseLocation string `xml:"ResponseLocation,attr,omitempty"`
}
type IndexedEndpoint struct {
Binding string `xml:"Binding,attr"`
Location string `xml:"Location,attr"`
Index int `xml:"index,attr"`
}
type SPSSODescriptor struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata SPSSODescriptor"`
AuthnRequestsSigned bool `xml:"AuthnRequestsSigned,attr"`
WantAssertionsSigned bool `xml:"WantAssertionsSigned,attr"`
ProtocolSupportEnumeration string `xml:"protocolSupportEnumeration,attr"`
KeyDescriptors []KeyDescriptor `xml:"KeyDescriptor"`
SingleLogoutServices []Endpoint `xml:"SingleLogoutService"`
NameIDFormats []string `xml:"NameIDFormat"`
AssertionConsumerServices []IndexedEndpoint `xml:"AssertionConsumerService"`
}
type IDPSSODescriptor struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata IDPSSODescriptor"`
WantAuthnRequestsSigned bool `xml:"WantAuthnRequestsSigned,attr"`
KeyDescriptors []KeyDescriptor `xml:"KeyDescriptor"`
NameIDFormats []NameIDFormat `xml:"NameIDFormat"`
SingleSignOnServices []SingleSignOnService `xml:"SingleSignOnService"`
Attributes []Attribute `xml:"Attribute"`
}
type KeyDescriptor struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata KeyDescriptor"`
Use string `xml:"use,attr"`
KeyInfo dsigtypes.KeyInfo `xml:"KeyInfo"`
EncryptionMethods []EncryptionMethod `xml:"EncryptionMethod"`
}
type NameIDFormat struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata NameIDFormat"`
Value string `xml:",chardata"`
}
type SingleSignOnService struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata SingleSignOnService"`
Binding string `xml:"Binding,attr"`
Location string `xml:"Location,attr"`
}

156
vendor/github.com/mattermost/gosaml2/types/response.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,156 @@
package types
import (
"encoding/xml"
"time"
)
// UnverifiedBaseResponse extracts several basic attributes of a SAML Response
// which may be useful in deciding how to validate the Response. An UnverifiedBaseResponse
// is parsed by this library prior to any validation of the Response, so the
// values it contains may have been supplied by an attacker and should not be
// trusted as authoritative from the IdP.
type UnverifiedBaseResponse struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol Response"`
ID string `xml:"ID,attr"`
InResponseTo string `xml:"InResponseTo,attr"`
Destination string `xml:"Destination,attr"`
Version string `xml:"Version,attr"`
Issuer *Issuer `xml:"Issuer"`
}
type Response struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol Response"`
ID string `xml:"ID,attr"`
InResponseTo string `xml:"InResponseTo,attr"`
Destination string `xml:"Destination,attr"`
Version string `xml:"Version,attr"`
IssueInstant time.Time `xml:"IssueInstant,attr"`
Status *Status `xml:"Status"`
Issuer *Issuer `xml:"Issuer"`
Assertions []Assertion `xml:"Assertion"`
EncryptedAssertions []EncryptedAssertion `xml:"EncryptedAssertion"`
SignatureValidated bool `xml:"-"` // not read, not dumped
}
type Status struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"`
StatusCode *StatusCode `xml:"StatusCode"`
}
type StatusCode struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol StatusCode"`
Value string `xml:"Value,attr"`
}
type Issuer struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
Value string `xml:",chardata"`
}
type Signature struct {
SignatureDocument []byte `xml:",innerxml"`
}
type Assertion struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Assertion"`
Version string `xml:"Version,attr"`
ID string `xml:"ID,attr"`
IssueInstant time.Time `xml:"IssueInstant,attr"`
Issuer *Issuer `xml:"Issuer"`
Signature *Signature `xml:"Signature"`
Subject *Subject `xml:"Subject"`
Conditions *Conditions `xml:"Conditions"`
AttributeStatement *AttributeStatement `xml:"AttributeStatement"`
AuthnStatement *AuthnStatement `xml:"AuthnStatement"`
SignatureValidated bool `xml:"-"` // not read, not dumped
}
type Subject struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Subject"`
NameID *NameID `xml:"NameID"`
SubjectConfirmation *SubjectConfirmation `xml:"SubjectConfirmation"`
}
type AuthnContext struct {
XMLName xml.Name `xml:urn:oasis:names:tc:SAML:2.0:assertion AuthnContext"`
AuthnContextClassRef *AuthnContextClassRef `xml:"AuthnContextClassRef"`
}
type AuthnContextClassRef struct {
XMLName xml.Name `xml:urn:oasis:names:tc:SAML:2.0:assertion AuthnContextClassRef"`
Value string `xml:",chardata"`
}
type NameID struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion NameID"`
Value string `xml:",chardata"`
}
type SubjectConfirmation struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion SubjectConfirmation"`
Method string `xml:"Method,attr"`
SubjectConfirmationData *SubjectConfirmationData `xml:"SubjectConfirmationData"`
}
type SubjectConfirmationData struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion SubjectConfirmationData"`
NotOnOrAfter string `xml:"NotOnOrAfter,attr"`
Recipient string `xml:"Recipient,attr"`
InResponseTo string `xml:"InResponseTo,attr"`
}
type Conditions struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Conditions"`
NotBefore string `xml:"NotBefore,attr"`
NotOnOrAfter string `xml:"NotOnOrAfter,attr"`
AudienceRestrictions []AudienceRestriction `xml:"AudienceRestriction"`
OneTimeUse *OneTimeUse `xml:"OneTimeUse"`
ProxyRestriction *ProxyRestriction `xml:"ProxyRestriction"`
}
type AudienceRestriction struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion AudienceRestriction"`
Audiences []Audience `xml:"Audience"`
}
type Audience struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Audience"`
Value string `xml:",chardata"`
}
type OneTimeUse struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion OneTimeUse"`
}
type ProxyRestriction struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion ProxyRestriction"`
Count int `xml:"Count,attr"`
Audience []Audience `xml:"Audience"`
}
type AttributeStatement struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion AttributeStatement"`
Attributes []Attribute `xml:"Attribute"`
}
type Attribute struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Attribute"`
FriendlyName string `xml:"FriendlyName,attr"`
Name string `xml:"Name,attr"`
NameFormat string `xml:"NameFormat,attr"`
Values []AttributeValue `xml:"AttributeValue"`
}
type AttributeValue struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion AttributeValue"`
Type string `xml:"xsi:type,attr"`
Value string `xml:",chardata"`
}
type AuthnStatement struct {
XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion AuthnStatement"`
AuthnInstant *time.Time `xml:"AuthnInstant,attr,omitempty"`
SessionNotOnOrAfter *time.Time `xml:"SessionNotOnOrAfter,attr,omitempty"`
AuthnContext *AuthnContext `xml:"AuthnContext"`
}

27
vendor/github.com/mattermost/gosaml2/uuid/uuid.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,27 @@
package uuid
// relevant bits from https://github.com/abneptis/GoUUID/blob/master/uuid.go
import (
"crypto/rand"
"fmt"
)
type UUID [16]byte
// NewV4 returns random generated UUID.
func NewV4() *UUID {
u := &UUID{}
_, err := rand.Read(u[:16])
if err != nil {
panic(err)
}
u[8] = (u[8] | 0x80) & 0xBf
u[6] = (u[6] | 0x40) & 0x4f
return u
}
func (u *UUID) String() string {
return fmt.Sprintf("%x-%x-%x-%x-%x", u[:4], u[4:6], u[6:8], u[8:10], u[10:])
}

231
vendor/github.com/mattermost/gosaml2/validate.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,231 @@
package saml2
import (
"fmt"
"time"
"github.com/mattermost/gosaml2/types"
)
//ErrParsing indicates that the value present in an assertion could not be
//parsed. It can be inspected for the specific tag name, the contents, and the
//intended type.
type ErrParsing struct {
Tag, Value, Type string
}
func (ep ErrParsing) Error() string {
return fmt.Sprintf("Error parsing %s tag value as type %s", ep.Tag, ep.Value)
}
//Oft-used messages
const (
ReasonUnsupported = "Unsupported"
ReasonExpired = "Expired"
)
//ErrInvalidValue indicates that the expected value did not match the received
//value.
type ErrInvalidValue struct {
Key, Expected, Actual string
Reason string
}
func (e ErrInvalidValue) Error() string {
if e.Reason == "" {
e.Reason = "Unrecognized"
}
return fmt.Sprintf("%s %s value, Expected: %s, Actual: %s", e.Reason, e.Key, e.Expected, e.Actual)
}
//Well-known methods of subject confirmation
const (
SubjMethodBearer = "urn:oasis:names:tc:SAML:2.0:cm:bearer"
)
//VerifyAssertionConditions inspects an assertion element and makes sure that
//all SAML2 contracts are upheld.
func (sp *SAMLServiceProvider) VerifyAssertionConditions(assertion *types.Assertion) (*WarningInfo, error) {
warningInfo := &WarningInfo{}
now := sp.Clock.Now()
conditions := assertion.Conditions
if conditions == nil {
return nil, ErrMissingElement{Tag: ConditionsTag}
}
if conditions.NotBefore == "" {
return nil, ErrMissingElement{Tag: ConditionsTag, Attribute: NotBeforeAttr}
}
notBefore, err := time.Parse(time.RFC3339, conditions.NotBefore)
if err != nil {
return nil, ErrParsing{Tag: NotBeforeAttr, Value: conditions.NotBefore, Type: "time.RFC3339"}
}
if now.Before(notBefore) {
warningInfo.InvalidTime = true
}
if conditions.NotOnOrAfter == "" {
return nil, ErrMissingElement{Tag: ConditionsTag, Attribute: NotOnOrAfterAttr}
}
notOnOrAfter, err := time.Parse(time.RFC3339, conditions.NotOnOrAfter)
if err != nil {
return nil, ErrParsing{Tag: NotOnOrAfterAttr, Value: conditions.NotOnOrAfter, Type: "time.RFC3339"}
}
if now.After(notOnOrAfter) {
warningInfo.InvalidTime = true
}
for _, audienceRestriction := range conditions.AudienceRestrictions {
matched := false
for _, audience := range audienceRestriction.Audiences {
if audience.Value == sp.AudienceURI {
matched = true
break
}
}
if !matched {
warningInfo.NotInAudience = true
break
}
}
if conditions.OneTimeUse != nil {
warningInfo.OneTimeUse = true
}
proxyRestriction := conditions.ProxyRestriction
if proxyRestriction != nil {
proxyRestrictionInfo := &ProxyRestriction{
Count: proxyRestriction.Count,
Audience: []string{},
}
for _, audience := range proxyRestriction.Audience {
proxyRestrictionInfo.Audience = append(proxyRestrictionInfo.Audience, audience.Value)
}
warningInfo.ProxyRestriction = proxyRestrictionInfo
}
return warningInfo, nil
}
//Validate ensures that the assertion passed is valid for the current Service
//Provider.
func (sp *SAMLServiceProvider) Validate(response *types.Response) error {
err := sp.validateResponseAttributes(response)
if err != nil {
return err
}
if len(response.Assertions) == 0 {
return ErrMissingAssertion
}
issuer := response.Issuer
if issuer == nil {
// FIXME?: SAML Core 2.0 Section 3.2.2 has Response.Issuer as [Optional]
return ErrMissingElement{Tag: IssuerTag}
}
if sp.IdentityProviderIssuer != "" && response.Issuer.Value != sp.IdentityProviderIssuer {
return ErrInvalidValue{
Key: IssuerTag,
Expected: sp.IdentityProviderIssuer,
Actual: response.Issuer.Value,
}
}
status := response.Status
if status == nil {
return ErrMissingElement{Tag: StatusTag}
}
statusCode := status.StatusCode
if statusCode == nil {
return ErrMissingElement{Tag: StatusCodeTag}
}
if statusCode.Value != StatusCodeSuccess {
return ErrInvalidValue{
Key: StatusCodeTag,
Expected: StatusCodeSuccess,
Actual: statusCode.Value,
}
}
for _, assertion := range response.Assertions {
issuer = assertion.Issuer
if issuer == nil {
return ErrMissingElement{Tag: IssuerTag}
}
if sp.IdentityProviderIssuer != "" && assertion.Issuer.Value != sp.IdentityProviderIssuer {
return ErrInvalidValue{
Key: IssuerTag,
Expected: sp.IdentityProviderIssuer,
Actual: issuer.Value,
}
}
subject := assertion.Subject
if subject == nil {
return ErrMissingElement{Tag: SubjectTag}
}
subjectConfirmation := subject.SubjectConfirmation
if subjectConfirmation == nil {
return ErrMissingElement{Tag: SubjectConfirmationTag}
}
if subjectConfirmation.Method != SubjMethodBearer {
return ErrInvalidValue{
Reason: ReasonUnsupported,
Key: SubjectConfirmationTag,
Expected: SubjMethodBearer,
Actual: subjectConfirmation.Method,
}
}
subjectConfirmationData := subjectConfirmation.SubjectConfirmationData
if subjectConfirmationData == nil {
return ErrMissingElement{Tag: SubjectConfirmationDataTag}
}
if subjectConfirmationData.Recipient != sp.AssertionConsumerServiceURL {
return ErrInvalidValue{
Key: RecipientAttr,
Expected: sp.AssertionConsumerServiceURL,
Actual: subjectConfirmationData.Recipient,
}
}
if subjectConfirmationData.NotOnOrAfter == "" {
return ErrMissingElement{Tag: SubjectConfirmationDataTag, Attribute: NotOnOrAfterAttr}
}
notOnOrAfter, err := time.Parse(time.RFC3339, subjectConfirmationData.NotOnOrAfter)
if err != nil {
return ErrParsing{Tag: NotOnOrAfterAttr, Value: subjectConfirmationData.NotOnOrAfter, Type: "time.RFC3339"}
}
now := sp.Clock.Now()
if now.After(notOnOrAfter) {
return ErrInvalidValue{
Reason: ReasonExpired,
Key: NotOnOrAfterAttr,
Expected: now.Format(time.RFC3339),
Actual: subjectConfirmationData.NotOnOrAfter,
}
}
}
return nil
}

58
vendor/github.com/mattermost/gosaml2/xml_constants.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,58 @@
package saml2
const (
ResponseTag = "Response"
AssertionTag = "Assertion"
EncryptedAssertionTag = "EncryptedAssertion"
SubjectTag = "Subject"
NameIdTag = "NameID"
SubjectConfirmationTag = "SubjectConfirmation"
SubjectConfirmationDataTag = "SubjectConfirmationData"
AttributeStatementTag = "AttributeStatement"
AttributeValueTag = "AttributeValue"
ConditionsTag = "Conditions"
AudienceRestrictionTag = "AudienceRestriction"
AudienceTag = "Audience"
OneTimeUseTag = "OneTimeUse"
ProxyRestrictionTag = "ProxyRestriction"
IssuerTag = "Issuer"
StatusTag = "Status"
StatusCodeTag = "StatusCode"
)
const (
DestinationAttr = "Destination"
VersionAttr = "Version"
IdAttr = "ID"
MethodAttr = "Method"
RecipientAttr = "Recipient"
NameAttr = "Name"
NotBeforeAttr = "NotBefore"
NotOnOrAfterAttr = "NotOnOrAfter"
CountAttr = "Count"
)
const (
NameIdFormatPersistent = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
NameIdFormatTransient = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
NameIdFormatEmailAddress = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
NameIdFormatUnspecified = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
NameIdFormatX509SubjectName = "urn:oasis:names:tc:SAML:1.1:nameid-format:x509SubjectName"
AuthnContextPasswordProtectedTransport = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
AuthnPolicyMatchExact = "exact"
AuthnPolicyMatchMinimum = "minimum"
AuthnPolicyMatchMaximum = "maximum"
AuthnPolicyMatchBetter = "better"
StatusCodeSuccess = "urn:oasis:names:tc:SAML:2.0:status:Success"
BindingHttpPost = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
BindingHttpRedirect = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
)
const (
SAMLAssertionNamespace = "urn:oasis:names:tc:SAML:2.0:assertion"
SAMLProtocolNamespace = "urn:oasis:names:tc:SAML:2.0:protocol"
)

1
vendor/github.com/russellhaering/goxmldsig/.gitignore сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1 @@
*.test

9
vendor/github.com/russellhaering/goxmldsig/.travis.yml сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,9 @@
language: go
go:
- "1.6.x"
- "1.7.x"
- "1.8.x"
- "1.9.x"
- "1.10.x"
- master

175
vendor/github.com/russellhaering/goxmldsig/LICENSE сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,175 @@
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.

90
vendor/github.com/russellhaering/goxmldsig/README.md сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,90 @@
# goxmldsig
[![Build Status](https://travis-ci.org/russellhaering/goxmldsig.svg?branch=master)](https://travis-ci.org/russellhaering/goxmldsig)
[![GoDoc](https://godoc.org/github.com/russellhaering/goxmldsig?status.svg)](https://godoc.org/github.com/russellhaering/goxmldsig)
XML Digital Signatures implemented in pure Go.
## Installation
Install `goxmldsig` into your `$GOPATH` using `go get`:
```
$ go get github.com/russellhaering/goxmldsig
```
## Usage
### Signing
```go
package main
import (
"github.com/beevik/etree"
"github.com/russellhaering/goxmldsig"
)
func main() {
// Generate a key and self-signed certificate for signing
randomKeyStore := dsig.RandomKeyStoreForTest()
ctx := dsig.NewDefaultSigningContext(randomKeyStore)
elementToSign := &etree.Element{
Tag: "ExampleElement",
}
elementToSign.CreateAttr("ID", "id1234")
// Sign the element
signedElement, err := ctx.SignEnveloped(elementToSign)
if err != nil {
panic(err)
}
// Serialize the signed element. It is important not to modify the element
// after it has been signed - even pretty-printing the XML will invalidate
// the signature.
doc := etree.NewDocument()
doc.SetRoot(signedElement)
str, err := doc.WriteToString()
if err != nil {
panic(err)
}
println(str)
}
```
### Signature Validation
```go
// Validate an element against a root certificate
func validate(root *x509.Certificate, el *etree.Element) {
// Construct a signing context with one or more roots of trust.
ctx := dsig.NewDefaultValidationContext(&dsig.MemoryX509CertificateStore{
Roots: []*x509.Certificate{root},
})
// It is important to only use the returned validated element.
// See: https://www.w3.org/TR/xmldsig-bestpractices/#check-what-is-signed
validated, err := ctx.Validate(el)
if err != nil {
panic(err)
}
doc := etree.NewDocument()
doc.SetRoot(validated)
str, err := doc.WriteToString()
if err != nil {
panic(err)
}
println(str)
}
```
## Limitations
This library was created in order to [implement SAML 2.0](https://github.com/russellhaering/gosaml2)
without needing to execute a command line tool to create and validate signatures. It currently
only implements the subset of relevant standards needed to support that implementation, but
I hope to make it more complete over time. Contributions are welcome.

162
vendor/github.com/russellhaering/goxmldsig/canonicalize.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,162 @@
package dsig
import (
"sort"
"github.com/beevik/etree"
"github.com/russellhaering/goxmldsig/etreeutils"
)
// Canonicalizer is an implementation of a canonicalization algorithm.
type Canonicalizer interface {
Canonicalize(el *etree.Element) ([]byte, error)
Algorithm() AlgorithmID
}
type c14N10ExclusiveCanonicalizer struct {
prefixList string
}
// MakeC14N10ExclusiveCanonicalizerWithPrefixList constructs an exclusive Canonicalizer
// from a PrefixList in NMTOKENS format (a white space separated list).
func MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList string) Canonicalizer {
return &c14N10ExclusiveCanonicalizer{
prefixList: prefixList,
}
}
// Canonicalize transforms the input Element into a serialized XML document in canonical form.
func (c *c14N10ExclusiveCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
err := etreeutils.TransformExcC14n(el, c.prefixList)
if err != nil {
return nil, err
}
return canonicalSerialize(el)
}
func (c *c14N10ExclusiveCanonicalizer) Algorithm() AlgorithmID {
return CanonicalXML10ExclusiveAlgorithmId
}
type c14N11Canonicalizer struct{}
// MakeC14N11Canonicalizer constructs an inclusive canonicalizer.
func MakeC14N11Canonicalizer() Canonicalizer {
return &c14N11Canonicalizer{}
}
// Canonicalize transforms the input Element into a serialized XML document in canonical form.
func (c *c14N11Canonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
scope := make(map[string]struct{})
return canonicalSerialize(canonicalPrep(el, scope))
}
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
}
return key
}
type c14nSpace struct {
a etree.Attr
used bool
}
const nsSpace = "xmlns"
// canonicalPrep accepts an *etree.Element and transforms it into one which is ready
// for serialization into inclusive canonical form. Specifically this
// entails:
//
// 1. Stripping re-declarations of namespaces
// 2. Sorting attributes into canonical order
//
// Inclusive canonicalization does not strip unused namespaces.
//
// TODO(russell_h): This is very similar to excCanonicalPrep - perhaps they should
// be unified into one parameterized function?
func canonicalPrep(el *etree.Element, seenSoFar map[string]struct{}) *etree.Element {
_seenSoFar := make(map[string]struct{})
for k, v := range seenSoFar {
_seenSoFar[k] = v
}
ne := el.Copy()
sort.Sort(etreeutils.SortedAttrs(ne.Attr))
if len(ne.Attr) != 0 {
for _, attr := range ne.Attr {
if attr.Space != nsSpace {
continue
}
key := attr.Space + ":" + attr.Key
if _, seen := _seenSoFar[key]; seen {
ne.RemoveAttr(attr.Space + ":" + attr.Key)
} else {
_seenSoFar[key] = struct{}{}
}
}
}
for i, token := range ne.Child {
childElement, ok := token.(*etree.Element)
if ok {
ne.Child[i] = canonicalPrep(childElement, _seenSoFar)
}
}
return ne
}
func canonicalSerialize(el *etree.Element) ([]byte, error) {
doc := etree.NewDocument()
doc.SetRoot(el.Copy())
doc.WriteSettings = etree.WriteSettings{
CanonicalAttrVal: true,
CanonicalEndTags: true,
CanonicalText: true,
}
return doc.WriteToBytes()
}

55
vendor/github.com/russellhaering/goxmldsig/clock.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,55 @@
package dsig
import (
"time"
"github.com/jonboulle/clockwork"
)
// Clock wraps a clockwork.Clock (which could be real or fake) in order
// to default to a real clock when a nil *Clock is used. In other words,
// if you attempt to use a nil *Clock it will defer to the real system
// clock. This allows Clock to be easily added to structs with methods
// that currently reference the time package, without requiring every
// instantiation of that struct to be updated.
type Clock struct {
wrapped clockwork.Clock
}
func (c *Clock) getWrapped() clockwork.Clock {
if c == nil {
return clockwork.NewRealClock()
}
return c.wrapped
}
func (c *Clock) After(d time.Duration) <-chan time.Time {
return c.getWrapped().After(d)
}
func (c *Clock) Sleep(d time.Duration) {
c.getWrapped().Sleep(d)
}
func (c *Clock) Now() time.Time {
return c.getWrapped().Now()
}
func NewRealClock() *Clock {
return &Clock{
wrapped: clockwork.NewRealClock(),
}
}
func NewFakeClock(wrapped clockwork.Clock) *Clock {
return &Clock{
wrapped: wrapped,
}
}
func NewFakeClockAt(t time.Time) *Clock {
return &Clock{
wrapped: clockwork.NewFakeClockAt(t),
}
}

98
vendor/github.com/russellhaering/goxmldsig/etreeutils/canonicalize.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,98 @@
package etreeutils
import (
"sort"
"strings"
"github.com/beevik/etree"
)
// TransformExcC14n transforms the passed element into xml-exc-c14n form.
func TransformExcC14n(el *etree.Element, inclusiveNamespacesPrefixList string) error {
prefixes := strings.Fields(inclusiveNamespacesPrefixList)
prefixSet := make(map[string]struct{}, len(prefixes))
for _, prefix := range prefixes {
prefixSet[prefix] = struct{}{}
}
err := transformExcC14n(DefaultNSContext, DefaultNSContext, el, prefixSet)
if err != nil {
return err
}
return nil
}
func transformExcC14n(ctx, declared NSContext, el *etree.Element, inclusiveNamespaces map[string]struct{}) error {
scope, err := ctx.SubContext(el)
if err != nil {
return err
}
visiblyUtilizedPrefixes := map[string]struct{}{
el.Space: struct{}{},
}
filteredAttrs := []etree.Attr{}
// Filter out all namespace declarations
for _, attr := range el.Attr {
switch {
case attr.Space == xmlnsPrefix:
if _, ok := inclusiveNamespaces[attr.Key]; ok {
visiblyUtilizedPrefixes[attr.Key] = struct{}{}
}
case attr.Space == defaultPrefix && attr.Key == xmlnsPrefix:
if _, ok := inclusiveNamespaces[defaultPrefix]; ok {
visiblyUtilizedPrefixes[defaultPrefix] = struct{}{}
}
default:
if attr.Space != defaultPrefix {
visiblyUtilizedPrefixes[attr.Space] = struct{}{}
}
filteredAttrs = append(filteredAttrs, attr)
}
}
el.Attr = filteredAttrs
declared = declared.Copy()
// Declare all visibly utilized prefixes that are in-scope but haven't
// been declared in the canonicalized form yet. These might have been
// declared on this element but then filtered out above, or they might
// have been declared on an ancestor (before canonicalization) which
// didn't visibly utilize and thus had them removed.
for prefix := range visiblyUtilizedPrefixes {
// Skip redundant declarations - they have to already have the same
// value.
if declaredNamespace, ok := declared.prefixes[prefix]; ok {
if value, ok := scope.prefixes[prefix]; ok && declaredNamespace == value {
continue
}
}
namespace, err := scope.LookupPrefix(prefix)
if err != nil {
return err
}
el.Attr = append(el.Attr, declared.declare(prefix, namespace))
}
sort.Sort(SortedAttrs(el.Attr))
// Transform child elements
for _, child := range el.ChildElements() {
err := transformExcC14n(scope, declared, child, inclusiveNamespaces)
if err != nil {
return err
}
}
return nil
}

407
vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,407 @@
package etreeutils
import (
"errors"
"fmt"
"sort"
"github.com/beevik/etree"
)
const (
defaultPrefix = ""
xmlnsPrefix = "xmlns"
xmlPrefix = "xml"
XMLNamespace = "http://www.w3.org/XML/1998/namespace"
XMLNSNamespace = "http://www.w3.org/2000/xmlns/"
)
var (
DefaultNSContext = NSContext{
prefixes: map[string]string{
defaultPrefix: XMLNamespace,
xmlPrefix: XMLNamespace,
xmlnsPrefix: XMLNSNamespace,
},
}
EmptyNSContext = NSContext{}
ErrReservedNamespace = errors.New("disallowed declaration of reserved namespace")
ErrInvalidDefaultNamespace = errors.New("invalid default namespace declaration")
ErrTraversalHalted = errors.New("traversal halted")
)
type ErrUndeclaredNSPrefix struct {
Prefix string
}
func (e ErrUndeclaredNSPrefix) Error() string {
return fmt.Sprintf("undeclared namespace prefix: '%s'", e.Prefix)
}
type NSContext struct {
prefixes map[string]string
}
func (ctx NSContext) Copy() NSContext {
prefixes := make(map[string]string, len(ctx.prefixes)+4)
for k, v := range ctx.prefixes {
prefixes[k] = v
}
return NSContext{prefixes: prefixes}
}
func (ctx NSContext) declare(prefix, namespace string) etree.Attr {
ctx.prefixes[prefix] = namespace
switch prefix {
case defaultPrefix:
return etree.Attr{
Key: xmlnsPrefix,
Value: namespace,
}
default:
return etree.Attr{
Space: xmlnsPrefix,
Key: prefix,
Value: namespace,
}
}
}
func (ctx NSContext) SubContext(el *etree.Element) (NSContext, error) {
// The subcontext should inherit existing declared prefixes
newCtx := ctx.Copy()
// Merge new namespace declarations on top of existing ones.
for _, attr := range el.Attr {
if attr.Space == xmlnsPrefix {
// This attribute is a namespace declaration of the form "xmlns:<prefix>"
// The 'xml' namespace may only be re-declared with the name 'http://www.w3.org/XML/1998/namespace'
if attr.Key == xmlPrefix && attr.Value != XMLNamespace {
return ctx, ErrReservedNamespace
}
// The 'xmlns' namespace may not be re-declared
if attr.Key == xmlnsPrefix {
return ctx, ErrReservedNamespace
}
newCtx.declare(attr.Key, attr.Value)
} else if attr.Space == defaultPrefix && attr.Key == xmlnsPrefix {
// This attribute is a default namespace declaration
// The xmlns namespace value may not be declared as the default namespace
if attr.Value == XMLNSNamespace {
return ctx, ErrInvalidDefaultNamespace
}
newCtx.declare(defaultPrefix, attr.Value)
}
}
return newCtx, nil
}
// Prefixes returns a copy of this context's prefix map.
func (ctx NSContext) Prefixes() map[string]string {
prefixes := make(map[string]string, len(ctx.prefixes))
for k, v := range ctx.prefixes {
prefixes[k] = v
}
return prefixes
}
// LookupPrefix attempts to find a declared namespace for the specified prefix. If the prefix
// is an empty string this will be the default namespace for this context. If the prefix is
// undeclared in this context an ErrUndeclaredNSPrefix will be returned.
func (ctx NSContext) LookupPrefix(prefix string) (string, error) {
if namespace, ok := ctx.prefixes[prefix]; ok {
return namespace, nil
}
return "", ErrUndeclaredNSPrefix{
Prefix: prefix,
}
}
// NSIterHandler is a function which is invoked with a element and its surrounding
// NSContext during traversals.
type NSIterHandler func(NSContext, *etree.Element) error
// NSTraverse traverses an element tree, invoking the passed handler for each element
// in the tree.
func NSTraverse(ctx NSContext, el *etree.Element, handle NSIterHandler) error {
ctx, err := ctx.SubContext(el)
if err != nil {
return err
}
err = handle(ctx, el)
if err != nil {
return err
}
// Recursively traverse child elements.
for _, child := range el.ChildElements() {
err := NSTraverse(ctx, child, handle)
if err != nil {
return err
}
}
return nil
}
// NSDetatch makes a copy of the passed element, and declares any namespaces in
// the passed context onto the new element before returning it.
func NSDetatch(ctx NSContext, el *etree.Element) (*etree.Element, error) {
ctx, err := ctx.SubContext(el)
if err != nil {
return nil, err
}
el = el.Copy()
// Build a new attribute list
attrs := make([]etree.Attr, 0, len(el.Attr))
// First copy over anything that isn't a namespace declaration
for _, attr := range el.Attr {
if attr.Space == xmlnsPrefix {
continue
}
if attr.Space == defaultPrefix && attr.Key == xmlnsPrefix {
continue
}
attrs = append(attrs, attr)
}
// Append all in-context namespace declarations
for prefix, namespace := range ctx.prefixes {
// Skip the implicit "xml" and "xmlns" prefix declarations
if prefix == xmlnsPrefix || prefix == xmlPrefix {
continue
}
// Also skip declararing the default namespace as XMLNamespace
if prefix == defaultPrefix && namespace == XMLNamespace {
continue
}
if prefix != defaultPrefix {
attrs = append(attrs, etree.Attr{
Space: xmlnsPrefix,
Key: prefix,
Value: namespace,
})
} else {
attrs = append(attrs, etree.Attr{
Key: xmlnsPrefix,
Value: namespace,
})
}
}
sort.Sort(SortedAttrs(attrs))
el.Attr = attrs
return el, nil
}
// NSSelectOne behaves identically to NSSelectOneCtx, but uses DefaultNSContext as the
// surrounding context.
func NSSelectOne(el *etree.Element, namespace, tag string) (*etree.Element, error) {
return NSSelectOneCtx(DefaultNSContext, el, namespace, tag)
}
// NSSelectOneCtx conducts a depth-first search for an element with the specified namespace
// and tag. If such an element is found, a new *etree.Element is returned which is a
// copy of the found element, but with all in-context namespace declarations attached
// to the element as attributes.
func NSSelectOneCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*etree.Element, error) {
var found *etree.Element
err := NSFindIterateCtx(ctx, el, namespace, tag, func(ctx NSContext, el *etree.Element) error {
var err error
found, err = NSDetatch(ctx, el)
if err != nil {
return err
}
return ErrTraversalHalted
})
if err != nil {
return nil, err
}
return found, nil
}
// NSFindIterate behaves identically to NSFindIterateCtx, but uses DefaultNSContext
// as the surrounding context.
func NSFindIterate(el *etree.Element, namespace, tag string, handle NSIterHandler) error {
return NSFindIterateCtx(DefaultNSContext, el, namespace, tag, handle)
}
// NSFindIterateCtx conducts a depth-first traversal searching for elements with the
// specified tag in the specified namespace. It uses the passed NSContext for prefix
// lookups. For each such element, the passed handler function is invoked. If the
// handler function returns an error traversal is immediately halted. If the error
// returned by the handler is ErrTraversalHalted then nil will be returned by
// NSFindIterate. If any other error is returned by the handler, that error will be
// 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 {
_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
}
// NSFindOne behaves identically to NSFindOneCtx, but uses DefaultNSContext for
// context.
func NSFindOne(el *etree.Element, namespace, tag string) (*etree.Element, error) {
return NSFindOneCtx(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 NSFindOneCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*etree.Element, error) {
var found *etree.Element
err := NSFindIterateCtx(ctx, el, namespace, tag, func(ctx NSContext, el *etree.Element) error {
found = el
return ErrTraversalHalted
})
if err != nil {
return nil, err
}
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.
func NSBuildParentContext(el *etree.Element) (NSContext, error) {
parent := el.Parent()
if parent == nil {
return DefaultNSContext, nil
}
ctx, err := NSBuildParentContext(parent)
if err != nil {
return ctx, err
}
return ctx.SubContext(parent)
}

66
vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,66 @@
package etreeutils
import "github.com/beevik/etree"
// SortedAttrs provides sorting capabilities, compatible with XML C14N, on top
// of an []etree.Attr
type SortedAttrs []etree.Attr
func (a SortedAttrs) Len() int {
return len(a)
}
func (a SortedAttrs) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
func (a SortedAttrs) Less(i, j int) bool {
// This is the best reference I've found on sort order:
// http://dst.lbl.gov/~ksb/Scratch/XMLC14N.html
// If attr j is a default namespace declaration, attr i may
// not be strictly "less" than it.
if a[j].Space == defaultPrefix && a[j].Key == xmlnsPrefix {
return false
}
// Otherwise, if attr i is a default namespace declaration, it
// must be less than anything else.
if a[i].Space == defaultPrefix && a[i].Key == xmlnsPrefix {
return true
}
// Next, namespace prefix declarations, sorted by prefix, come before
// anythign else.
if a[i].Space == xmlnsPrefix {
if a[j].Space == xmlnsPrefix {
return a[i].Key < a[j].Key
}
return true
}
if a[j].Space == xmlnsPrefix {
return false
}
// Then come unprefixed attributes, sorted by key.
if a[i].Space == defaultPrefix {
if a[j].Space == defaultPrefix {
return a[i].Key < a[j].Key
}
return true
}
if a[j].Space == defaultPrefix {
return false
}
// Wow. We're still going. Finally, attributes in the same namespace should be
// sorted by key. Attributes in different namespaces should be sorted by the
// actual namespace (_not_ the prefix). For now just use the prefix.
if a[i].Space == a[j].Space {
return a[i].Key < a[j].Key
}
return a[i].Space < a[j].Space
}

43
vendor/github.com/russellhaering/goxmldsig/etreeutils/unmarshal.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,43 @@
package etreeutils
import (
"encoding/xml"
"github.com/beevik/etree"
)
// NSUnmarshalElement unmarshals the passed etree Element into the value pointed to by
// v using encoding/xml in the context of the passed NSContext. If v implements
// ElementKeeper, SetUnderlyingElement will be called on v with a reference to el.
func NSUnmarshalElement(ctx NSContext, el *etree.Element, v interface{}) error {
detatched, err := NSDetatch(ctx, el)
if err != nil {
return err
}
doc := etree.NewDocument()
doc.AddChild(detatched)
data, err := doc.WriteToBytes()
if err != nil {
return err
}
err = xml.Unmarshal(data, v)
if err != nil {
return err
}
switch v := v.(type) {
case ElementKeeper:
v.SetUnderlyingElement(el)
}
return nil
}
// ElementKeeper should be implemented by types which will be passed to
// UnmarshalElement, but wish to keep a reference
type ElementKeeper interface {
SetUnderlyingElement(*etree.Element)
UnderlyingElement() *etree.Element
}

67
vendor/github.com/russellhaering/goxmldsig/keystore.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,67 @@
package dsig
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"math/big"
"time"
)
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)
}
type MemoryX509CertificateStore struct {
Roots []*x509.Certificate
}
func (mX509cs *MemoryX509CertificateStore) Certificates() ([]*x509.Certificate, error) {
return mX509cs.Roots, nil
}
type MemoryX509KeyStore struct {
privateKey *rsa.PrivateKey
cert []byte
}
func (ks *MemoryX509KeyStore) GetKeyPair() (*rsa.PrivateKey, []byte, error) {
return ks.privateKey, ks.cert, nil
}
func RandomKeyStoreForTest() X509KeyStore {
key, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
panic(err)
}
now := time.Now()
template := &x509.Certificate{
SerialNumber: big.NewInt(0),
NotBefore: now.Add(-5 * time.Minute),
NotAfter: now.Add(365 * 24 * time.Hour),
KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{},
BasicConstraintsValid: true,
}
cert, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
if err != nil {
panic(err)
}
return &MemoryX509KeyStore{
privateKey: key,
cert: cert,
}
}

12
vendor/github.com/russellhaering/goxmldsig/run_test.sh сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -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

256
vendor/github.com/russellhaering/goxmldsig/sign.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,256 @@
package dsig
import (
"crypto"
"crypto/rand"
"crypto/rsa"
_ "crypto/sha1"
_ "crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"github.com/beevik/etree"
"github.com/russellhaering/goxmldsig/etreeutils"
)
type SigningContext struct {
Hash crypto.Hash
KeyStore X509KeyStore
IdAttribute string
Prefix string
Canonicalizer Canonicalizer
}
func NewDefaultSigningContext(ks X509KeyStore) *SigningContext {
return &SigningContext{
Hash: crypto.SHA256,
KeyStore: ks,
IdAttribute: DefaultIdAttr,
Prefix: DefaultPrefix,
Canonicalizer: MakeC14N11Canonicalizer(),
}
}
func (ctx *SigningContext) SetSignatureMethod(algorithmID string) error {
hash, ok := signatureMethodsByIdentifier[algorithmID]
if !ok {
return fmt.Errorf("Unknown SignatureMethod: %s", algorithmID)
}
ctx.Hash = hash
return nil
}
func (ctx *SigningContext) digest(el *etree.Element) ([]byte, error) {
canonical, err := ctx.Canonicalizer.Canonicalize(el)
if err != nil {
return nil, err
}
hash := ctx.Hash.New()
_, err = hash.Write(canonical)
if err != nil {
return nil, err
}
return hash.Sum(nil), nil
}
func (ctx *SigningContext) constructSignedInfo(el *etree.Element, enveloped bool) (*etree.Element, error) {
digestAlgorithmIdentifier := ctx.GetDigestAlgorithmIdentifier()
if digestAlgorithmIdentifier == "" {
return nil, errors.New("unsupported hash mechanism")
}
signatureMethodIdentifier := ctx.GetSignatureMethodIdentifier()
if signatureMethodIdentifier == "" {
return nil, errors.New("unsupported signature method")
}
digest, err := ctx.digest(el)
if err != nil {
return nil, err
}
signedInfo := &etree.Element{
Tag: SignedInfoTag,
Space: ctx.Prefix,
}
// /SignedInfo/CanonicalizationMethod
canonicalizationMethod := ctx.createNamespacedElement(signedInfo, CanonicalizationMethodTag)
canonicalizationMethod.CreateAttr(AlgorithmAttr, string(ctx.Canonicalizer.Algorithm()))
// /SignedInfo/SignatureMethod
signatureMethod := ctx.createNamespacedElement(signedInfo, SignatureMethodTag)
signatureMethod.CreateAttr(AlgorithmAttr, signatureMethodIdentifier)
// /SignedInfo/Reference
reference := ctx.createNamespacedElement(signedInfo, ReferenceTag)
dataId := el.SelectAttrValue(ctx.IdAttribute, "")
if dataId == "" {
return nil, errors.New("Missing data ID")
}
reference.CreateAttr(URIAttr, "#"+dataId)
// /SignedInfo/Reference/Transforms
transforms := ctx.createNamespacedElement(reference, TransformsTag)
if enveloped {
envelopedTransform := ctx.createNamespacedElement(transforms, TransformTag)
envelopedTransform.CreateAttr(AlgorithmAttr, EnvelopedSignatureAltorithmId.String())
}
canonicalizationAlgorithm := ctx.createNamespacedElement(transforms, TransformTag)
canonicalizationAlgorithm.CreateAttr(AlgorithmAttr, string(ctx.Canonicalizer.Algorithm()))
// /SignedInfo/Reference/DigestMethod
digestMethod := ctx.createNamespacedElement(reference, DigestMethodTag)
digestMethod.CreateAttr(AlgorithmAttr, digestAlgorithmIdentifier)
// /SignedInfo/Reference/DigestValue
digestValue := ctx.createNamespacedElement(reference, DigestValueTag)
digestValue.SetText(base64.StdEncoding.EncodeToString(digest))
return signedInfo, nil
}
func (ctx *SigningContext) ConstructSignature(el *etree.Element, enveloped bool) (*etree.Element, error) {
signedInfo, err := ctx.constructSignedInfo(el, enveloped)
if err != nil {
return nil, err
}
sig := &etree.Element{
Tag: SignatureTag,
Space: ctx.Prefix,
}
xmlns := "xmlns"
if ctx.Prefix != "" {
xmlns += ":" + ctx.Prefix
}
sig.CreateAttr(xmlns, Namespace)
sig.AddChild(signedInfo)
// When using xml-c14n11 (ie, non-exclusive canonicalization) the canonical form
// of the SignedInfo must declare all namespaces that are in scope at it's final
// enveloped location in the document. In order to do that, we're going to construct
// a series of cascading NSContexts to capture namespace declarations:
// First get the context surrounding the element we are signing.
rootNSCtx, err := etreeutils.NSBuildParentContext(el)
if err != nil {
return nil, err
}
// Then capture any declarations on the element itself.
elNSCtx, err := rootNSCtx.SubContext(el)
if err != nil {
return nil, err
}
// Followed by declarations on the Signature (which we just added above)
sigNSCtx, err := elNSCtx.SubContext(sig)
if err != nil {
return nil, err
}
// Finally detatch the SignedInfo in order to capture all of the namespace
// declarations in the scope we've constructed.
detatchedSignedInfo, err := etreeutils.NSDetatch(sigNSCtx, signedInfo)
if err != nil {
return nil, err
}
digest, err := ctx.digest(detatchedSignedInfo)
if err != nil {
return nil, err
}
key, cert, err := ctx.KeyStore.GetKeyPair()
if err != nil {
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
}
signatureValue := ctx.createNamespacedElement(sig, SignatureValueTag)
signatureValue.SetText(base64.StdEncoding.EncodeToString(rawSignature))
keyInfo := ctx.createNamespacedElement(sig, KeyInfoTag)
x509Data := ctx.createNamespacedElement(keyInfo, X509DataTag)
for _, cert := range certs {
x509Certificate := ctx.createNamespacedElement(x509Data, X509CertificateTag)
x509Certificate.SetText(base64.StdEncoding.EncodeToString(cert))
}
return sig, nil
}
func (ctx *SigningContext) createNamespacedElement(el *etree.Element, tag string) *etree.Element {
child := el.CreateElement(tag)
child.Space = ctx.Prefix
return child
}
func (ctx *SigningContext) SignEnveloped(el *etree.Element) (*etree.Element, error) {
sig, err := ctx.ConstructSignature(el, true)
if err != nil {
return nil, err
}
ret := el.Copy()
ret.Child = append(ret.Child, sig)
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
}

39
vendor/github.com/russellhaering/goxmldsig/tls_keystore.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,39 @@
package dsig
import (
"crypto/rsa"
"crypto/tls"
"fmt"
)
//Well-known errors
var (
ErrNonRSAKey = fmt.Errorf("Private key was not RSA")
ErrMissingCertificates = fmt.Errorf("No public certificates provided")
)
//TLSCertKeyStore wraps the stdlib tls.Certificate to return its contained key
//and certs.
type TLSCertKeyStore tls.Certificate
//GetKeyPair implements X509KeyStore using the underlying tls.Certificate
func (d TLSCertKeyStore) GetKeyPair() (*rsa.PrivateKey, []byte, error) {
pk, ok := d.PrivateKey.(*rsa.PrivateKey)
if !ok {
return nil, nil, ErrNonRSAKey
}
if len(d.Certificate) < 1 {
return nil, nil, ErrMissingCertificates
}
crt := d.Certificate[0]
return pk, crt, nil
}
//GetChain impliments X509ChainStore using the underlying tls.Certificate
func (d TLSCertKeyStore) GetChain() ([][]byte, error) {
return d.Certificate, nil
}

93
vendor/github.com/russellhaering/goxmldsig/types/signature.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,93 @@
package types
import (
"encoding/xml"
"github.com/beevik/etree"
)
type InclusiveNamespaces struct {
XMLName xml.Name `xml:"http://www.w3.org/2001/10/xml-exc-c14n# InclusiveNamespaces"`
PrefixList string `xml:"PrefixList,attr"`
}
type Transform struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# Transform"`
Algorithm string `xml:"Algorithm,attr"`
InclusiveNamespaces *InclusiveNamespaces `xml:"InclusiveNamespaces"`
}
type Transforms struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# Transforms"`
Transforms []Transform `xml:"Transform"`
}
type DigestMethod struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# DigestMethod"`
Algorithm string `xml:"Algorithm,attr"`
}
type Reference struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# Reference"`
URI string `xml:"URI,attr"`
DigestValue string `xml:"DigestValue"`
DigestAlgo DigestMethod `xml:"DigestMethod"`
Transforms Transforms `xml:"Transforms"`
}
type CanonicalizationMethod struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# CanonicalizationMethod"`
Algorithm string `xml:"Algorithm,attr"`
}
type SignatureMethod struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# SignatureMethod"`
Algorithm string `xml:"Algorithm,attr"`
}
type SignedInfo struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# SignedInfo"`
CanonicalizationMethod CanonicalizationMethod `xml:"CanonicalizationMethod"`
SignatureMethod SignatureMethod `xml:"SignatureMethod"`
References []Reference `xml:"Reference"`
}
type SignatureValue struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# SignatureValue"`
Data string `xml:",chardata"`
}
type KeyInfo struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"`
X509Data X509Data `xml:"X509Data"`
}
type X509Data struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"`
X509Certificates []X509Certificate `xml:"X509Certificate"`
}
type X509Certificate struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Certificate"`
Data string `xml:",chardata"`
}
type Signature struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# Signature"`
SignedInfo *SignedInfo `xml:"SignedInfo"`
SignatureValue *SignatureValue `xml:"SignatureValue"`
KeyInfo *KeyInfo `xml:"KeyInfo"`
el *etree.Element
}
// SetUnderlyingElement will be called with a reference to the Element this Signature
// was unmarshaled from.
func (s *Signature) SetUnderlyingElement(el *etree.Element) {
s.el = el
}
// UnderlyingElement returns a reference to the Element this signature was unmarshaled
// from, where applicable.
func (s *Signature) UnderlyingElement() *etree.Element {
return s.el
}

467
vendor/github.com/russellhaering/goxmldsig/validate.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,467 @@
package dsig
import (
"bytes"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"errors"
"fmt"
"regexp"
"github.com/beevik/etree"
"github.com/russellhaering/goxmldsig/etreeutils"
"github.com/russellhaering/goxmldsig/types"
)
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")
)
type ValidationContext struct {
CertificateStore X509CertificateStore
IdAttribute string
Clock *Clock
}
func NewDefaultValidationContext(certificateStore X509CertificateStore) *ValidationContext {
return &ValidationContext{
CertificateStore: certificateStore,
IdAttribute: DefaultIdAttr,
}
}
// TODO(russell_h): More flexible namespace support. This might barely work.
func inNamespace(el *etree.Element, ns string) bool {
for _, attr := range el.Attr {
if attr.Value == ns {
if attr.Space == "" && attr.Key == "xmlns" {
return el.Space == ""
} else if attr.Space == "xmlns" {
return el.Space == attr.Key
}
}
}
return false
}
func childPath(space, tag string) string {
if space == "" {
return "./" + tag
} else {
return "./" + space + ":" + tag
}
}
func mapPathToElement(tree, el *etree.Element) []int {
for i, child := range tree.Child {
if child == el {
return []int{i}
}
}
for i, child := range tree.Child {
if childElement, ok := child.(*etree.Element); ok {
childPath := mapPathToElement(childElement, el)
if childElement != nil {
return append([]int{i}, childPath...)
}
}
}
return nil
}
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.
func (ctx *ValidationContext) transform(
el *etree.Element,
sig *types.Signature,
ref *types.Reference) (*etree.Element, Canonicalizer, error) {
transforms := ref.Transforms.Transforms
if len(transforms) != 2 {
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 {
algo := transform.Algorithm
switch AlgorithmID(algo) {
case EnvelopedSignatureAltorithmId:
if !removeElementAtPath(el, signaturePath) {
return nil, nil, errors.New("Error applying canonicalization transform: Signature not found")
}
case CanonicalXML10ExclusiveAlgorithmId:
var prefixList string
if transform.InclusiveNamespaces != nil {
prefixList = transform.InclusiveNamespaces.PrefixList
}
canonicalizer = MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList)
case CanonicalXML11AlgorithmId:
canonicalizer = MakeC14N11Canonicalizer()
case CanonicalXML10RecAlgorithmId:
canonicalizer = MakeC14N10RecCanonicalizer()
case CanonicalXML10CommentAlgorithmId:
canonicalizer = MakeC14N10CommentCanonicalizer()
default:
return nil, nil, errors.New("Unknown Transform Algorithm: " + algo)
}
}
if canonicalizer == nil {
return nil, nil, errors.New("Expected canonicalization transform")
}
return el, canonicalizer, nil
}
func (ctx *ValidationContext) digest(el *etree.Element, digestAlgorithmId string, canonicalizer Canonicalizer) ([]byte, error) {
data, err := canonicalizer.Canonicalize(el)
if err != nil {
return nil, err
}
digestAlgorithm, ok := digestAlgorithmsByIdentifier[digestAlgorithmId]
if !ok {
return nil, errors.New("Unknown digest algorithm: " + digestAlgorithmId)
}
hash := digestAlgorithm.New()
_, err = hash.Write(data)
if err != nil {
return nil, err
}
return hash.Sum(nil), nil
}
func (ctx *ValidationContext) verifySignedInfo(sig *types.Signature, canonicalizer Canonicalizer, signatureMethodId string, cert *x509.Certificate, decodedSignature []byte) error {
signatureElement := sig.UnderlyingElement()
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")
}
// Canonicalize the xml
canonical, err := canonicalSerialize(signedInfo)
if err != nil {
return err
}
signatureAlgorithm, ok := signatureMethodsByIdentifier[signatureMethodId]
if !ok {
return errors.New("Unknown signature method: " + signatureMethodId)
}
hash := signatureAlgorithm.New()
_, err = hash.Write(canonical)
if err != nil {
return err
}
hashed := hash.Sum(nil)
pubKey, ok := cert.PublicKey.(*rsa.PublicKey)
if !ok {
return errors.New("Invalid public key")
}
// Verify that the private key matching the public key from the cert was what was used to sign the 'SignedInfo' and produce the 'SignatureValue'
err = rsa.VerifyPKCS1v15(pubKey, signatureAlgorithm, hashed[:], decodedSignature)
if err != nil {
return err
}
return nil
}
func (ctx *ValidationContext) validateSignature(el *etree.Element, sig *types.Signature, cert *x509.Certificate) (*etree.Element, error) {
idAttr := el.SelectAttr(ctx.IdAttribute)
if idAttr == nil || idAttr.Value == "" {
return nil, errors.New("Missing ID attribute")
}
var ref *types.Reference
// Find the first reference which references the top-level element
for _, _ref := range sig.SignedInfo.References {
if _ref.URI == "" || _ref.URI[1:] == idAttr.Value {
ref = &_ref
}
}
// Perform all transformations listed in the 'SignedInfo'
// Basically, this means removing the 'SignedInfo'
transformed, canonicalizer, err := ctx.transform(el, sig, ref)
if err != nil {
return nil, err
}
digestAlgorithm := ref.DigestAlgo.Algorithm
// Digest the transformed XML and compare it to the 'DigestValue' from the 'SignedInfo'
digest, err := ctx.digest(transformed, digestAlgorithm, canonicalizer)
if err != nil {
return nil, err
}
decodedDigestValue, err := base64.StdEncoding.DecodeString(ref.DigestValue)
if err != nil {
return nil, err
}
if !bytes.Equal(digest, decodedDigestValue) {
return nil, errors.New("Signature could not be verified")
}
// Decode the 'SignatureValue' so we can compare against it
decodedSignature, err := base64.StdEncoding.DecodeString(sig.SignatureValue.Data)
if err != nil {
return nil, errors.New("Could not decode signature")
}
// Actually verify the 'SignedInfo' was signed by a trusted source
signatureMethod := sig.SignedInfo.SignatureMethod.Algorithm
err = ctx.verifySignedInfo(sig, canonicalizer, signatureMethod, cert, decodedSignature)
if err != nil {
return nil, err
}
return transformed, nil
}
func contains(roots []*x509.Certificate, cert *x509.Certificate) bool {
for _, root := range roots {
if root.Equal(cert) {
return true
}
}
return false
}
// 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)
if idAttr == nil || idAttr.Value == "" {
return nil, errors.New("Missing ID attribute")
}
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 {
found := false
err := etreeutils.NSFindChildrenIterateCtx(ctx, el, Namespace, SignedInfoTag,
func(ctx etreeutils.NSContext, signedInfo *etree.Element) error {
detachedSignedInfo, err := etreeutils.NSDetatch(ctx, signedInfo)
if err != nil {
return err
}
c14NMethod, err := etreeutils.NSFindOneChildCtx(ctx, detachedSignedInfo, Namespace, CanonicalizationMethodTag)
if err != nil {
return err
}
if c14NMethod == nil {
return errors.New("missing CanonicalizationMethod on Signature")
}
c14NAlgorithm := c14NMethod.SelectAttrValue(AlgorithmAttr, "")
var canonicalSignedInfo *etree.Element
switch AlgorithmID(c14NAlgorithm) {
case CanonicalXML10ExclusiveAlgorithmId:
err := etreeutils.TransformExcC14n(detachedSignedInfo, "")
if err != nil {
return err
}
// NOTE: TransformExcC14n transforms the element in-place,
// while canonicalPrep isn't meant to. Once we standardize
// this behavior we can drop this, as well as the adding and
// removing of elements below.
canonicalSignedInfo = detachedSignedInfo
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)
found = true
return etreeutils.ErrTraversalHalted
})
if err != nil {
return err
}
if !found {
return errors.New("Missing SignedInfo")
}
// Unmarshal the signature into a structured Signature type
_sig := &types.Signature{}
err = etreeutils.NSUnmarshalElement(ctx, el, _sig)
if err != nil {
return err
}
// Traverse references in the signature to determine whether it has at least
// one reference to the top level element. If so, conclude the search.
for _, ref := range _sig.SignedInfo.References {
if ref.URI == "" || ref.URI[1:] == idAttr.Value {
sig = _sig
return etreeutils.ErrTraversalHalted
}
}
return nil
})
if err != nil {
return nil, err
}
if sig == nil {
return nil, ErrMissingSignature
}
return sig, nil
}
func (ctx *ValidationContext) verifyCertificate(sig *types.Signature) (*x509.Certificate, error) {
now := ctx.Clock.Now()
roots, err := ctx.CertificateStore.Certificates()
if err != nil {
return nil, err
}
var cert *x509.Certificate
if sig.KeyInfo != nil {
// If the Signature includes KeyInfo, extract the certificate from there
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(
whiteSpace.ReplaceAllString(sig.KeyInfo.X509Data.X509Certificates[0].Data, ""))
if err != nil {
return nil, errors.New("Failed to parse certificate")
}
cert, err = x509.ParseCertificate(certData)
if err != nil {
return nil, err
}
} else {
// If the Signature doesn't have KeyInfo, Use the root certificate if there is only one
if len(roots) == 1 {
cert = roots[0]
} else {
return nil, errors.New("Missing x509 Element")
}
}
// Verify that the certificate is one we trust
if !contains(roots, cert) {
return nil, errors.New("Could not verify certificate against trusted certs")
}
if now.Before(cert.NotBefore) || now.After(cert.NotAfter) {
return nil, errors.New("Cert is not valid at this time")
}
return cert, nil
}
// Validate verifies that the passed element contains a valid enveloped signature
// matching a currently-valid certificate in the context's CertificateStore.
func (ctx *ValidationContext) Validate(el *etree.Element) (*etree.Element, error) {
// Make a copy of the element to avoid mutating the one we were passed.
el = el.Copy()
sig, err := ctx.findSignature(el)
if err != nil {
return nil, err
}
cert, err := ctx.verifyCertificate(sig)
if err != nil {
return nil, err
}
return ctx.validateSignature(el, sig, cert)
}

81
vendor/github.com/russellhaering/goxmldsig/xml_constants.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,81 @@
package dsig
import "crypto"
const (
DefaultPrefix = "ds"
Namespace = "http://www.w3.org/2000/09/xmldsig#"
)
// Tags
const (
SignatureTag = "Signature"
SignedInfoTag = "SignedInfo"
CanonicalizationMethodTag = "CanonicalizationMethod"
SignatureMethodTag = "SignatureMethod"
ReferenceTag = "Reference"
TransformsTag = "Transforms"
TransformTag = "Transform"
DigestMethodTag = "DigestMethod"
DigestValueTag = "DigestValue"
SignatureValueTag = "SignatureValue"
KeyInfoTag = "KeyInfo"
X509DataTag = "X509Data"
X509CertificateTag = "X509Certificate"
InclusiveNamespacesTag = "InclusiveNamespaces"
)
const (
AlgorithmAttr = "Algorithm"
URIAttr = "URI"
DefaultIdAttr = "ID"
PrefixListAttr = "PrefixList"
)
type AlgorithmID string
func (id AlgorithmID) String() string {
return string(id)
}
const (
RSASHA1SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
RSASHA256SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
RSASHA512SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
)
//Well-known signature algorithms
const (
// Supported canonicalization algorithms
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"
)
var digestAlgorithmIdentifiers = map[crypto.Hash]string{
crypto.SHA1: "http://www.w3.org/2000/09/xmldsig#sha1",
crypto.SHA256: "http://www.w3.org/2001/04/xmlenc#sha256",
crypto.SHA512: "http://www.w3.org/2001/04/xmlenc#sha512",
}
var digestAlgorithmsByIdentifier = map[string]crypto.Hash{}
var signatureMethodsByIdentifier = map[string]crypto.Hash{}
func init() {
for hash, id := range digestAlgorithmIdentifiers {
digestAlgorithmsByIdentifier[id] = hash
}
for hash, id := range signatureMethodIdentifiers {
signatureMethodsByIdentifier[id] = hash
}
}
var signatureMethodIdentifiers = map[crypto.Hash]string{
crypto.SHA1: RSASHA1SignatureMethod,
crypto.SHA256: RSASHA256SignatureMethod,
crypto.SHA512: RSASHA512SignatureMethod,
}

12
vendor/modules.txt поставляемый
Просмотреть файл

@@ -6,6 +6,8 @@ github.com/NYTimes/gziphandler
github.com/armon/go-metrics
# github.com/avct/uasurfer v0.0.0-20190821150637-906cc7dc6197
github.com/avct/uasurfer
# github.com/beevik/etree v1.1.0
github.com/beevik/etree
# github.com/beorn7/perks v1.0.1
github.com/beorn7/perks/quantile
# github.com/blang/semver v3.5.1+incompatible
@@ -94,6 +96,8 @@ github.com/jaytaylor/html2text
# github.com/jmoiron/sqlx v1.2.0
github.com/jmoiron/sqlx
github.com/jmoiron/sqlx/reflectx
# github.com/jonboulle/clockwork v0.1.0
github.com/jonboulle/clockwork
# github.com/konsorten/go-windows-terminal-sequences v1.0.2
github.com/konsorten/go-windows-terminal-sequences
# github.com/lann/builder v0.0.0-20180802200727-47ae307949d0
@@ -118,6 +122,10 @@ github.com/mattermost/go-i18n/i18n/language
github.com/mattermost/go-i18n/i18n/translation
# github.com/mattermost/gorp v2.0.1-0.20190301154413-3b31e9a39d05+incompatible
github.com/mattermost/gorp
# github.com/mattermost/gosaml2 v0.3.2
github.com/mattermost/gosaml2
github.com/mattermost/gosaml2/types
github.com/mattermost/gosaml2/uuid
# github.com/mattermost/ldap v0.0.0-20191128190019-9f62ba4b8d4d
github.com/mattermost/ldap
# github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0
@@ -186,6 +194,10 @@ github.com/prometheus/procfs/internal/fs
github.com/prometheus/procfs/internal/util
# github.com/rs/cors v1.7.0
github.com/rs/cors
# github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7
github.com/russellhaering/goxmldsig
github.com/russellhaering/goxmldsig/etreeutils
github.com/russellhaering/goxmldsig/types
# github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd
github.com/rwcarlsen/goexif/exif
github.com/rwcarlsen/goexif/tiff