go.mod: update osbuild/images to v0.156.0
tag v0.155.0 Tagger: imagebuilder-bot <imagebuilder-bots+imagebuilder-bot@redhat.com> Changes with 0.155.0 ---------------- * Fedora 43: add shadow-utils when LockRoot is enabled, update cloud-init service name (osbuild/images#1618) * Author: Achilleas Koutsou, Reviewers: Gianluca Zuccarelli, Michael Vogt * Update osbuild dependency commit ID to latest (osbuild/images#1609) * Author: SchutzBot, Reviewers: Achilleas Koutsou, Simon de Vlieger, Tomáš Hozza * Update snapshots to 20250626 (osbuild/images#1623) * Author: SchutzBot, Reviewers: Achilleas Koutsou, Simon de Vlieger * distro/rhel9: xz compress azure-cvm image type [HMS-8587] (osbuild/images#1620) * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza * distro/rhel: introduce new image type: Azure SAP Apps [HMS-8738] (osbuild/images#1612) * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza * distro/rhel: move ansible-core to sap_extras_pkgset (osbuild/images#1624) * Author: Achilleas Koutsou, Reviewers: Brian C. Lane, Tomáš Hozza * github/create-tag: allow passing the version when run manually (osbuild/images#1621) * Author: Achilleas Koutsou, Reviewers: Lukáš Zapletal, Tomáš Hozza * rhel9: move image-config into pure YAML (HMS-8593) (osbuild/images#1616) * Author: Michael Vogt, Reviewers: Achilleas Koutsou, Simon de Vlieger * test: split manifest checksums into separate files (osbuild/images#1625) * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza — Somewhere on the Internet, 2025-06-30 --- tag v0.156.0 Tagger: imagebuilder-bot <imagebuilder-bots+imagebuilder-bot@redhat.com> Changes with 0.156.0 ---------------- * Many: delete repositories for EOL distributions (HMS-7044) (osbuild/images#1607) * Author: Tomáš Hozza, Reviewers: Michael Vogt, Simon de Vlieger * RHSM/facts: add 'image-builder CLI' API type (osbuild/images#1640) * Author: Tomáš Hozza, Reviewers: Brian C. Lane, Simon de Vlieger * Update dependencies 2025-06-29 (osbuild/images#1628) * Author: SchutzBot, Reviewers: Simon de Vlieger, Tomáš Hozza * Update osbuild dependency commit ID to latest (osbuild/images#1627) * Author: SchutzBot, Reviewers: Simon de Vlieger, Tomáš Hozza * [RFC] image: drop `InstallWeakDeps` from image.DiskImage (osbuild/images#1642) * Author: Michael Vogt, Reviewers: Brian C. Lane, Simon de Vlieger, Tomáš Hozza * build(deps): bump the go-deps group across 1 directory with 3 updates (osbuild/images#1632) * Author: dependabot[bot], Reviewers: SchutzBot, Tomáš Hozza * distro/rhel10: xz compress azure-cvm image type (osbuild/images#1638) * Author: Achilleas Koutsou, Reviewers: Brian C. Lane, Simon de Vlieger * distro: cleanup/refactor distro/{defs,generic} (HMS-8744) (osbuild/images#1570) * Author: Michael Vogt, Reviewers: Simon de Vlieger, Tomáš Hozza * distro: remove some hardcoded values from generic/images.go (osbuild/images#1636) * Author: Michael Vogt, Reviewers: Simon de Vlieger, Tomáš Hozza * distro: small tweaks for the YAML based imagetypes (osbuild/images#1622) * Author: Michael Vogt, Reviewers: Brian C. Lane, Simon de Vlieger * fedora/wsl: packages and locale (osbuild/images#1635) * Author: Simon de Vlieger, Reviewers: Michael Vogt, Tomáš Hozza * image/many: make compression more generic (osbuild/images#1634) * Author: Simon de Vlieger, Reviewers: Brian C. Lane, Michael Vogt * manifest: handle content template name with spaces (osbuild/images#1641) * Author: Bryttanie, Reviewers: Brian C. Lane, Michael Vogt, Tomáš Hozza * many: implement gzip (osbuild/images#1633) * Author: Simon de Vlieger, Reviewers: Michael Vogt, Tomáš Hozza * rhel/azure: set GRUB_TERMINAL based on architecture [RHEL-91383] (osbuild/images#1626) * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza — Somewhere on the Internet, 2025-07-07 ---
This commit is contained in:
parent
60c5f10af8
commit
3fd7092db5
1486 changed files with 124742 additions and 82516 deletions
201
vendor/github.com/spiffe/go-spiffe/v2/LICENSE
generated
vendored
Normal file
201
vendor/github.com/spiffe/go-spiffe/v2/LICENSE
generated
vendored
Normal file
|
|
@ -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.
|
||||
200
vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/bundle.go
generated
vendored
Normal file
200
vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/bundle.go
generated
vendored
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
package jwtbundle
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
"github.com/spiffe/go-spiffe/v2/internal/jwtutil"
|
||||
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||
"github.com/zeebo/errs"
|
||||
)
|
||||
|
||||
var jwtbundleErr = errs.Class("jwtbundle")
|
||||
|
||||
// Bundle is a collection of trusted JWT authorities for a trust domain.
|
||||
type Bundle struct {
|
||||
trustDomain spiffeid.TrustDomain
|
||||
|
||||
mtx sync.RWMutex
|
||||
jwtAuthorities map[string]crypto.PublicKey
|
||||
}
|
||||
|
||||
// New creates a new bundle.
|
||||
func New(trustDomain spiffeid.TrustDomain) *Bundle {
|
||||
return &Bundle{
|
||||
trustDomain: trustDomain,
|
||||
jwtAuthorities: make(map[string]crypto.PublicKey),
|
||||
}
|
||||
}
|
||||
|
||||
// FromJWTAuthorities creates a new bundle from JWT authorities
|
||||
func FromJWTAuthorities(trustDomain spiffeid.TrustDomain, jwtAuthorities map[string]crypto.PublicKey) *Bundle {
|
||||
return &Bundle{
|
||||
trustDomain: trustDomain,
|
||||
jwtAuthorities: jwtutil.CopyJWTAuthorities(jwtAuthorities),
|
||||
}
|
||||
}
|
||||
|
||||
// Load loads a bundle from a file on disk. The file must contain a standard RFC 7517 JWKS document.
|
||||
func Load(trustDomain spiffeid.TrustDomain, path string) (*Bundle, error) {
|
||||
bundleBytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, jwtbundleErr.New("unable to read JWT bundle: %w", err)
|
||||
}
|
||||
|
||||
return Parse(trustDomain, bundleBytes)
|
||||
}
|
||||
|
||||
// Read decodes a bundle from a reader. The contents must contain a standard RFC 7517 JWKS document.
|
||||
func Read(trustDomain spiffeid.TrustDomain, r io.Reader) (*Bundle, error) {
|
||||
b, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, jwtbundleErr.New("unable to read: %v", err)
|
||||
}
|
||||
|
||||
return Parse(trustDomain, b)
|
||||
}
|
||||
|
||||
// Parse parses a bundle from bytes. The data must be a standard RFC 7517 JWKS document.
|
||||
func Parse(trustDomain spiffeid.TrustDomain, bundleBytes []byte) (*Bundle, error) {
|
||||
jwks := new(jose.JSONWebKeySet)
|
||||
if err := json.Unmarshal(bundleBytes, jwks); err != nil {
|
||||
return nil, jwtbundleErr.New("unable to parse JWKS: %v", err)
|
||||
}
|
||||
|
||||
bundle := New(trustDomain)
|
||||
for i, key := range jwks.Keys {
|
||||
if err := bundle.AddJWTAuthority(key.KeyID, key.Key); err != nil {
|
||||
return nil, jwtbundleErr.New("error adding authority %d of JWKS: %v", i, errors.Unwrap(err))
|
||||
}
|
||||
}
|
||||
|
||||
return bundle, nil
|
||||
}
|
||||
|
||||
// TrustDomain returns the trust domain that the bundle belongs to.
|
||||
func (b *Bundle) TrustDomain() spiffeid.TrustDomain {
|
||||
return b.trustDomain
|
||||
}
|
||||
|
||||
// JWTAuthorities returns the JWT authorities in the bundle, keyed by key ID.
|
||||
func (b *Bundle) JWTAuthorities() map[string]crypto.PublicKey {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
return jwtutil.CopyJWTAuthorities(b.jwtAuthorities)
|
||||
}
|
||||
|
||||
// FindJWTAuthority finds the JWT authority with the given key ID from the bundle. If the authority
|
||||
// is found, it is returned and the boolean is true. Otherwise, the returned
|
||||
// value is nil and the boolean is false.
|
||||
func (b *Bundle) FindJWTAuthority(keyID string) (crypto.PublicKey, bool) {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
if jwtAuthority, ok := b.jwtAuthorities[keyID]; ok {
|
||||
return jwtAuthority, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// HasJWTAuthority returns true if the bundle has a JWT authority with the given key ID.
|
||||
func (b *Bundle) HasJWTAuthority(keyID string) bool {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
_, ok := b.jwtAuthorities[keyID]
|
||||
return ok
|
||||
}
|
||||
|
||||
// AddJWTAuthority adds a JWT authority to the bundle. If a JWT authority already exists
|
||||
// under the given key ID, it is replaced. A key ID must be specified.
|
||||
func (b *Bundle) AddJWTAuthority(keyID string, jwtAuthority crypto.PublicKey) error {
|
||||
if keyID == "" {
|
||||
return jwtbundleErr.New("keyID cannot be empty")
|
||||
}
|
||||
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
b.jwtAuthorities[keyID] = jwtAuthority
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveJWTAuthority removes the JWT authority identified by the key ID from the bundle.
|
||||
func (b *Bundle) RemoveJWTAuthority(keyID string) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
delete(b.jwtAuthorities, keyID)
|
||||
}
|
||||
|
||||
// SetJWTAuthorities sets the JWT authorities in the bundle.
|
||||
func (b *Bundle) SetJWTAuthorities(jwtAuthorities map[string]crypto.PublicKey) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
b.jwtAuthorities = jwtutil.CopyJWTAuthorities(jwtAuthorities)
|
||||
}
|
||||
|
||||
// Empty returns true if the bundle has no JWT authorities.
|
||||
func (b *Bundle) Empty() bool {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
return len(b.jwtAuthorities) == 0
|
||||
}
|
||||
|
||||
// Marshal marshals the JWT bundle into a standard RFC 7517 JWKS document. The
|
||||
// JWKS does not contain any SPIFFE-specific parameters.
|
||||
func (b *Bundle) Marshal() ([]byte, error) {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
jwks := jose.JSONWebKeySet{}
|
||||
for keyID, jwtAuthority := range b.jwtAuthorities {
|
||||
jwks.Keys = append(jwks.Keys, jose.JSONWebKey{
|
||||
Key: jwtAuthority,
|
||||
KeyID: keyID,
|
||||
})
|
||||
}
|
||||
|
||||
return json.Marshal(jwks)
|
||||
}
|
||||
|
||||
// Clone clones the bundle.
|
||||
func (b *Bundle) Clone() *Bundle {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
return FromJWTAuthorities(b.trustDomain, b.jwtAuthorities)
|
||||
}
|
||||
|
||||
// Equal compares the bundle for equality against the given bundle.
|
||||
func (b *Bundle) Equal(other *Bundle) bool {
|
||||
if b == nil || other == nil {
|
||||
return b == other
|
||||
}
|
||||
|
||||
return b.trustDomain == other.trustDomain &&
|
||||
jwtutil.JWTAuthoritiesEqual(b.jwtAuthorities, other.jwtAuthorities)
|
||||
}
|
||||
|
||||
// GetJWTBundleForTrustDomain returns the JWT bundle for the given trust
|
||||
// domain. It implements the Source interface. An error will be returned if
|
||||
// the trust domain does not match that of the bundle.
|
||||
func (b *Bundle) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
if b.trustDomain != trustDomain {
|
||||
return nil, jwtbundleErr.New("no JWT bundle for trust domain %q", trustDomain)
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
43
vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/doc.go
generated
vendored
Normal file
43
vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Package jwtbundle provides JWT bundle related functionality.
|
||||
//
|
||||
// A bundle represents a collection of JWT authorities, i.e., those that
|
||||
// are used to authenticate SPIFFE JWT-SVIDs.
|
||||
//
|
||||
// You can create a new bundle for a specific trust domain:
|
||||
//
|
||||
// td := spiffeid.RequireTrustDomainFromString("example.org")
|
||||
// bundle := jwtbundle.New(td)
|
||||
//
|
||||
// Or you can load it from disk:
|
||||
//
|
||||
// td := spiffeid.RequireTrustDomainFromString("example.org")
|
||||
// bundle := jwtbundle.Load(td, "bundle.jwks")
|
||||
//
|
||||
// The bundle can be initialized with JWT authorities:
|
||||
//
|
||||
// td := spiffeid.RequireTrustDomainFromString("example.org")
|
||||
// var jwtAuthorities map[string]crypto.PublicKey = ...
|
||||
// bundle := jwtbundle.FromJWTAuthorities(td, jwtAuthorities)
|
||||
//
|
||||
// In addition, you can add JWT authorities to the bundle:
|
||||
//
|
||||
// var keyID string = ...
|
||||
// var publicKey crypto.PublicKey = ...
|
||||
// bundle.AddJWTAuthority(keyID, publicKey)
|
||||
//
|
||||
// Bundles can be organized into a set, keyed by trust domain:
|
||||
//
|
||||
// set := jwtbundle.NewSet()
|
||||
// set.Add(bundle)
|
||||
//
|
||||
// A Source is source of JWT bundles for a trust domain. Both the Bundle
|
||||
// and Set types implement Source:
|
||||
//
|
||||
// // Initialize the source from a bundle or set
|
||||
// var source jwtbundle.Source = bundle
|
||||
// // ... or ...
|
||||
// var source jwtbundle.Source = set
|
||||
//
|
||||
// // Use the source to query for bundles by trust domain
|
||||
// bundle, err := source.GetJWTBundleForTrustDomain(td)
|
||||
package jwtbundle
|
||||
105
vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/set.go
generated
vendored
Normal file
105
vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/set.go
generated
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package jwtbundle
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||
)
|
||||
|
||||
// Set is a set of bundles, keyed by trust domain.
|
||||
type Set struct {
|
||||
mtx sync.RWMutex
|
||||
bundles map[spiffeid.TrustDomain]*Bundle
|
||||
}
|
||||
|
||||
// NewSet creates a new set initialized with the given bundles.
|
||||
func NewSet(bundles ...*Bundle) *Set {
|
||||
bundlesMap := make(map[spiffeid.TrustDomain]*Bundle)
|
||||
|
||||
for _, b := range bundles {
|
||||
if b != nil {
|
||||
bundlesMap[b.trustDomain] = b
|
||||
}
|
||||
}
|
||||
|
||||
return &Set{
|
||||
bundles: bundlesMap,
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds a new bundle into the set. If a bundle already exists for the
|
||||
// trust domain, the existing bundle is replaced.
|
||||
func (s *Set) Add(bundle *Bundle) {
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
|
||||
if bundle != nil {
|
||||
s.bundles[bundle.trustDomain] = bundle
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes the bundle for the given trust domain.
|
||||
func (s *Set) Remove(trustDomain spiffeid.TrustDomain) {
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
|
||||
delete(s.bundles, trustDomain)
|
||||
}
|
||||
|
||||
// Has returns true if there is a bundle for the given trust domain.
|
||||
func (s *Set) Has(trustDomain spiffeid.TrustDomain) bool {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
_, ok := s.bundles[trustDomain]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Get returns a bundle for the given trust domain. If the bundle is in the set
|
||||
// it is returned and the boolean is true. Otherwise, the returned value is
|
||||
// nil and the boolean is false.
|
||||
func (s *Set) Get(trustDomain spiffeid.TrustDomain) (*Bundle, bool) {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
bundle, ok := s.bundles[trustDomain]
|
||||
return bundle, ok
|
||||
}
|
||||
|
||||
// Bundles returns the bundles in the set sorted by trust domain.
|
||||
func (s *Set) Bundles() []*Bundle {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
out := make([]*Bundle, 0, len(s.bundles))
|
||||
for _, bundle := range s.bundles {
|
||||
out = append(out, bundle)
|
||||
}
|
||||
sort.Slice(out, func(a, b int) bool {
|
||||
return out[a].TrustDomain().Compare(out[b].TrustDomain()) < 0
|
||||
})
|
||||
return out
|
||||
}
|
||||
|
||||
// Len returns the number of bundles in the set.
|
||||
func (s *Set) Len() int {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
return len(s.bundles)
|
||||
}
|
||||
|
||||
// GetJWTBundleForTrustDomain returns the JWT bundle for the given trust
|
||||
// domain. It implements the Source interface.
|
||||
func (s *Set) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
bundle, ok := s.bundles[trustDomain]
|
||||
if !ok {
|
||||
return nil, jwtbundleErr.New("no JWT bundle for trust domain %q", trustDomain)
|
||||
}
|
||||
|
||||
return bundle, nil
|
||||
}
|
||||
12
vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/source.go
generated
vendored
Normal file
12
vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/source.go
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package jwtbundle
|
||||
|
||||
import (
|
||||
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||
)
|
||||
|
||||
// Source represents a source of JWT bundles keyed by trust domain.
|
||||
type Source interface {
|
||||
// GetJWTBundleForTrustDomain returns the JWT bundle for the given trust
|
||||
// domain.
|
||||
GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error)
|
||||
}
|
||||
485
vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/bundle.go
generated
vendored
Normal file
485
vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/bundle.go
generated
vendored
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
package spiffebundle
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
"github.com/spiffe/go-spiffe/v2/bundle/jwtbundle"
|
||||
"github.com/spiffe/go-spiffe/v2/bundle/x509bundle"
|
||||
"github.com/spiffe/go-spiffe/v2/internal/jwtutil"
|
||||
"github.com/spiffe/go-spiffe/v2/internal/x509util"
|
||||
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||
"github.com/zeebo/errs"
|
||||
)
|
||||
|
||||
const (
|
||||
x509SVIDUse = "x509-svid"
|
||||
jwtSVIDUse = "jwt-svid"
|
||||
)
|
||||
|
||||
var spiffebundleErr = errs.Class("spiffebundle")
|
||||
|
||||
type bundleDoc struct {
|
||||
jose.JSONWebKeySet
|
||||
SequenceNumber *uint64 `json:"spiffe_sequence,omitempty"`
|
||||
RefreshHint *int64 `json:"spiffe_refresh_hint,omitempty"`
|
||||
}
|
||||
|
||||
// Bundle is a collection of trusted public key material for a trust domain,
|
||||
// conforming to the SPIFFE Bundle Format as part of the SPIFFE Trust Domain
|
||||
// and Bundle specification:
|
||||
// https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Trust_Domain_and_Bundle.md
|
||||
type Bundle struct {
|
||||
trustDomain spiffeid.TrustDomain
|
||||
|
||||
mtx sync.RWMutex
|
||||
refreshHint *time.Duration
|
||||
sequenceNumber *uint64
|
||||
jwtAuthorities map[string]crypto.PublicKey
|
||||
x509Authorities []*x509.Certificate
|
||||
}
|
||||
|
||||
// New creates a new bundle.
|
||||
func New(trustDomain spiffeid.TrustDomain) *Bundle {
|
||||
return &Bundle{
|
||||
trustDomain: trustDomain,
|
||||
jwtAuthorities: make(map[string]crypto.PublicKey),
|
||||
}
|
||||
}
|
||||
|
||||
// Load loads a bundle from a file on disk. The file must contain a JWKS
|
||||
// document following the SPIFFE Trust Domain and Bundle specification.
|
||||
func Load(trustDomain spiffeid.TrustDomain, path string) (*Bundle, error) {
|
||||
bundleBytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, spiffebundleErr.New("unable to read SPIFFE bundle: %w", err)
|
||||
}
|
||||
|
||||
return Parse(trustDomain, bundleBytes)
|
||||
}
|
||||
|
||||
// Read decodes a bundle from a reader. The contents must contain a JWKS
|
||||
// document following the SPIFFE Trust Domain and Bundle specification.
|
||||
func Read(trustDomain spiffeid.TrustDomain, r io.Reader) (*Bundle, error) {
|
||||
b, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, spiffebundleErr.New("unable to read: %v", err)
|
||||
}
|
||||
|
||||
return Parse(trustDomain, b)
|
||||
}
|
||||
|
||||
// Parse parses a bundle from bytes. The data must be a JWKS document following
|
||||
// the SPIFFE Trust Domain and Bundle specification.
|
||||
func Parse(trustDomain spiffeid.TrustDomain, bundleBytes []byte) (*Bundle, error) {
|
||||
jwks := &bundleDoc{}
|
||||
if err := json.Unmarshal(bundleBytes, jwks); err != nil {
|
||||
return nil, spiffebundleErr.New("unable to parse JWKS: %v", err)
|
||||
}
|
||||
|
||||
bundle := New(trustDomain)
|
||||
if jwks.RefreshHint != nil {
|
||||
bundle.SetRefreshHint(time.Second * time.Duration(*jwks.RefreshHint))
|
||||
}
|
||||
if jwks.SequenceNumber != nil {
|
||||
bundle.SetSequenceNumber(*jwks.SequenceNumber)
|
||||
}
|
||||
|
||||
if jwks.Keys == nil {
|
||||
// The parameter keys MUST be present.
|
||||
// https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Trust_Domain_and_Bundle.md#413-keys
|
||||
return nil, spiffebundleErr.New("no authorities found")
|
||||
}
|
||||
for i, key := range jwks.Keys {
|
||||
switch key.Use {
|
||||
// Two SVID types are supported: x509-svid and jwt-svid.
|
||||
case x509SVIDUse:
|
||||
if len(key.Certificates) != 1 {
|
||||
return nil, spiffebundleErr.New("expected a single certificate in %s entry %d; got %d", x509SVIDUse, i, len(key.Certificates))
|
||||
}
|
||||
bundle.AddX509Authority(key.Certificates[0])
|
||||
case jwtSVIDUse:
|
||||
if err := bundle.AddJWTAuthority(key.KeyID, key.Key); err != nil {
|
||||
return nil, spiffebundleErr.New("error adding authority %d of JWKS: %v", i, errors.Unwrap(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bundle, nil
|
||||
}
|
||||
|
||||
// FromX509Bundle creates a bundle from an X.509 bundle.
|
||||
// The function panics in case of a nil X.509 bundle.
|
||||
func FromX509Bundle(x509Bundle *x509bundle.Bundle) *Bundle {
|
||||
bundle := New(x509Bundle.TrustDomain())
|
||||
bundle.x509Authorities = x509Bundle.X509Authorities()
|
||||
return bundle
|
||||
}
|
||||
|
||||
// FromJWTBundle creates a bundle from a JWT bundle.
|
||||
// The function panics in case of a nil JWT bundle.
|
||||
func FromJWTBundle(jwtBundle *jwtbundle.Bundle) *Bundle {
|
||||
bundle := New(jwtBundle.TrustDomain())
|
||||
bundle.jwtAuthorities = jwtBundle.JWTAuthorities()
|
||||
return bundle
|
||||
}
|
||||
|
||||
// FromX509Authorities creates a bundle from X.509 certificates.
|
||||
func FromX509Authorities(trustDomain spiffeid.TrustDomain, x509Authorities []*x509.Certificate) *Bundle {
|
||||
bundle := New(trustDomain)
|
||||
bundle.x509Authorities = x509util.CopyX509Authorities(x509Authorities)
|
||||
return bundle
|
||||
}
|
||||
|
||||
// FromJWTAuthorities creates a new bundle from JWT authorities.
|
||||
func FromJWTAuthorities(trustDomain spiffeid.TrustDomain, jwtAuthorities map[string]crypto.PublicKey) *Bundle {
|
||||
bundle := New(trustDomain)
|
||||
bundle.jwtAuthorities = jwtutil.CopyJWTAuthorities(jwtAuthorities)
|
||||
return bundle
|
||||
}
|
||||
|
||||
// TrustDomain returns the trust domain that the bundle belongs to.
|
||||
func (b *Bundle) TrustDomain() spiffeid.TrustDomain {
|
||||
return b.trustDomain
|
||||
}
|
||||
|
||||
// X509Authorities returns the X.509 authorities in the bundle.
|
||||
func (b *Bundle) X509Authorities() []*x509.Certificate {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
return x509util.CopyX509Authorities(b.x509Authorities)
|
||||
}
|
||||
|
||||
// AddX509Authority adds an X.509 authority to the bundle. If the authority already
|
||||
// exists in the bundle, the contents of the bundle will remain unchanged.
|
||||
func (b *Bundle) AddX509Authority(x509Authority *x509.Certificate) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
for _, r := range b.x509Authorities {
|
||||
if r.Equal(x509Authority) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
b.x509Authorities = append(b.x509Authorities, x509Authority)
|
||||
}
|
||||
|
||||
// RemoveX509Authority removes an X.509 authority from the bundle.
|
||||
func (b *Bundle) RemoveX509Authority(x509Authority *x509.Certificate) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
for i, r := range b.x509Authorities {
|
||||
if r.Equal(x509Authority) {
|
||||
b.x509Authorities = append(b.x509Authorities[:i], b.x509Authorities[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HasX509Authority checks if the given X.509 authority exists in the bundle.
|
||||
func (b *Bundle) HasX509Authority(x509Authority *x509.Certificate) bool {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
for _, r := range b.x509Authorities {
|
||||
if r.Equal(x509Authority) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SetX509Authorities sets the X.509 authorities in the bundle.
|
||||
func (b *Bundle) SetX509Authorities(authorities []*x509.Certificate) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
b.x509Authorities = x509util.CopyX509Authorities(authorities)
|
||||
}
|
||||
|
||||
// JWTAuthorities returns the JWT authorities in the bundle, keyed by key ID.
|
||||
func (b *Bundle) JWTAuthorities() map[string]crypto.PublicKey {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
return jwtutil.CopyJWTAuthorities(b.jwtAuthorities)
|
||||
}
|
||||
|
||||
// FindJWTAuthority finds the JWT authority with the given key ID from the bundle. If the authority
|
||||
// is found, it is returned and the boolean is true. Otherwise, the returned
|
||||
// value is nil and the boolean is false.
|
||||
func (b *Bundle) FindJWTAuthority(keyID string) (crypto.PublicKey, bool) {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
jwtAuthority, ok := b.jwtAuthorities[keyID]
|
||||
return jwtAuthority, ok
|
||||
}
|
||||
|
||||
// HasJWTAuthority returns true if the bundle has a JWT authority with the given key ID.
|
||||
func (b *Bundle) HasJWTAuthority(keyID string) bool {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
_, ok := b.jwtAuthorities[keyID]
|
||||
return ok
|
||||
}
|
||||
|
||||
// AddJWTAuthority adds a JWT authority to the bundle. If a JWT authority already exists
|
||||
// under the given key ID, it is replaced. A key ID must be specified.
|
||||
func (b *Bundle) AddJWTAuthority(keyID string, jwtAuthority crypto.PublicKey) error {
|
||||
if keyID == "" {
|
||||
return spiffebundleErr.New("keyID cannot be empty")
|
||||
}
|
||||
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
b.jwtAuthorities[keyID] = jwtAuthority
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveJWTAuthority removes the JWT authority identified by the key ID from the bundle.
|
||||
func (b *Bundle) RemoveJWTAuthority(keyID string) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
delete(b.jwtAuthorities, keyID)
|
||||
}
|
||||
|
||||
// SetJWTAuthorities sets the JWT authorities in the bundle.
|
||||
func (b *Bundle) SetJWTAuthorities(jwtAuthorities map[string]crypto.PublicKey) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
b.jwtAuthorities = jwtutil.CopyJWTAuthorities(jwtAuthorities)
|
||||
}
|
||||
|
||||
// Empty returns true if the bundle has no X.509 and JWT authorities.
|
||||
func (b *Bundle) Empty() bool {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
return len(b.x509Authorities) == 0 && len(b.jwtAuthorities) == 0
|
||||
}
|
||||
|
||||
// RefreshHint returns the refresh hint. If the refresh hint is set in
|
||||
// the bundle, it is returned and the boolean is true. Otherwise, the returned
|
||||
// value is zero and the boolean is false.
|
||||
func (b *Bundle) RefreshHint() (refreshHint time.Duration, ok bool) {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
if b.refreshHint != nil {
|
||||
return *b.refreshHint, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// SetRefreshHint sets the refresh hint. The refresh hint value will be
|
||||
// truncated to time.Second.
|
||||
func (b *Bundle) SetRefreshHint(refreshHint time.Duration) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
b.refreshHint = &refreshHint
|
||||
}
|
||||
|
||||
// ClearRefreshHint clears the refresh hint.
|
||||
func (b *Bundle) ClearRefreshHint() {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
b.refreshHint = nil
|
||||
}
|
||||
|
||||
// SequenceNumber returns the sequence number. If the sequence number is set in
|
||||
// the bundle, it is returned and the boolean is true. Otherwise, the returned
|
||||
// value is zero and the boolean is false.
|
||||
func (b *Bundle) SequenceNumber() (uint64, bool) {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
if b.sequenceNumber != nil {
|
||||
return *b.sequenceNumber, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// SetSequenceNumber sets the sequence number.
|
||||
func (b *Bundle) SetSequenceNumber(sequenceNumber uint64) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
b.sequenceNumber = &sequenceNumber
|
||||
}
|
||||
|
||||
// ClearSequenceNumber clears the sequence number.
|
||||
func (b *Bundle) ClearSequenceNumber() {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
b.sequenceNumber = nil
|
||||
}
|
||||
|
||||
// Marshal marshals the bundle according to the SPIFFE Trust Domain and Bundle
|
||||
// specification. The trust domain is not marshaled as part of the bundle and
|
||||
// must be conveyed separately. See the specification for details.
|
||||
func (b *Bundle) Marshal() ([]byte, error) {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
jwks := bundleDoc{}
|
||||
if b.refreshHint != nil {
|
||||
tr := int64((*b.refreshHint + (time.Second - 1)) / time.Second)
|
||||
jwks.RefreshHint = &tr
|
||||
}
|
||||
jwks.SequenceNumber = b.sequenceNumber
|
||||
for _, x509Authority := range b.x509Authorities {
|
||||
jwks.Keys = append(jwks.Keys, jose.JSONWebKey{
|
||||
Key: x509Authority.PublicKey,
|
||||
Certificates: []*x509.Certificate{x509Authority},
|
||||
Use: x509SVIDUse,
|
||||
})
|
||||
}
|
||||
|
||||
for keyID, jwtAuthority := range b.jwtAuthorities {
|
||||
jwks.Keys = append(jwks.Keys, jose.JSONWebKey{
|
||||
Key: jwtAuthority,
|
||||
KeyID: keyID,
|
||||
Use: jwtSVIDUse,
|
||||
})
|
||||
}
|
||||
|
||||
return json.Marshal(jwks)
|
||||
}
|
||||
|
||||
// Clone clones the bundle.
|
||||
func (b *Bundle) Clone() *Bundle {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
return &Bundle{
|
||||
trustDomain: b.trustDomain,
|
||||
refreshHint: copyRefreshHint(b.refreshHint),
|
||||
sequenceNumber: copySequenceNumber(b.sequenceNumber),
|
||||
x509Authorities: x509util.CopyX509Authorities(b.x509Authorities),
|
||||
jwtAuthorities: jwtutil.CopyJWTAuthorities(b.jwtAuthorities),
|
||||
}
|
||||
}
|
||||
|
||||
// X509Bundle returns an X.509 bundle containing the X.509 authorities in the SPIFFE
|
||||
// bundle.
|
||||
func (b *Bundle) X509Bundle() *x509bundle.Bundle {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
// FromX509Authorities makes a copy, so we can pass our internal slice directly.
|
||||
return x509bundle.FromX509Authorities(b.trustDomain, b.x509Authorities)
|
||||
}
|
||||
|
||||
// JWTBundle returns a JWT bundle containing the JWT authorities in the SPIFFE bundle.
|
||||
func (b *Bundle) JWTBundle() *jwtbundle.Bundle {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
// FromJWTBundle makes a copy, so we can pass our internal slice directly.
|
||||
return jwtbundle.FromJWTAuthorities(b.trustDomain, b.jwtAuthorities)
|
||||
}
|
||||
|
||||
// GetBundleForTrustDomain returns the SPIFFE bundle for the given trust
|
||||
// domain. It implements the Source interface. An error will be returned if the
|
||||
// trust domain does not match that of the bundle.
|
||||
func (b *Bundle) GetBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
if b.trustDomain != trustDomain {
|
||||
return nil, spiffebundleErr.New("no SPIFFE bundle for trust domain %q", trustDomain)
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// GetX509BundleForTrustDomain returns the X.509 bundle for the given trust
|
||||
// domain. It implements the x509bundle.Source interface. An error will be
|
||||
// returned if the trust domain does not match that of the bundle.
|
||||
func (b *Bundle) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*x509bundle.Bundle, error) {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
if b.trustDomain != trustDomain {
|
||||
return nil, spiffebundleErr.New("no X.509 bundle for trust domain %q", trustDomain)
|
||||
}
|
||||
|
||||
return b.X509Bundle(), nil
|
||||
}
|
||||
|
||||
// GetJWTBundleForTrustDomain returns the JWT bundle of the given trust domain.
|
||||
// It implements the jwtbundle.Source interface. An error will be returned if
|
||||
// the trust domain does not match that of the bundle.
|
||||
func (b *Bundle) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*jwtbundle.Bundle, error) {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
if b.trustDomain != trustDomain {
|
||||
return nil, spiffebundleErr.New("no JWT bundle for trust domain %q", trustDomain)
|
||||
}
|
||||
|
||||
return b.JWTBundle(), nil
|
||||
}
|
||||
|
||||
// Equal compares the bundle for equality against the given bundle.
|
||||
func (b *Bundle) Equal(other *Bundle) bool {
|
||||
if b == nil || other == nil {
|
||||
return b == other
|
||||
}
|
||||
|
||||
return b.trustDomain == other.trustDomain &&
|
||||
refreshHintEqual(b.refreshHint, other.refreshHint) &&
|
||||
sequenceNumberEqual(b.sequenceNumber, other.sequenceNumber) &&
|
||||
jwtutil.JWTAuthoritiesEqual(b.jwtAuthorities, other.jwtAuthorities) &&
|
||||
x509util.CertsEqual(b.x509Authorities, other.x509Authorities)
|
||||
}
|
||||
|
||||
func refreshHintEqual(a, b *time.Duration) bool {
|
||||
if a == nil || b == nil {
|
||||
return a == b
|
||||
}
|
||||
|
||||
return *a == *b
|
||||
}
|
||||
|
||||
func sequenceNumberEqual(a, b *uint64) bool {
|
||||
if a == nil || b == nil {
|
||||
return a == b
|
||||
}
|
||||
|
||||
return *a == *b
|
||||
}
|
||||
|
||||
func copyRefreshHint(refreshHint *time.Duration) *time.Duration {
|
||||
if refreshHint == nil {
|
||||
return nil
|
||||
}
|
||||
copied := *refreshHint
|
||||
return &copied
|
||||
}
|
||||
|
||||
func copySequenceNumber(sequenceNumber *uint64) *uint64 {
|
||||
if sequenceNumber == nil {
|
||||
return nil
|
||||
}
|
||||
copied := *sequenceNumber
|
||||
return &copied
|
||||
}
|
||||
59
vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/doc.go
generated
vendored
Normal file
59
vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Package spiffebundle provides SPIFFE bundle related functionality.
|
||||
//
|
||||
// A bundle represents a SPIFFE bundle, a collection authorities for
|
||||
// authenticating SVIDs.
|
||||
//
|
||||
// You can create a new bundle for a specific trust domain:
|
||||
//
|
||||
// td := spiffeid.RequireTrustDomainFromString("example.org")
|
||||
// bundle := spiffebundle.New(td)
|
||||
//
|
||||
// Or you can load it from disk:
|
||||
//
|
||||
// td := spiffeid.RequireTrustDomainFromString("example.org")
|
||||
// bundle := spiffebundle.Load(td, "bundle.json")
|
||||
//
|
||||
// The bundle can be initialized with X.509 or JWT authorities:
|
||||
//
|
||||
// td := spiffeid.RequireTrustDomainFromString("example.org")
|
||||
//
|
||||
// var x509Authorities []*x509.Certificate = ...
|
||||
// bundle := spiffebundle.FromX509Authorities(td, x509Authorities)
|
||||
// // ... or ...
|
||||
// var jwtAuthorities map[string]crypto.PublicKey = ...
|
||||
// bundle := spiffebundle.FromJWTAuthorities(td, jwtAuthorities)
|
||||
//
|
||||
// In addition, you can add authorities to the bundle:
|
||||
//
|
||||
// var x509CA *x509.Certificate = ...
|
||||
// bundle.AddX509Authority(x509CA)
|
||||
// var keyID string = ...
|
||||
// var publicKey crypto.PublicKey = ...
|
||||
// bundle.AddJWTAuthority(keyID, publicKey)
|
||||
//
|
||||
// Bundles can be organized into a set, keyed by trust domain:
|
||||
//
|
||||
// set := spiffebundle.NewSet()
|
||||
// set.Add(bundle)
|
||||
//
|
||||
// A Source is source of bundles for a trust domain. Both the
|
||||
// Bundle and Set types implement Source:
|
||||
//
|
||||
// // Initialize the source from a bundle or set
|
||||
// var source spiffebundle.Source = bundle
|
||||
// // ... or ...
|
||||
// var source spiffebundle.Source = set
|
||||
//
|
||||
// // Use the source to query for X.509 bundles by trust domain
|
||||
// bundle, err := source.GetBundleForTrustDomain(td)
|
||||
//
|
||||
// Additionally the Bundle and Set types also implement the x509bundle.Source and jwtbundle.Source interfaces:
|
||||
//
|
||||
// // As an x509bundle.Source...
|
||||
// var source x509bundle.Source = bundle // or set
|
||||
// x509Bundle, err := source.GetX509BundleForTrustDomain(td)
|
||||
//
|
||||
// // As a jwtbundle.Source...
|
||||
// var source jwtbundle.Source = bundle // or set
|
||||
// jwtBundle, err := source.GetJWTBundleForTrustDomain(td)
|
||||
package spiffebundle
|
||||
135
vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/set.go
generated
vendored
Normal file
135
vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/set.go
generated
vendored
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
package spiffebundle
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/spiffe/go-spiffe/v2/bundle/jwtbundle"
|
||||
"github.com/spiffe/go-spiffe/v2/bundle/x509bundle"
|
||||
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||
)
|
||||
|
||||
// Set is a set of bundles, keyed by trust domain.
|
||||
type Set struct {
|
||||
mtx sync.RWMutex
|
||||
bundles map[spiffeid.TrustDomain]*Bundle
|
||||
}
|
||||
|
||||
// NewSet creates a new set initialized with the given bundles.
|
||||
func NewSet(bundles ...*Bundle) *Set {
|
||||
bundlesMap := make(map[spiffeid.TrustDomain]*Bundle)
|
||||
|
||||
for _, b := range bundles {
|
||||
if b != nil {
|
||||
bundlesMap[b.trustDomain] = b
|
||||
}
|
||||
}
|
||||
|
||||
return &Set{
|
||||
bundles: bundlesMap,
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds a new bundle into the set. If a bundle already exists for the
|
||||
// trust domain, the existing bundle is replaced.
|
||||
func (s *Set) Add(bundle *Bundle) {
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
|
||||
if bundle != nil {
|
||||
s.bundles[bundle.trustDomain] = bundle
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes the bundle for the given trust domain.
|
||||
func (s *Set) Remove(trustDomain spiffeid.TrustDomain) {
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
|
||||
delete(s.bundles, trustDomain)
|
||||
}
|
||||
|
||||
// Has returns true if there is a bundle for the given trust domain.
|
||||
func (s *Set) Has(trustDomain spiffeid.TrustDomain) bool {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
_, ok := s.bundles[trustDomain]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Get returns a bundle for the given trust domain. If the bundle is in the set
|
||||
// it is returned and the boolean is true. Otherwise, the returned value is
|
||||
// nil and the boolean is false.
|
||||
func (s *Set) Get(trustDomain spiffeid.TrustDomain) (*Bundle, bool) {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
bundle, ok := s.bundles[trustDomain]
|
||||
return bundle, ok
|
||||
}
|
||||
|
||||
// Bundles returns the bundles in the set sorted by trust domain.
|
||||
func (s *Set) Bundles() []*Bundle {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
out := make([]*Bundle, 0, len(s.bundles))
|
||||
for _, bundle := range s.bundles {
|
||||
out = append(out, bundle)
|
||||
}
|
||||
sort.Slice(out, func(a, b int) bool {
|
||||
return out[a].TrustDomain().Compare(out[b].TrustDomain()) < 0
|
||||
})
|
||||
return out
|
||||
}
|
||||
|
||||
// Len returns the number of bundles in the set.
|
||||
func (s *Set) Len() int {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
return len(s.bundles)
|
||||
}
|
||||
|
||||
// GetBundleForTrustDomain returns the SPIFFE bundle for the given trust
|
||||
// domain. It implements the Source interface.
|
||||
func (s *Set) GetBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
bundle, ok := s.bundles[trustDomain]
|
||||
if !ok {
|
||||
return nil, spiffebundleErr.New("no SPIFFE bundle for trust domain %q", trustDomain)
|
||||
}
|
||||
|
||||
return bundle, nil
|
||||
}
|
||||
|
||||
// GetX509BundleForTrustDomain returns the X.509 bundle for the given trust
|
||||
// domain. It implements the x509bundle.Source interface.
|
||||
func (s *Set) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*x509bundle.Bundle, error) {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
bundle, ok := s.bundles[trustDomain]
|
||||
if !ok {
|
||||
return nil, spiffebundleErr.New("no X.509 bundle for trust domain %q", trustDomain)
|
||||
}
|
||||
|
||||
return bundle.X509Bundle(), nil
|
||||
}
|
||||
|
||||
// GetJWTBundleForTrustDomain returns the JWT bundle for the given trust
|
||||
// domain. It implements the jwtbundle.Source interface.
|
||||
func (s *Set) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*jwtbundle.Bundle, error) {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
bundle, ok := s.bundles[trustDomain]
|
||||
if !ok {
|
||||
return nil, spiffebundleErr.New("no JWT bundle for trust domain %q", trustDomain)
|
||||
}
|
||||
|
||||
return bundle.JWTBundle(), nil
|
||||
}
|
||||
10
vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/source.go
generated
vendored
Normal file
10
vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/source.go
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package spiffebundle
|
||||
|
||||
import "github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||
|
||||
// Source represents a source of SPIFFE bundles keyed by trust domain.
|
||||
type Source interface {
|
||||
// GetBundleForTrustDomain returns the SPIFFE bundle for the given trust
|
||||
// domain.
|
||||
GetBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error)
|
||||
}
|
||||
202
vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/bundle.go
generated
vendored
Normal file
202
vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/bundle.go
generated
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
package x509bundle
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/spiffe/go-spiffe/v2/internal/pemutil"
|
||||
"github.com/spiffe/go-spiffe/v2/internal/x509util"
|
||||
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||
"github.com/zeebo/errs"
|
||||
)
|
||||
|
||||
var x509bundleErr = errs.Class("x509bundle")
|
||||
|
||||
// Bundle is a collection of trusted X.509 authorities for a trust domain.
|
||||
type Bundle struct {
|
||||
trustDomain spiffeid.TrustDomain
|
||||
|
||||
mtx sync.RWMutex
|
||||
x509Authorities []*x509.Certificate
|
||||
}
|
||||
|
||||
// New creates a new bundle.
|
||||
func New(trustDomain spiffeid.TrustDomain) *Bundle {
|
||||
return &Bundle{
|
||||
trustDomain: trustDomain,
|
||||
}
|
||||
}
|
||||
|
||||
// FromX509Authorities creates a bundle from X.509 certificates.
|
||||
func FromX509Authorities(trustDomain spiffeid.TrustDomain, authorities []*x509.Certificate) *Bundle {
|
||||
return &Bundle{
|
||||
trustDomain: trustDomain,
|
||||
x509Authorities: x509util.CopyX509Authorities(authorities),
|
||||
}
|
||||
}
|
||||
|
||||
// Load loads a bundle from a file on disk. The file must contain PEM-encoded
|
||||
// certificate blocks.
|
||||
func Load(trustDomain spiffeid.TrustDomain, path string) (*Bundle, error) {
|
||||
fileBytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, x509bundleErr.New("unable to load X.509 bundle file: %w", err)
|
||||
}
|
||||
|
||||
return Parse(trustDomain, fileBytes)
|
||||
}
|
||||
|
||||
// Read decodes a bundle from a reader. The contents must be PEM-encoded
|
||||
// certificate blocks.
|
||||
func Read(trustDomain spiffeid.TrustDomain, r io.Reader) (*Bundle, error) {
|
||||
b, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, x509bundleErr.New("unable to read X.509 bundle: %v", err)
|
||||
}
|
||||
|
||||
return Parse(trustDomain, b)
|
||||
}
|
||||
|
||||
// Parse parses a bundle from bytes. The data must be PEM-encoded certificate
|
||||
// blocks.
|
||||
func Parse(trustDomain spiffeid.TrustDomain, b []byte) (*Bundle, error) {
|
||||
bundle := New(trustDomain)
|
||||
if len(b) == 0 {
|
||||
return bundle, nil
|
||||
}
|
||||
|
||||
certs, err := pemutil.ParseCertificates(b)
|
||||
if err != nil {
|
||||
return nil, x509bundleErr.New("cannot parse certificate: %v", err)
|
||||
}
|
||||
for _, cert := range certs {
|
||||
bundle.AddX509Authority(cert)
|
||||
}
|
||||
return bundle, nil
|
||||
}
|
||||
|
||||
// ParseRaw parses a bundle from bytes. The certificate must be ASN.1 DER (concatenated
|
||||
// with no intermediate padding if there are more than one certificate)
|
||||
func ParseRaw(trustDomain spiffeid.TrustDomain, b []byte) (*Bundle, error) {
|
||||
bundle := New(trustDomain)
|
||||
if len(b) == 0 {
|
||||
return bundle, nil
|
||||
}
|
||||
|
||||
certs, err := x509.ParseCertificates(b)
|
||||
if err != nil {
|
||||
return nil, x509bundleErr.New("cannot parse certificate: %v", err)
|
||||
}
|
||||
for _, cert := range certs {
|
||||
bundle.AddX509Authority(cert)
|
||||
}
|
||||
return bundle, nil
|
||||
}
|
||||
|
||||
// TrustDomain returns the trust domain that the bundle belongs to.
|
||||
func (b *Bundle) TrustDomain() spiffeid.TrustDomain {
|
||||
return b.trustDomain
|
||||
}
|
||||
|
||||
// X509Authorities returns the X.509 x509Authorities in the bundle.
|
||||
func (b *Bundle) X509Authorities() []*x509.Certificate {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
return x509util.CopyX509Authorities(b.x509Authorities)
|
||||
}
|
||||
|
||||
// AddX509Authority adds an X.509 authority to the bundle. If the authority already
|
||||
// exists in the bundle, the contents of the bundle will remain unchanged.
|
||||
func (b *Bundle) AddX509Authority(x509Authority *x509.Certificate) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
for _, r := range b.x509Authorities {
|
||||
if r.Equal(x509Authority) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
b.x509Authorities = append(b.x509Authorities, x509Authority)
|
||||
}
|
||||
|
||||
// RemoveX509Authority removes an X.509 authority from the bundle.
|
||||
func (b *Bundle) RemoveX509Authority(x509Authority *x509.Certificate) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
for i, r := range b.x509Authorities {
|
||||
if r.Equal(x509Authority) {
|
||||
// remove element from slice
|
||||
b.x509Authorities = append(b.x509Authorities[:i], b.x509Authorities[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HasX509Authority checks if the given X.509 authority exists in the bundle.
|
||||
func (b *Bundle) HasX509Authority(x509Authority *x509.Certificate) bool {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
for _, r := range b.x509Authorities {
|
||||
if r.Equal(x509Authority) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SetX509Authorities sets the X.509 authorities in the bundle.
|
||||
func (b *Bundle) SetX509Authorities(x509Authorities []*x509.Certificate) {
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
b.x509Authorities = x509util.CopyX509Authorities(x509Authorities)
|
||||
}
|
||||
|
||||
// Empty returns true if the bundle has no X.509 x509Authorities.
|
||||
func (b *Bundle) Empty() bool {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
return len(b.x509Authorities) == 0
|
||||
}
|
||||
|
||||
// Marshal marshals the X.509 bundle into PEM-encoded certificate blocks.
|
||||
func (b *Bundle) Marshal() ([]byte, error) {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
return pemutil.EncodeCertificates(b.x509Authorities), nil
|
||||
}
|
||||
|
||||
// Equal compares the bundle for equality against the given bundle.
|
||||
func (b *Bundle) Equal(other *Bundle) bool {
|
||||
if b == nil || other == nil {
|
||||
return b == other
|
||||
}
|
||||
|
||||
return b.trustDomain == other.trustDomain &&
|
||||
x509util.CertsEqual(b.x509Authorities, other.x509Authorities)
|
||||
}
|
||||
|
||||
// Clone clones the bundle.
|
||||
func (b *Bundle) Clone() *Bundle {
|
||||
b.mtx.RLock()
|
||||
defer b.mtx.RUnlock()
|
||||
|
||||
return FromX509Authorities(b.trustDomain, b.x509Authorities)
|
||||
}
|
||||
|
||||
// GetX509BundleForTrustDomain returns the X.509 bundle for the given trust
|
||||
// domain. It implements the Source interface. An error will be
|
||||
// returned if the trust domain does not match that of the bundle.
|
||||
func (b *Bundle) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
|
||||
if b.trustDomain != trustDomain {
|
||||
return nil, x509bundleErr.New("no X.509 bundle found for trust domain: %q", trustDomain)
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
42
vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/doc.go
generated
vendored
Normal file
42
vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Package x509bundle provides X.509 bundle related functionality.
|
||||
//
|
||||
// A bundle represents a collection of X.509 authorities, i.e., those that
|
||||
// are used to authenticate SPIFFE X509-SVIDs.
|
||||
//
|
||||
// You can create a new bundle for a specific trust domain:
|
||||
//
|
||||
// td := spiffeid.RequireTrustDomainFromString("example.org")
|
||||
// bundle := x509bundle.New(td)
|
||||
//
|
||||
// Or you can load it from disk:
|
||||
//
|
||||
// td := spiffeid.RequireTrustDomainFromString("example.org")
|
||||
// bundle := x509bundle.Load(td, "bundle.pem")
|
||||
//
|
||||
// The bundle can be initialized with X.509 authorities:
|
||||
//
|
||||
// td := spiffeid.RequireTrustDomainFromString("example.org")
|
||||
// var x509Authorities []*x509.Certificate = ...
|
||||
// bundle := x509bundle.FromX509Authorities(td, x509Authorities)
|
||||
//
|
||||
// In addition, you can add X.509 authorities to the bundle:
|
||||
//
|
||||
// var x509CA *x509.Certificate = ...
|
||||
// bundle.AddX509Authority(x509CA)
|
||||
//
|
||||
// Bundles can be organized into a set, keyed by trust domain:
|
||||
//
|
||||
// set := x509bundle.NewSet()
|
||||
// set.Add(bundle)
|
||||
//
|
||||
// A Source is source of X.509 bundles for a trust domain. Both the Bundle
|
||||
// and Set types implement Source:
|
||||
//
|
||||
// // Initialize the source from a bundle or set
|
||||
// var source x509bundle.Source = bundle
|
||||
// // ... or ...
|
||||
// var source x509bundle.Source = set
|
||||
//
|
||||
// // Use the source to query for bundles by trust domain
|
||||
// bundle, err := source.GetX509BundleForTrustDomain(td)
|
||||
package x509bundle
|
||||
105
vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/set.go
generated
vendored
Normal file
105
vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/set.go
generated
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package x509bundle
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||
)
|
||||
|
||||
// Set is a set of bundles, keyed by trust domain.
|
||||
type Set struct {
|
||||
mtx sync.RWMutex
|
||||
bundles map[spiffeid.TrustDomain]*Bundle
|
||||
}
|
||||
|
||||
// NewSet creates a new set initialized with the given bundles.
|
||||
func NewSet(bundles ...*Bundle) *Set {
|
||||
bundlesMap := make(map[spiffeid.TrustDomain]*Bundle)
|
||||
|
||||
for _, b := range bundles {
|
||||
if b != nil {
|
||||
bundlesMap[b.trustDomain] = b
|
||||
}
|
||||
}
|
||||
|
||||
return &Set{
|
||||
bundles: bundlesMap,
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds a new bundle into the set. If a bundle already exists for the
|
||||
// trust domain, the existing bundle is replaced.
|
||||
func (s *Set) Add(bundle *Bundle) {
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
|
||||
if bundle != nil {
|
||||
s.bundles[bundle.trustDomain] = bundle
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes the bundle for the given trust domain.
|
||||
func (s *Set) Remove(trustDomain spiffeid.TrustDomain) {
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
|
||||
delete(s.bundles, trustDomain)
|
||||
}
|
||||
|
||||
// Has returns true if there is a bundle for the given trust domain.
|
||||
func (s *Set) Has(trustDomain spiffeid.TrustDomain) bool {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
_, ok := s.bundles[trustDomain]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Get returns a bundle for the given trust domain. If the bundle is in the set
|
||||
// it is returned and the boolean is true. Otherwise, the returned value is
|
||||
// nil and the boolean is false.
|
||||
func (s *Set) Get(trustDomain spiffeid.TrustDomain) (*Bundle, bool) {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
bundle, ok := s.bundles[trustDomain]
|
||||
return bundle, ok
|
||||
}
|
||||
|
||||
// Bundles returns the bundles in the set sorted by trust domain.
|
||||
func (s *Set) Bundles() []*Bundle {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
out := make([]*Bundle, 0, len(s.bundles))
|
||||
for _, bundle := range s.bundles {
|
||||
out = append(out, bundle)
|
||||
}
|
||||
sort.Slice(out, func(a, b int) bool {
|
||||
return out[a].TrustDomain().Compare(out[b].TrustDomain()) < 0
|
||||
})
|
||||
return out
|
||||
}
|
||||
|
||||
// Len returns the number of bundles in the set.
|
||||
func (s *Set) Len() int {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
return len(s.bundles)
|
||||
}
|
||||
|
||||
// GetX509BundleForTrustDomain returns the X.509 bundle for the given trust
|
||||
// domain. It implements the Source interface.
|
||||
func (s *Set) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
|
||||
bundle, ok := s.bundles[trustDomain]
|
||||
if !ok {
|
||||
return nil, x509bundleErr.New("no X.509 bundle for trust domain %q", trustDomain)
|
||||
}
|
||||
|
||||
return bundle, nil
|
||||
}
|
||||
12
vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/source.go
generated
vendored
Normal file
12
vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/source.go
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package x509bundle
|
||||
|
||||
import (
|
||||
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||
)
|
||||
|
||||
// Source represents a source of X.509 bundles keyed by trust domain.
|
||||
type Source interface {
|
||||
// GetX509BundleForTrustDomain returns the X.509 bundle for the given trust
|
||||
// domain.
|
||||
GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error)
|
||||
}
|
||||
34
vendor/github.com/spiffe/go-spiffe/v2/internal/cryptoutil/keys.go
generated
vendored
Normal file
34
vendor/github.com/spiffe/go-spiffe/v2/internal/cryptoutil/keys.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package cryptoutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func PublicKeyEqual(a, b crypto.PublicKey) (bool, error) {
|
||||
switch a := a.(type) {
|
||||
case *rsa.PublicKey:
|
||||
rsaPublicKey, ok := b.(*rsa.PublicKey)
|
||||
return ok && RSAPublicKeyEqual(a, rsaPublicKey), nil
|
||||
case *ecdsa.PublicKey:
|
||||
ecdsaPublicKey, ok := b.(*ecdsa.PublicKey)
|
||||
return ok && ECDSAPublicKeyEqual(a, ecdsaPublicKey), nil
|
||||
case ed25519.PublicKey:
|
||||
ed25519PublicKey, ok := b.(ed25519.PublicKey)
|
||||
return ok && bytes.Equal(a, ed25519PublicKey), nil
|
||||
default:
|
||||
return false, fmt.Errorf("unsupported public key type %T", a)
|
||||
}
|
||||
}
|
||||
|
||||
func RSAPublicKeyEqual(a, b *rsa.PublicKey) bool {
|
||||
return a.E == b.E && a.N.Cmp(b.N) == 0
|
||||
}
|
||||
|
||||
func ECDSAPublicKeyEqual(a, b *ecdsa.PublicKey) bool {
|
||||
return a.Curve == b.Curve && a.X.Cmp(b.X) == 0 && a.Y.Cmp(b.Y) == 0
|
||||
}
|
||||
34
vendor/github.com/spiffe/go-spiffe/v2/internal/jwtutil/util.go
generated
vendored
Normal file
34
vendor/github.com/spiffe/go-spiffe/v2/internal/jwtutil/util.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package jwtutil
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
|
||||
"github.com/spiffe/go-spiffe/v2/internal/cryptoutil"
|
||||
)
|
||||
|
||||
// CopyJWTAuthorities copies JWT authorities from a map to a new map.
|
||||
func CopyJWTAuthorities(jwtAuthorities map[string]crypto.PublicKey) map[string]crypto.PublicKey {
|
||||
copiedJWTAuthorities := make(map[string]crypto.PublicKey)
|
||||
for key, jwtAuthority := range jwtAuthorities {
|
||||
copiedJWTAuthorities[key] = jwtAuthority
|
||||
}
|
||||
return copiedJWTAuthorities
|
||||
}
|
||||
|
||||
func JWTAuthoritiesEqual(a, b map[string]crypto.PublicKey) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
for k, pka := range a {
|
||||
pkb, ok := b[k]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if equal, _ := cryptoutil.PublicKeyEqual(pka, pkb); !equal {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
123
vendor/github.com/spiffe/go-spiffe/v2/internal/pemutil/pem.go
generated
vendored
Normal file
123
vendor/github.com/spiffe/go-spiffe/v2/internal/pemutil/pem.go
generated
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
package pemutil
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
certType string = "CERTIFICATE"
|
||||
keyType string = "PRIVATE KEY"
|
||||
)
|
||||
|
||||
func ParseCertificates(certsBytes []byte) ([]*x509.Certificate, error) {
|
||||
objects, err := parseBlocks(certsBytes, certType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certs := []*x509.Certificate{}
|
||||
for _, object := range objects {
|
||||
cert, ok := object.(*x509.Certificate)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected *x509.Certificate; got %T", object)
|
||||
}
|
||||
certs = append(certs, cert)
|
||||
}
|
||||
|
||||
return certs, nil
|
||||
}
|
||||
|
||||
func ParsePrivateKey(keyBytes []byte) (crypto.PrivateKey, error) {
|
||||
objects, err := parseBlocks(keyBytes, keyType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(objects) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
privateKey, ok := objects[0].(crypto.PrivateKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected crypto.PrivateKey; got %T", objects[0])
|
||||
}
|
||||
return privateKey, nil
|
||||
}
|
||||
|
||||
func EncodePKCS8PrivateKey(privateKey interface{}) ([]byte, error) {
|
||||
keyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pem.EncodeToMemory(&pem.Block{
|
||||
Type: keyType,
|
||||
Bytes: keyBytes,
|
||||
}), nil
|
||||
}
|
||||
|
||||
func EncodeCertificates(certificates []*x509.Certificate) []byte {
|
||||
pemBytes := []byte{}
|
||||
for _, cert := range certificates {
|
||||
pemBytes = append(pemBytes, pem.EncodeToMemory(&pem.Block{
|
||||
Type: certType,
|
||||
Bytes: cert.Raw,
|
||||
})...)
|
||||
}
|
||||
return pemBytes
|
||||
}
|
||||
|
||||
func parseBlocks(blocksBytes []byte, expectedType string) ([]interface{}, error) {
|
||||
objects := []interface{}{}
|
||||
var foundBlocks = false
|
||||
for {
|
||||
if len(blocksBytes) == 0 {
|
||||
if len(objects) == 0 && !foundBlocks {
|
||||
return nil, errors.New("no PEM blocks found")
|
||||
}
|
||||
return objects, nil
|
||||
}
|
||||
object, rest, foundBlock, err := parseBlock(blocksBytes, expectedType)
|
||||
blocksBytes = rest
|
||||
if foundBlock {
|
||||
foundBlocks = true
|
||||
}
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, err
|
||||
case object != nil:
|
||||
objects = append(objects, object)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseBlock(pemBytes []byte, pemType string) (interface{}, []byte, bool, error) {
|
||||
pemBlock, rest := pem.Decode(pemBytes)
|
||||
if pemBlock == nil {
|
||||
return nil, nil, false, nil
|
||||
}
|
||||
|
||||
if pemBlock.Type != pemType {
|
||||
return nil, rest, true, nil
|
||||
}
|
||||
|
||||
var object interface{}
|
||||
var err error
|
||||
switch pemType {
|
||||
case certType:
|
||||
object, err = x509.ParseCertificate(pemBlock.Bytes)
|
||||
case keyType:
|
||||
object, err = x509.ParsePKCS8PrivateKey(pemBlock.Bytes)
|
||||
default:
|
||||
err = fmt.Errorf("PEM type not supported: %q", pemType)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, false, err
|
||||
}
|
||||
|
||||
return object, rest, true, nil
|
||||
}
|
||||
53
vendor/github.com/spiffe/go-spiffe/v2/internal/x509util/util.go
generated
vendored
Normal file
53
vendor/github.com/spiffe/go-spiffe/v2/internal/x509util/util.go
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package x509util
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
)
|
||||
|
||||
// NewCertPool returns a new CertPool with the given X.509 certificates
|
||||
func NewCertPool(certs []*x509.Certificate) *x509.CertPool {
|
||||
pool := x509.NewCertPool()
|
||||
for _, cert := range certs {
|
||||
pool.AddCert(cert)
|
||||
}
|
||||
return pool
|
||||
}
|
||||
|
||||
// CopyX509Authorities copies a slice of X.509 certificates to a new slice.
|
||||
func CopyX509Authorities(x509Authorities []*x509.Certificate) []*x509.Certificate {
|
||||
copiedX509Authorities := make([]*x509.Certificate, len(x509Authorities))
|
||||
copy(copiedX509Authorities, x509Authorities)
|
||||
|
||||
return copiedX509Authorities
|
||||
}
|
||||
|
||||
// CertsEqual returns true if the slices of X.509 certificates are equal.
|
||||
func CertsEqual(a, b []*x509.Certificate) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, cert := range a {
|
||||
if !cert.Equal(b[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func RawCertsFromCerts(certs []*x509.Certificate) [][]byte {
|
||||
rawCerts := make([][]byte, 0, len(certs))
|
||||
for _, cert := range certs {
|
||||
rawCerts = append(rawCerts, cert.Raw)
|
||||
}
|
||||
return rawCerts
|
||||
}
|
||||
|
||||
func ConcatRawCertsFromCerts(certs []*x509.Certificate) []byte {
|
||||
var rawCerts []byte
|
||||
for _, cert := range certs {
|
||||
rawCerts = append(rawCerts, cert.Raw...)
|
||||
}
|
||||
return rawCerts
|
||||
}
|
||||
42
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/charset_backcompat_allow.go
generated
vendored
Normal file
42
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/charset_backcompat_allow.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
//go:build spiffeid_charset_backcompat
|
||||
// +build spiffeid_charset_backcompat
|
||||
|
||||
package spiffeid
|
||||
|
||||
func isBackcompatTrustDomainChar(c uint8) bool {
|
||||
if isSubDelim(c) {
|
||||
return true
|
||||
}
|
||||
switch c {
|
||||
// unreserved
|
||||
case '~':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isBackcompatPathChar(c uint8) bool {
|
||||
if isSubDelim(c) {
|
||||
return true
|
||||
}
|
||||
switch c {
|
||||
// unreserved
|
||||
case '~':
|
||||
return true
|
||||
// gen-delims
|
||||
case ':', '[', ']', '@':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isSubDelim(c uint8) bool {
|
||||
switch c {
|
||||
case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
12
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/charset_backcompat_deny.go
generated
vendored
Normal file
12
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/charset_backcompat_deny.go
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
//go:build !spiffeid_charset_backcompat
|
||||
// +build !spiffeid_charset_backcompat
|
||||
|
||||
package spiffeid
|
||||
|
||||
func isBackcompatTrustDomainChar(c uint8) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func isBackcompatPathChar(c uint8) bool {
|
||||
return false
|
||||
}
|
||||
15
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/errors.go
generated
vendored
Normal file
15
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/errors.go
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package spiffeid
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
errBadTrustDomainChar = errors.New("trust domain characters are limited to lowercase letters, numbers, dots, dashes, and underscores")
|
||||
errBadPathSegmentChar = errors.New("path segment characters are limited to letters, numbers, dots, dashes, and underscores")
|
||||
errDotSegment = errors.New("path cannot contain dot segments")
|
||||
errNoLeadingSlash = errors.New("path must have a leading slash")
|
||||
errEmpty = errors.New("cannot be empty")
|
||||
errEmptySegment = errors.New("path cannot contain empty segments")
|
||||
errMissingTrustDomain = errors.New("trust domain is missing")
|
||||
errTrailingSlash = errors.New("path cannot have a trailing slash")
|
||||
errWrongScheme = errors.New("scheme is missing or invalid")
|
||||
)
|
||||
258
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/id.go
generated
vendored
Normal file
258
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/id.go
generated
vendored
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
package spiffeid
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
schemePrefix = "spiffe://"
|
||||
schemePrefixLen = len(schemePrefix)
|
||||
)
|
||||
|
||||
// FromPath returns a new SPIFFE ID in the given trust domain and with the
|
||||
// given path. The supplied path must be a valid absolute path according to the
|
||||
// SPIFFE specification.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#22-path
|
||||
func FromPath(td TrustDomain, path string) (ID, error) {
|
||||
if err := ValidatePath(path); err != nil {
|
||||
return ID{}, err
|
||||
}
|
||||
return makeID(td, path)
|
||||
}
|
||||
|
||||
// FromPathf returns a new SPIFFE ID from the formatted path in the given trust
|
||||
// domain. The formatted path must be a valid absolute path according to the
|
||||
// SPIFFE specification.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#22-path
|
||||
func FromPathf(td TrustDomain, format string, args ...interface{}) (ID, error) {
|
||||
path, err := FormatPath(format, args...)
|
||||
if err != nil {
|
||||
return ID{}, err
|
||||
}
|
||||
return makeID(td, path)
|
||||
}
|
||||
|
||||
// FromSegments returns a new SPIFFE ID in the given trust domain with joined
|
||||
// path segments. The path segments must be valid according to the SPIFFE
|
||||
// specification and must not contain path separators.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#22-path
|
||||
func FromSegments(td TrustDomain, segments ...string) (ID, error) {
|
||||
path, err := JoinPathSegments(segments...)
|
||||
if err != nil {
|
||||
return ID{}, err
|
||||
}
|
||||
return makeID(td, path)
|
||||
}
|
||||
|
||||
// FromString parses a SPIFFE ID from a string.
|
||||
func FromString(id string) (ID, error) {
|
||||
switch {
|
||||
case id == "":
|
||||
return ID{}, errEmpty
|
||||
case !strings.HasPrefix(id, schemePrefix):
|
||||
return ID{}, errWrongScheme
|
||||
}
|
||||
|
||||
pathidx := schemePrefixLen
|
||||
for ; pathidx < len(id); pathidx++ {
|
||||
c := id[pathidx]
|
||||
if c == '/' {
|
||||
break
|
||||
}
|
||||
if !isValidTrustDomainChar(c) {
|
||||
return ID{}, errBadTrustDomainChar
|
||||
}
|
||||
}
|
||||
|
||||
if pathidx == schemePrefixLen {
|
||||
return ID{}, errMissingTrustDomain
|
||||
}
|
||||
|
||||
if err := ValidatePath(id[pathidx:]); err != nil {
|
||||
return ID{}, err
|
||||
}
|
||||
|
||||
return ID{
|
||||
id: id,
|
||||
pathidx: pathidx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FromStringf parses a SPIFFE ID from a formatted string.
|
||||
func FromStringf(format string, args ...interface{}) (ID, error) {
|
||||
return FromString(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// FromURI parses a SPIFFE ID from a URI.
|
||||
func FromURI(uri *url.URL) (ID, error) {
|
||||
return FromString(uri.String())
|
||||
}
|
||||
|
||||
// ID is a SPIFFE ID
|
||||
type ID struct {
|
||||
id string
|
||||
|
||||
// pathidx tracks the index to the beginning of the path inside of id. This
|
||||
// is used when extracting the trust domain or path portions of the id.
|
||||
pathidx int
|
||||
}
|
||||
|
||||
// TrustDomain returns the trust domain of the SPIFFE ID.
|
||||
func (id ID) TrustDomain() TrustDomain {
|
||||
if id.IsZero() {
|
||||
return TrustDomain{}
|
||||
}
|
||||
return TrustDomain{name: id.id[schemePrefixLen:id.pathidx]}
|
||||
}
|
||||
|
||||
// MemberOf returns true if the SPIFFE ID is a member of the given trust domain.
|
||||
func (id ID) MemberOf(td TrustDomain) bool {
|
||||
return id.TrustDomain() == td
|
||||
}
|
||||
|
||||
// Path returns the path of the SPIFFE ID inside the trust domain.
|
||||
func (id ID) Path() string {
|
||||
return id.id[id.pathidx:]
|
||||
}
|
||||
|
||||
// String returns the string representation of the SPIFFE ID, e.g.,
|
||||
// "spiffe://example.org/foo/bar".
|
||||
func (id ID) String() string {
|
||||
return id.id
|
||||
}
|
||||
|
||||
// URL returns a URL for SPIFFE ID.
|
||||
func (id ID) URL() *url.URL {
|
||||
if id.IsZero() {
|
||||
return &url.URL{}
|
||||
}
|
||||
|
||||
return &url.URL{
|
||||
Scheme: "spiffe",
|
||||
Host: id.TrustDomain().String(),
|
||||
Path: id.Path(),
|
||||
}
|
||||
}
|
||||
|
||||
// IsZero returns true if the SPIFFE ID is the zero value.
|
||||
func (id ID) IsZero() bool {
|
||||
return id.id == ""
|
||||
}
|
||||
|
||||
// AppendPath returns an ID with the appended path. It will fail if called on a
|
||||
// zero value. The path to append must be a valid absolute path according to
|
||||
// the SPIFFE specification.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#22-path
|
||||
func (id ID) AppendPath(path string) (ID, error) {
|
||||
if id.IsZero() {
|
||||
return ID{}, errors.New("cannot append path on a zero ID value")
|
||||
}
|
||||
if err := ValidatePath(path); err != nil {
|
||||
return ID{}, err
|
||||
}
|
||||
id.id += path
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// AppendPathf returns an ID with the appended formatted path. It will fail if
|
||||
// called on a zero value. The formatted path must be a valid absolute path
|
||||
// according to the SPIFFE specification.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#22-path
|
||||
func (id ID) AppendPathf(format string, args ...interface{}) (ID, error) {
|
||||
if id.IsZero() {
|
||||
return ID{}, errors.New("cannot append path on a zero ID value")
|
||||
}
|
||||
path, err := FormatPath(format, args...)
|
||||
if err != nil {
|
||||
return ID{}, err
|
||||
}
|
||||
id.id += path
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// AppendSegments returns an ID with the appended joined path segments. It
|
||||
// will fail if called on a zero value. The path segments must be valid
|
||||
// according to the SPIFFE specification and must not contain path separators.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#22-path
|
||||
func (id ID) AppendSegments(segments ...string) (ID, error) {
|
||||
if id.IsZero() {
|
||||
return ID{}, errors.New("cannot append path segments on a zero ID value")
|
||||
}
|
||||
path, err := JoinPathSegments(segments...)
|
||||
if err != nil {
|
||||
return ID{}, err
|
||||
}
|
||||
id.id += path
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// Replace path returns an ID with the given path in the same trust domain. It
|
||||
// will fail if called on a zero value. The given path must be a valid absolute
|
||||
// path according to the SPIFFE specification.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#22-path
|
||||
func (id ID) ReplacePath(path string) (ID, error) {
|
||||
if id.IsZero() {
|
||||
return ID{}, errors.New("cannot replace path on a zero ID value")
|
||||
}
|
||||
return FromPath(id.TrustDomain(), path)
|
||||
}
|
||||
|
||||
// ReplacePathf returns an ID with the formatted path in the same trust domain.
|
||||
// It will fail if called on a zero value. The formatted path must be a valid
|
||||
// absolute path according to the SPIFFE specification.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#22-path
|
||||
func (id ID) ReplacePathf(format string, args ...interface{}) (ID, error) {
|
||||
if id.IsZero() {
|
||||
return ID{}, errors.New("cannot replace path on a zero ID value")
|
||||
}
|
||||
return FromPathf(id.TrustDomain(), format, args...)
|
||||
}
|
||||
|
||||
// ReplaceSegments returns an ID with the joined path segments in the same
|
||||
// trust domain. It will fail if called on a zero value. The path segments must
|
||||
// be valid according to the SPIFFE specification and must not contain path
|
||||
// separators.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#22-path
|
||||
func (id ID) ReplaceSegments(segments ...string) (ID, error) {
|
||||
if id.IsZero() {
|
||||
return ID{}, errors.New("cannot replace path segments on a zero ID value")
|
||||
}
|
||||
return FromSegments(id.TrustDomain(), segments...)
|
||||
}
|
||||
|
||||
// MarshalText returns a text representation of the ID. If the ID is the zero
|
||||
// value, nil is returned.
|
||||
func (id ID) MarshalText() ([]byte, error) {
|
||||
if id.IsZero() {
|
||||
return nil, nil
|
||||
}
|
||||
return []byte(id.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText decodes a text representation of the ID. If the text is empty,
|
||||
// the ID is set to the zero value.
|
||||
func (id *ID) UnmarshalText(text []byte) error {
|
||||
if len(text) == 0 {
|
||||
*id = ID{}
|
||||
return nil
|
||||
}
|
||||
unmarshaled, err := FromString(string(text))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*id = unmarshaled
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeID(td TrustDomain, path string) (ID, error) {
|
||||
if td.IsZero() {
|
||||
return ID{}, errors.New("trust domain is empty")
|
||||
}
|
||||
return ID{
|
||||
id: schemePrefix + td.name + path,
|
||||
pathidx: schemePrefixLen + len(td.name),
|
||||
}, nil
|
||||
}
|
||||
47
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/match.go
generated
vendored
Normal file
47
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/match.go
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package spiffeid
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Matcher is used to match a SPIFFE ID.
|
||||
type Matcher func(ID) error
|
||||
|
||||
// MatchAny matches any SPIFFE ID.
|
||||
func MatchAny() Matcher {
|
||||
return Matcher(func(actual ID) error {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// MatchID matches a specific SPIFFE ID.
|
||||
func MatchID(expected ID) Matcher {
|
||||
return Matcher(func(actual ID) error {
|
||||
if actual != expected {
|
||||
return fmt.Errorf("unexpected ID %q", actual)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// MatchOneOf matches any SPIFFE ID in the given list of IDs.
|
||||
func MatchOneOf(expected ...ID) Matcher {
|
||||
set := make(map[ID]struct{})
|
||||
for _, id := range expected {
|
||||
set[id] = struct{}{}
|
||||
}
|
||||
return Matcher(func(actual ID) error {
|
||||
if _, ok := set[actual]; !ok {
|
||||
return fmt.Errorf("unexpected ID %q", actual)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// MatchMemberOf matches any SPIFFE ID in the given trust domain.
|
||||
func MatchMemberOf(expected TrustDomain) Matcher {
|
||||
return Matcher(func(actual ID) error {
|
||||
if !actual.MemberOf(expected) {
|
||||
return fmt.Errorf("unexpected trust domain %q", actual.TrustDomain())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
107
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/path.go
generated
vendored
Normal file
107
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/path.go
generated
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
package spiffeid
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FormatPath builds a path by formatting the given formatting string with
|
||||
// the given args (i.e. fmt.Sprintf). The resulting path must be valid or
|
||||
// an error is returned.
|
||||
func FormatPath(format string, args ...interface{}) (string, error) {
|
||||
path := fmt.Sprintf(format, args...)
|
||||
if err := ValidatePath(path); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// JoinPathSegments joins one or more path segments into a slash separated
|
||||
// path. Segments cannot contain slashes. The resulting path must be valid or
|
||||
// an error is returned. If no segments are provided, an empty string is
|
||||
// returned.
|
||||
func JoinPathSegments(segments ...string) (string, error) {
|
||||
var builder strings.Builder
|
||||
for _, segment := range segments {
|
||||
if err := ValidatePathSegment(segment); err != nil {
|
||||
return "", err
|
||||
}
|
||||
builder.WriteByte('/')
|
||||
builder.WriteString(segment)
|
||||
}
|
||||
return builder.String(), nil
|
||||
}
|
||||
|
||||
// ValidatePath validates that a path string is a conformant path for a SPIFFE
|
||||
// ID.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#22-path
|
||||
func ValidatePath(path string) error {
|
||||
switch {
|
||||
case path == "":
|
||||
return nil
|
||||
case path[0] != '/':
|
||||
return errNoLeadingSlash
|
||||
}
|
||||
|
||||
segmentStart := 0
|
||||
segmentEnd := 0
|
||||
for ; segmentEnd < len(path); segmentEnd++ {
|
||||
c := path[segmentEnd]
|
||||
if c == '/' {
|
||||
switch path[segmentStart:segmentEnd] {
|
||||
case "/":
|
||||
return errEmptySegment
|
||||
case "/.", "/..":
|
||||
return errDotSegment
|
||||
}
|
||||
segmentStart = segmentEnd
|
||||
continue
|
||||
}
|
||||
if !isValidPathSegmentChar(c) {
|
||||
return errBadPathSegmentChar
|
||||
}
|
||||
}
|
||||
|
||||
switch path[segmentStart:segmentEnd] {
|
||||
case "/":
|
||||
return errTrailingSlash
|
||||
case "/.", "/..":
|
||||
return errDotSegment
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidatePathSegment validates that a string is a conformant segment for
|
||||
// inclusion in the path for a SPIFFE ID.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#22-path
|
||||
func ValidatePathSegment(segment string) error {
|
||||
switch segment {
|
||||
case "":
|
||||
return errEmptySegment
|
||||
case ".", "..":
|
||||
return errDotSegment
|
||||
}
|
||||
for i := 0; i < len(segment); i++ {
|
||||
if !isValidPathSegmentChar(segment[i]) {
|
||||
return errBadPathSegmentChar
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isValidPathSegmentChar(c uint8) bool {
|
||||
switch {
|
||||
case c >= 'a' && c <= 'z':
|
||||
return true
|
||||
case c >= 'A' && c <= 'Z':
|
||||
return true
|
||||
case c >= '0' && c <= '9':
|
||||
return true
|
||||
case c == '-', c == '.', c == '_':
|
||||
return true
|
||||
case isBackcompatPathChar(c):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
103
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/require.go
generated
vendored
Normal file
103
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/require.go
generated
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
package spiffeid
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// RequireFromPath is similar to FromPath except that instead of returning an
|
||||
// error on malformed input, it panics. It should only be used when the input
|
||||
// is statically verifiable.
|
||||
func RequireFromPath(td TrustDomain, path string) ID {
|
||||
id, err := FromPath(td, path)
|
||||
panicOnErr(err)
|
||||
return id
|
||||
}
|
||||
|
||||
// RequireFromPathf is similar to FromPathf except that instead of returning an
|
||||
// error on malformed input, it panics. It should only be used when the input
|
||||
// is statically verifiable.
|
||||
func RequireFromPathf(td TrustDomain, format string, args ...interface{}) ID {
|
||||
id, err := FromPathf(td, format, args...)
|
||||
panicOnErr(err)
|
||||
return id
|
||||
}
|
||||
|
||||
// RequireFromSegments is similar to FromSegments except that instead of
|
||||
// returning an error on malformed input, it panics. It should only be used
|
||||
// when the input is statically verifiable.
|
||||
func RequireFromSegments(td TrustDomain, segments ...string) ID {
|
||||
id, err := FromSegments(td, segments...)
|
||||
panicOnErr(err)
|
||||
return id
|
||||
}
|
||||
|
||||
// RequireFromString is similar to FromString except that instead of returning
|
||||
// an error on malformed input, it panics. It should only be used when the
|
||||
// input is statically verifiable.
|
||||
func RequireFromString(s string) ID {
|
||||
id, err := FromString(s)
|
||||
panicOnErr(err)
|
||||
return id
|
||||
}
|
||||
|
||||
// RequireFromStringf is similar to FromStringf except that instead of
|
||||
// returning an error on malformed input, it panics. It should only be used
|
||||
// when the input is statically verifiable.
|
||||
func RequireFromStringf(format string, args ...interface{}) ID {
|
||||
id, err := FromStringf(format, args...)
|
||||
panicOnErr(err)
|
||||
return id
|
||||
}
|
||||
|
||||
// RequireFromURI is similar to FromURI except that instead of returning an
|
||||
// error on malformed input, it panics. It should only be used when the input is
|
||||
// statically verifiable.
|
||||
func RequireFromURI(uri *url.URL) ID {
|
||||
id, err := FromURI(uri)
|
||||
panicOnErr(err)
|
||||
return id
|
||||
}
|
||||
|
||||
// RequireTrustDomainFromString is similar to TrustDomainFromString except that
|
||||
// instead of returning an error on malformed input, it panics. It should only
|
||||
// be used when the input is statically verifiable.
|
||||
func RequireTrustDomainFromString(s string) TrustDomain {
|
||||
td, err := TrustDomainFromString(s)
|
||||
panicOnErr(err)
|
||||
return td
|
||||
}
|
||||
|
||||
// RequireTrustDomainFromURI is similar to TrustDomainFromURI except that
|
||||
// instead of returning an error on malformed input, it panics. It should only
|
||||
// be used when the input is statically verifiable.
|
||||
func RequireTrustDomainFromURI(uri *url.URL) TrustDomain {
|
||||
td, err := TrustDomainFromURI(uri)
|
||||
panicOnErr(err)
|
||||
return td
|
||||
}
|
||||
|
||||
// RequireFormatPath builds a path by formatting the given formatting string
|
||||
// with the given args (i.e. fmt.Sprintf). The resulting path must be valid or
|
||||
// the function panics. It should only be used when the input is statically
|
||||
// verifiable.
|
||||
func RequireFormatPath(format string, args ...interface{}) string {
|
||||
path, err := FormatPath(format, args...)
|
||||
panicOnErr(err)
|
||||
return path
|
||||
}
|
||||
|
||||
// RequireJoinPathSegments joins one or more path segments into a slash separated
|
||||
// path. Segments cannot contain slashes. The resulting path must be valid or
|
||||
// the function panics. It should only be used when the input is statically
|
||||
// verifiable.
|
||||
func RequireJoinPathSegments(segments ...string) string {
|
||||
path, err := JoinPathSegments(segments...)
|
||||
panicOnErr(err)
|
||||
return path
|
||||
}
|
||||
|
||||
func panicOnErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
127
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/trustdomain.go
generated
vendored
Normal file
127
vendor/github.com/spiffe/go-spiffe/v2/spiffeid/trustdomain.go
generated
vendored
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package spiffeid
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TrustDomain represents the trust domain portion of a SPIFFE ID (e.g.
|
||||
// example.org).
|
||||
type TrustDomain struct {
|
||||
name string
|
||||
}
|
||||
|
||||
// TrustDomainFromString returns a new TrustDomain from a string. The string
|
||||
// can either be a trust domain name (e.g. example.org), or a valid SPIFFE ID
|
||||
// URI (e.g. spiffe://example.org), otherwise an error is returned.
|
||||
// See https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE-ID.md#21-trust-domain.
|
||||
func TrustDomainFromString(idOrName string) (TrustDomain, error) {
|
||||
switch {
|
||||
case idOrName == "":
|
||||
return TrustDomain{}, errMissingTrustDomain
|
||||
case strings.Contains(idOrName, ":/"):
|
||||
// The ID looks like it has something like a scheme separator, let's
|
||||
// try to parse as an ID. We use :/ instead of :// since the
|
||||
// diagnostics are better for a bad input like spiffe:/trustdomain.
|
||||
id, err := FromString(idOrName)
|
||||
if err != nil {
|
||||
return TrustDomain{}, err
|
||||
}
|
||||
return id.TrustDomain(), nil
|
||||
default:
|
||||
for i := 0; i < len(idOrName); i++ {
|
||||
if !isValidTrustDomainChar(idOrName[i]) {
|
||||
return TrustDomain{}, errBadTrustDomainChar
|
||||
}
|
||||
}
|
||||
return TrustDomain{name: idOrName}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// TrustDomainFromURI returns a new TrustDomain from a URI. The URI must be a
|
||||
// valid SPIFFE ID (see FromURI) or an error is returned. The trust domain is
|
||||
// extracted from the host field.
|
||||
func TrustDomainFromURI(uri *url.URL) (TrustDomain, error) {
|
||||
id, err := FromURI(uri)
|
||||
if err != nil {
|
||||
return TrustDomain{}, err
|
||||
}
|
||||
|
||||
return id.TrustDomain(), nil
|
||||
}
|
||||
|
||||
// Name returns the trust domain name as a string, e.g. example.org.
|
||||
func (td TrustDomain) Name() string {
|
||||
return td.name
|
||||
}
|
||||
|
||||
// String returns the trust domain name as a string, e.g. example.org.
|
||||
func (td TrustDomain) String() string {
|
||||
return td.name
|
||||
}
|
||||
|
||||
// ID returns the SPIFFE ID of the trust domain.
|
||||
func (td TrustDomain) ID() ID {
|
||||
if id, err := makeID(td, ""); err == nil {
|
||||
return id
|
||||
}
|
||||
return ID{}
|
||||
}
|
||||
|
||||
// IDString returns a string representation of the the SPIFFE ID of the trust
|
||||
// domain, e.g. "spiffe://example.org".
|
||||
func (td TrustDomain) IDString() string {
|
||||
return td.ID().String()
|
||||
}
|
||||
|
||||
// IsZero returns true if the trust domain is the zero value.
|
||||
func (td TrustDomain) IsZero() bool {
|
||||
return td.name == ""
|
||||
}
|
||||
|
||||
// Compare returns an integer comparing the trust domain to another
|
||||
// lexicographically. The result will be 0 if td==other, -1 if td < other, and
|
||||
// +1 if td > other.
|
||||
func (td TrustDomain) Compare(other TrustDomain) int {
|
||||
return strings.Compare(td.name, other.name)
|
||||
}
|
||||
|
||||
// MarshalText returns a text representation of the trust domain. If the trust
|
||||
// domain is the zero value, nil is returned.
|
||||
func (td TrustDomain) MarshalText() ([]byte, error) {
|
||||
if td.IsZero() {
|
||||
return nil, nil
|
||||
}
|
||||
return []byte(td.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText decodes a text representation of the trust domain. If the text
|
||||
// is empty, the trust domain is set to the zero value.
|
||||
func (td *TrustDomain) UnmarshalText(text []byte) error {
|
||||
if len(text) == 0 {
|
||||
*td = TrustDomain{}
|
||||
return nil
|
||||
}
|
||||
|
||||
unmarshaled, err := TrustDomainFromString(string(text))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*td = unmarshaled
|
||||
return nil
|
||||
}
|
||||
|
||||
func isValidTrustDomainChar(c uint8) bool {
|
||||
switch {
|
||||
case c >= 'a' && c <= 'z':
|
||||
return true
|
||||
case c >= '0' && c <= '9':
|
||||
return true
|
||||
case c == '-', c == '.', c == '_':
|
||||
return true
|
||||
case isBackcompatTrustDomainChar(c):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue