Merge branch 'opensource-master' into add-elasticsearch-auth

This commit is contained in:
Becca Petrin 2019-06-17 11:12:51 -07:00
commit 4ebfba2c2b
106 changed files with 4154 additions and 1689 deletions

1
.circleci/.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
config.yml linguist-generated

1
.circleci/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.tmp/

47
.circleci/Makefile Normal file
View file

@ -0,0 +1,47 @@
.PHONY: default
default: ci-config
.PHONY: check-circleci-installed
check-circleci-installed:
@command -v circleci > /dev/null 2>&1 || { \
echo "Please install circleci-cli, see https://circleci.com/docs/2.0/local-cli/#installation"; \
exit 1; }
.PHONY: ci-config
# ci-config is just an alias for config.yml for now
ci-config: config.yml
CONFIG_SOURCE_DIR := config/
CONFIG_SOURCE := $(shell find config/) Makefile
OUT := config.yml
TMP := .tmp/config.yml.tmp
CONFIG_21 := .tmp/config.2.1.tmp
# Ensure the .tmp dir exists.
$(shell [ -d .tmp ] || mkdir .tmp)
define GEN_CONFIG
@circleci config pack $(CONFIG_SOURCE_DIR) > $(CONFIG_21)
@echo "### Generated by 'make ci-config' do not manually edit this file." > $@
@circleci config process $(CONFIG_21) >> $@
endef
$(OUT): $(CONFIG_SOURCE) check-circleci-installed
$(GEN_CONFIG)
@echo "$@ updated"
$(TMP): $(CONFIG_SOURCE) check-circleci-installed
$(GEN_CONFIG)
.PHONY: config-up-to-date
config-up-to-date: $(TMP) # Note this must not depend on $(OUT)!
@if diff config.yml $<; then \
echo "Generated $(OUT) is up to date!"; \
else \
echo "Generated $(OUT) is out of date, run make ci-config to update."; \
exit 1; \
fi
.PHONY: ci-verify
ci-verify: config-up-to-date
@circleci config validate config.yml

117
.circleci/README.md Normal file
View file

@ -0,0 +1,117 @@
# CircleCI config
This directory contains both the source code (under `./config/`)
and the generated single-file `config.yml`
which defines the CircleCI workflows for this project.
The Makefile in this directory generates the `./config.yml`
in CircleCI 2.0 syntax,
from the tree rooted at `./config/`,
which contains files in CircleCI 2.1 syntax.
CircleCI supports [generating a single config file from many],
using the `$ circleci config pack` command.
It also supports [expanding 2.1 syntax to 2.0 syntax]
using the `$ circleci config process` command.
[generating a single config file from many]: https://circleci.com/docs/2.0/local-cli/#packing-a-config
[expanding 2.1 syntax to 2.0 syntax]: https://circleci.com/docs/2.0/local-cli/#processing-a-config
## Prerequisites
You will need the [CircleCI CLI tool] installed and working,
at least version `0.1.5607`.
```
$ circleci version
0.1.5607+f705856
```
NOTE: It is recommended to [download this tool directly from GitHub Releases].
Do not install it using Homebrew, as this version cannot be easily updated.
It is also not recommended to pipe curl to bash (which CircleCI recommend) for security reasons!
[CircleCI CLI tool]: https://circleci.com/docs/2.0/local-cli/
[download this tool directly from GitHub Releases]: https://github.com/CircleCI-Public/circleci-cli/releases
## How to make changes
Before making changes, be sure to understand the layout
of the `./config/` file tree, as well as circleci 2.1 syntax.
See the [Syntax and layout] section below.
To update the config, you should edit, add or remove files
in the `./config/` directory,
and then run `make ci-config`.
If that's successful,
you should then commit every `*.yml` file in the tree rooted in this directory.
That is: you should commit both the source under `./config/`
and the generated file `./config.yml` at the same time, in the same commit.
Do not edit the `./config.yml` file directly, as you will lose your changes
next time `make ci-config` is run.
[Syntax and layout]: #syntax-and-layout
### Verifying `./config.yml`
To check whether or not the current `./config.yml` is up to date with the source,
and whether it is valid, run `$ make ci-verify`.
Note that `$ make ci-verify` should be run in CI,
as well as by a local git commit hook,
to ensure we never commit files that are invalid or out of date.
#### Example shell session
```sh
$ make ci-config
config.yml updated
$ git add -A . # The -A makes sure to include deletions/renames etc.
$ git commit -m "ci: blah blah blah"
Changes detected in .circleci/, running 'make -C .circleci ci-verify'
--> Generated config.yml is up to date!
--> Config file at config.yml is valid.
```
### Syntax and layout
It is important to understand the layout of the config directory.
Read the documentation on [packing a config] for a full understanding
of how multiple YAML files are merged by the circleci CLI tool.
[packing a config]: https://circleci.com/docs/2.0/local-cli/#packing-a-config
Here is an example file tree (with comments added afterwards):
```sh
$ tree .
.
├── Makefile
├── README.md # This file.
├── config # The source code for config.yml is rooted here.
│   ├── @config.yml # Files beginning with @ are treated specially by `circleci config pack`
│   ├── commands # Subdirectories of config become top-level keys.
│   │   └── go_test.yml # Filenames (minus .yml) become top-level keys under their parent (in this case "commands").
│ │ # The contents of go_test.yml therefore are placed at: .commands.go_test:
│   └── jobs # jobs also becomes a top-level key under config...
│   ├── build-go-dev.yml # ...and likewise filenames become keys under their parent.
│   ├── go-mod-download.yml
│   ├── install-ui-dependencies.yml
│   ├── test-go-race.yml
│   ├── test-go.yml
│   └── test-ui.yml
└── config.yml # The generated file in 2.0 syntax.
```
About those `@` files... Preceding a filename with `@`
indicates to `$ circleci config pack` that the contents of this YAML file
should be at the top-level, rather than underneath a key named after their filename.
This naming convention is unfortunate as it breaks autocompletion in bash,
but there we go.
### Why not just use YAML references?
YAML references only work within a single file,
this is because `circleci config pack` is not a text-level packer,
but rather stitches together the structures defined in each YAML
file according to certain rules.
Therefore it must parse each file separately,
and YAML references are handled by the parser.

661
.circleci/config.yml generated
View file

@ -1,228 +1,511 @@
### Generated by 'make ci-config' do not manually edit this file.
version: 2
references:
images:
go: &GOLANG_IMAGE golang:1.12.4-stretch # Pin Go to patch version (ex: 1.2.3)
node: &NODE_IMAGE node:10-stretch # Pin Node.js to major version (ex: 10)
environment: &ENVIRONMENT
CIRCLECI_CLI_VERSION: 0.1.5546 # Pin CircleCI CLI to patch version (ex: 1.2.3)
GO_VERSION: 1.12.4 # Pin Go to patch version (ex: 1.2.3)
GOTESTSUM_VERSION: 0.3.3 # Pin gotestsum to patch version (ex: 1.2.3)
cache:
go-sum: &GO_SUM_CACHE_KEY go-sum-v1-{{ checksum "go.sum" }}
yarn-lock: &YARN_LOCK_CACHE_KEY yarn-lock-v1-{{ checksum "ui/yarn.lock" }}
jobs:
install-ui-dependencies:
docker:
- image: *NODE_IMAGE
- image: node:10-stretch
working_directory: /src
steps:
- checkout
- restore_cache:
key: *YARN_LOCK_CACHE_KEY
- run:
name: Install UI dependencies
command: |
set -eux -o pipefail
cd ui
yarn install --ignore-optional
npm rebuild node-sass
- save_cache:
key: *YARN_LOCK_CACHE_KEY
paths:
- ui/node_modules
- checkout
- restore_cache:
key: yarn-lock-v1-{{ checksum "ui/yarn.lock" }}
- run:
command: |
set -eux -o pipefail
cd ui
yarn install --ignore-optional
npm rebuild node-sass
name: Install UI dependencies
- save_cache:
key: yarn-lock-v1-{{ checksum "ui/yarn.lock" }}
paths:
- ui/node_modules
go-mod-download:
docker:
- image: *GOLANG_IMAGE
- image: golang:1.12.4-stretch
working_directory: /src
steps:
- checkout
- restore_cache:
key: *GO_SUM_CACHE_KEY
- run:
name: Download Go modules
command: go mod download
- run:
name: Verify checksums of Go modules
command: go mod verify
- save_cache:
key: *GO_SUM_CACHE_KEY
paths:
- /go/pkg/mod
- add_ssh_keys:
fingerprints:
- c6:96:98:82:dc:04:6c:39:dd:ac:83:05:e3:15:1c:98
- checkout
- restore_cache:
key: go-sum-v1-{{ checksum "go.sum" }}
- run:
command: go mod download
name: Download Go modules
- run:
command: go mod verify
name: Verify checksums of Go modules
- save_cache:
key: go-sum-v1-{{ checksum "go.sum" }}
paths:
- /go/pkg/mod
build-go-dev:
docker:
- image: *GOLANG_IMAGE
- image: golang:1.12.4-stretch
working_directory: /src
steps:
- checkout
- restore_cache:
key: *GO_SUM_CACHE_KEY
- run:
name: Build dev binary
command: |
set -eux -o pipefail
- checkout
- restore_cache:
key: go-sum-v1-{{ checksum "go.sum" }}
- attach_workspace:
at: .
- run:
command: |
set -eux -o pipefail
# Move dev UI assets to expected location
rm -rf ./pkg
mkdir ./pkg
# Build dev binary
make bootstrap dev
- persist_to_workspace:
root: .
paths:
- bin
# Move dev UI assets to expected location
rm -rf ./pkg
mkdir ./pkg
# Build dev binary
make bootstrap dev
name: Build dev binary
- persist_to_workspace:
paths:
- bin
root: .
test-ui:
docker:
- image: *NODE_IMAGE
- image: node:10-stretch
working_directory: /src
resource_class: medium+
steps:
- checkout
- restore_cache:
key: *YARN_LOCK_CACHE_KEY
- attach_workspace:
at: .
- run:
name: Test UI
command: |
set -eux -o pipefail
- checkout
- restore_cache:
key: yarn-lock-v1-{{ checksum "ui/yarn.lock" }}
- attach_workspace:
at: .
- run:
command: |
set -eux -o pipefail
# Install Chrome
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub \
| apt-key add -
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" \
| tee /etc/apt/sources.list.d/google-chrome.list
apt-get update
apt-get -y install google-chrome-stable
rm /etc/apt/sources.list.d/google-chrome.list
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
# Install Chrome
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub \
| apt-key add -
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" \
| tee /etc/apt/sources.list.d/google-chrome.list
apt-get update
apt-get -y install google-chrome-stable
rm /etc/apt/sources.list.d/google-chrome.list
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
# Add ./bin to the PATH so vault binary can be run by Ember tests
export PATH="${PWD}"/bin:${PATH}
# Run Ember tests
cd ui
mkdir -p test-results/qunit
yarn run test-oss
- store_artifacts:
path: ui/test-results
- store_test_results:
path: ui/test-results
test-ui-browserstack:
docker:
- image: *NODE_IMAGE
steps:
- checkout
- restore_cache:
key: *YARN_LOCK_CACHE_KEY
- attach_workspace:
at: .
- run:
name: Run BrowserStack tests
command: |
set -eux -o pipefail
# Add ./bin to the PATH so vault binary can be run by Ember tests
export PATH="${PWD}"/bin:${PATH}
make test-ui-browserstack
# Add ./bin to the PATH so vault binary can be run by Ember tests
export PATH="${PWD}/bin:${PATH}"
# Run Ember tests
cd ui
mkdir -p test-results/qunit
yarn run test-oss
name: Test UI
- store_artifacts:
path: ui/test-results
- store_test_results:
path: ui/test-results
test-go:
machine: true
environment:
<<: *ENVIRONMENT
GO_TAGS:
working_directory: ~/src
parallelism: 2
steps:
- checkout
- run:
command: |
set -eux -o pipefail
sudo mkdir /go
sudo chown -R circleci:circleci /go
name: Allow circleci user to restore Go modules cache
- restore_cache:
key: go-sum-v1-{{ checksum "go.sum" }}
- run:
command: |
set -eux -o pipefail
# Install Go
curl -sSLO "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz"
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "go${GO_VERSION}.linux-amd64.tar.gz"
rm -f "go${GO_VERSION}.linux-amd64.tar.gz"
export GOPATH=/go
export PATH="${PATH}:${GOPATH}/bin:/usr/local/go/bin"
# Install CircleCI CLI
curl -sSL \
"https://github.com/CircleCI-Public/circleci-cli/releases/download/v${CIRCLECI_CLI_VERSION}/circleci-cli_${CIRCLECI_CLI_VERSION}_linux_amd64.tar.gz" \
| sudo tar --overwrite -xz \
-C /usr/local/bin \
"circleci-cli_${CIRCLECI_CLI_VERSION}_linux_amd64/circleci"
# Split Go tests by prior test times
package_names=$(go list \
-tags "${GO_TAGS}" \
./... \
| grep -v /integ \
| grep -v /vendor/ \
| sort \
| circleci tests split --split-by=timings --timings-type=classname)
# Install gotestsum
curl -sSL "https://github.com/gotestyourself/gotestsum/releases/download/v${GOTESTSUM_VERSION}/gotestsum_${GOTESTSUM_VERSION}_linux_amd64.tar.gz" \
| sudo tar --overwrite -xz -C /usr/local/bin gotestsum
# Run tests
make prep
mkdir -p test-results/go-test
CGO_ENABLED= \
VAULT_ADDR= \
VAULT_TOKEN= \
VAULT_DEV_ROOT_TOKEN_ID= \
VAULT_ACC= \
gotestsum --format=short-verbose --junitfile test-results/go-test/results.xml -- \
-tags "${GO_TAGS}" \
-timeout=40m \
-parallel=20 \
\
${package_names}
name: Run Go tests
no_output_timeout: 20m
- store_artifacts:
path: test-results
- store_test_results:
path: test-results
environment:
- CIRCLECI_CLI_VERSION: 0.1.5546
- GO_TAGS: null
- GO_VERSION: 1.12.4
- GOTESTSUM_VERSION: 0.3.3
test-go-race:
machine: true
working_directory: ~/src
steps:
- checkout
- run:
name: Allow circleci user to restore Go modules cache
command: |
set -eux -o pipefail
- checkout
- run:
command: |
set -eux -o pipefail
sudo mkdir /go
sudo chown -R circleci:circleci /go
- restore_cache:
key: *GO_SUM_CACHE_KEY
- run:
name: Run Go tests
no_output_timeout: 20m
command: |
set -eux -o pipefail
sudo mkdir /go
sudo chown -R circleci:circleci /go
name: Allow circleci user to restore Go modules cache
- restore_cache:
key: go-sum-v1-{{ checksum "go.sum" }}
- run:
command: |
set -eux -o pipefail
# Install Go
curl -sSLO "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz"
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "go${GO_VERSION}.linux-amd64.tar.gz"
rm -f "go${GO_VERSION}.linux-amd64.tar.gz"
export GOPATH=/go
export PATH="${PATH}:${GOPATH}/bin:/usr/local/go/bin"
# Install Go
curl -sSLO "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz"
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "go${GO_VERSION}.linux-amd64.tar.gz"
rm -f "go${GO_VERSION}.linux-amd64.tar.gz"
export GOPATH=/go
export PATH="${PATH}:${GOPATH}/bin:/usr/local/go/bin"
# Install CircleCI CLI
curl -sSL \
"https://github.com/CircleCI-Public/circleci-cli/releases/download/v${CIRCLECI_CLI_VERSION}/circleci-cli_${CIRCLECI_CLI_VERSION}_linux_amd64.tar.gz" \
| sudo tar --overwrite -xz \
-C /usr/local/bin \
"circleci-cli_${CIRCLECI_CLI_VERSION}_linux_amd64/circleci"
# Install CircleCI CLI
curl -sSL \
"https://github.com/CircleCI-Public/circleci-cli/releases/download/v${CIRCLECI_CLI_VERSION}/circleci-cli_${CIRCLECI_CLI_VERSION}_linux_amd64.tar.gz" \
| sudo tar --overwrite -xz \
-C /usr/local/bin \
"circleci-cli_${CIRCLECI_CLI_VERSION}_linux_amd64/circleci"
# Split Go tests by prior test times
package_names=$(go list \
-tags "${GO_TAGS}" \
./... \
| grep -v /vendor/ \
| sort \
| circleci tests split --split-by=timings --timings-type=classname)
# Split Go tests by prior test times
package_names=$(go list \
-tags "${GO_TAGS}" \
./... \
| grep -v /integ \
| grep -v /vendor/ \
| sort \
| circleci tests split --split-by=timings --timings-type=classname)
# Install gotestsum
curl -sSL "https://github.com/gotestyourself/gotestsum/releases/download/v${GOTESTSUM_VERSION}/gotestsum_${GOTESTSUM_VERSION}_linux_amd64.tar.gz" \
| sudo tar --overwrite -xz -C /usr/local/bin gotestsum
# Run tests
make prep
mkdir -p test-results/go-test
CGO_ENABLED= \
VAULT_ADDR= \
VAULT_TOKEN= \
VAULT_DEV_ROOT_TOKEN_ID= \
VAULT_ACC= \
gotestsum --format=short-verbose --junitfile test-results/go-test/results.xml -- \
-tags "${GO_TAGS}" \
-timeout=40m \
-parallel=20 \
${package_names}
- store_artifacts:
path: test-results
- store_test_results:
path: test-results
# Install gotestsum
curl -sSL "https://github.com/gotestyourself/gotestsum/releases/download/v${GOTESTSUM_VERSION}/gotestsum_${GOTESTSUM_VERSION}_linux_amd64.tar.gz" \
| sudo tar --overwrite -xz -C /usr/local/bin gotestsum
# Run tests
make prep
mkdir -p test-results/go-test
CGO_ENABLED= \
VAULT_ADDR= \
VAULT_TOKEN= \
VAULT_DEV_ROOT_TOKEN_ID= \
VAULT_ACC= \
gotestsum --format=short-verbose --junitfile test-results/go-test/results.xml -- \
-tags "${GO_TAGS}" \
-timeout=40m \
-parallel=20 \
-race \
${package_names}
name: Run Go tests
no_output_timeout: 20m
- store_artifacts:
path: test-results
- store_test_results:
path: test-results
environment:
- CIRCLECI_CLI_VERSION: 0.1.5546
- GO_TAGS: null
- GO_VERSION: 1.12.4
- GOTESTSUM_VERSION: 0.3.3
workflows:
version: 2
ci:
jobs:
- install-ui-dependencies
- go-mod-download
- build-go-dev:
requires:
- go-mod-download
- test-ui:
requires:
- install-ui-dependencies
- build-go-dev
- test-go:
requires:
- build-go-dev
- test-ui-browserstack:
requires:
- install-ui-dependencies
- build-go-dev
- install-ui-dependencies
- go-mod-download
- build-go-dev:
requires:
- go-mod-download
- test-ui:
requires:
- install-ui-dependencies
- build-go-dev
- test-go:
requires:
- build-go-dev
- test-go-race:
requires:
- build-go-dev
version: 2
# Original config.yml file:
# commands:
# go_test:
# description: run go tests
# parameters:
# extra_flags:
# default: \"\"
# type: string
# steps:
# - run:
# command: |
# set -eux -o pipefail
#
# # Install Go
# curl -sSLO \"https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz\"
# sudo rm -rf /usr/local/go
# sudo tar -C /usr/local -xzf \"go${GO_VERSION}.linux-amd64.tar.gz\"
# rm -f \"go${GO_VERSION}.linux-amd64.tar.gz\"
# export GOPATH=/go
# export PATH=\"${PATH}:${GOPATH}/bin:/usr/local/go/bin\"
#
# # Install CircleCI CLI
# curl -sSL \\
# \"https://github.com/CircleCI-Public/circleci-cli/releases/download/v${CIRCLECI_CLI_VERSION}/circleci-cli_${CIRCLECI_CLI_VERSION}_linux_amd64.tar.gz\" \\
# | sudo tar --overwrite -xz \\
# -C /usr/local/bin \\
# \"circleci-cli_${CIRCLECI_CLI_VERSION}_linux_amd64/circleci\"
#
# # Split Go tests by prior test times
# package_names=$(go list \\
# -tags \"${GO_TAGS}\" \\
# ./... \\
# | grep -v /integ \\
# | grep -v /vendor/ \\
# | sort \\
# | circleci tests split --split-by=timings --timings-type=classname)
#
# # Install gotestsum
# curl -sSL \"https://github.com/gotestyourself/gotestsum/releases/download/v${GOTESTSUM_VERSION}/gotestsum_${GOTESTSUM_VERSION}_linux_amd64.tar.gz\" \\
# | sudo tar --overwrite -xz -C /usr/local/bin gotestsum
#
# # Run tests
# make prep
# mkdir -p test-results/go-test
# CGO_ENABLED= \\
# VAULT_ADDR= \\
# VAULT_TOKEN= \\
# VAULT_DEV_ROOT_TOKEN_ID= \\
# VAULT_ACC= \\
# gotestsum --format=short-verbose --junitfile test-results/go-test/results.xml -- \\
# -tags \"${GO_TAGS}\" \\
# -timeout=40m \\
# -parallel=20 \\
# << parameters.extra_flags >> \\
# ${package_names}
# name: Run Go tests
# no_output_timeout: 20m
# restore_go_cache:
# steps:
# - restore_cache:
# key: go-sum-v1-{{ checksum \"go.sum\" }}
# restore_yarn_cache:
# steps:
# - restore_cache:
# key: yarn-lock-v1-{{ checksum \"ui/yarn.lock\" }}
# save_go_cache:
# steps:
# - save_cache:
# key: go-sum-v1-{{ checksum \"go.sum\" }}
# paths:
# - /go/pkg/mod
# save_yarn_cache:
# steps:
# - save_cache:
# key: yarn-lock-v1-{{ checksum \"ui/yarn.lock\" }}
# paths:
# - ui/node_modules
# executors:
# go:
# docker:
# - image: golang:1.12.4-stretch
# working_directory: /src
# go-machine:
# environment:
# CIRCLECI_CLI_VERSION: 0.1.5546
# GO_TAGS: null
# GO_VERSION: 1.12.4
# GOTESTSUM_VERSION: 0.3.3
# machine: true
# working_directory: ~/src
# node:
# docker:
# - image: node:10-stretch
# working_directory: /src
# jobs:
# build-go-dev:
# executor: go
# steps:
# - checkout
# - restore_go_cache
# - attach_workspace:
# at: .
# - run:
# command: |
# set -eux -o pipefail
#
# # Move dev UI assets to expected location
# rm -rf ./pkg
# mkdir ./pkg
#
# # Build dev binary
# make bootstrap dev
# name: Build dev binary
# - persist_to_workspace:
# paths:
# - bin
# root: .
# go-mod-download:
# executor: go
# steps:
# - add_ssh_keys:
# fingerprints:
# - c6:96:98:82:dc:04:6c:39:dd:ac:83:05:e3:15:1c:98
# - checkout
# - restore_go_cache
# - run:
# command: go mod download
# name: Download Go modules
# - run:
# command: go mod verify
# name: Verify checksums of Go modules
# - save_go_cache
# install-ui-dependencies:
# executor: node
# steps:
# - checkout
# - restore_yarn_cache
# - run:
# command: |
# set -eux -o pipefail
#
# cd ui
# yarn install --ignore-optional
# npm rebuild node-sass
# name: Install UI dependencies
# - save_yarn_cache
# test-go:
# executor: go-machine
# parallelism: 2
# steps:
# - checkout
# - run:
# command: |
# set -eux -o pipefail
#
# sudo mkdir /go
# sudo chown -R circleci:circleci /go
# name: Allow circleci user to restore Go modules cache
# - restore_go_cache
# - go_test
# - store_artifacts:
# path: test-results
# - store_test_results:
# path: test-results
# test-go-race:
# executor: go-machine
# steps:
# - checkout
# - run:
# command: |
# set -eux -o pipefail
#
# sudo mkdir /go
# sudo chown -R circleci:circleci /go
# name: Allow circleci user to restore Go modules cache
# - restore_go_cache
# - go_test:
# extra_flags: -race
# - store_artifacts:
# path: test-results
# - store_test_results:
# path: test-results
# test-ui:
# executor: node
# resource_class: medium+
# steps:
# - checkout
# - restore_yarn_cache
# - attach_workspace:
# at: .
# - run:
# command: |
# set -eux -o pipefail
#
# # Install Chrome
# wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub \\
# | apt-key add -
# echo \"deb http://dl.google.com/linux/chrome/deb/ stable main\" \\
# | tee /etc/apt/sources.list.d/google-chrome.list
# apt-get update
# apt-get -y install google-chrome-stable
# rm /etc/apt/sources.list.d/google-chrome.list
# rm -rf /var/lib/apt/lists/* /var/cache/apt/*
#
# # Add ./bin to the PATH so vault binary can be run by Ember tests
# export PATH=\"${PWD}/bin:${PATH}\"
#
# # Run Ember tests
# cd ui
# mkdir -p test-results/qunit
# yarn run test-oss
# name: Test UI
# - store_artifacts:
# path: ui/test-results
# - store_test_results:
# path: ui/test-results
# references:
# cache:
# go-sum: go-sum-v1-{{ checksum \"go.sum\" }}
# yarn-lock: yarn-lock-v1-{{ checksum \"ui/yarn.lock\" }}
# images:
# go: golang:1.12.4-stretch
# node: node:10-stretch
# version: 2.1
# workflows:
# ci:
# jobs:
# - install-ui-dependencies
# - go-mod-download
# - build-go-dev:
# requires:
# - go-mod-download
# - test-ui:
# requires:
# - install-ui-dependencies
# - build-go-dev
# - test-go:
# requires:
# - build-go-dev
# - test-go-race:
# requires:
# - build-go-dev

View file

@ -0,0 +1,53 @@
---
version: 2.1
references:
images:
go: &GOLANG_IMAGE golang:1.12.4-stretch # Pin Go to patch version (ex: 1.2.3)
node: &NODE_IMAGE node:10-stretch # Pin Node.js to major version (ex: 10)
cache:
go-sum: &GO_SUM_CACHE_KEY go-sum-v1-{{ checksum "go.sum" }}
yarn-lock: &YARN_LOCK_CACHE_KEY yarn-lock-v1-{{ checksum "ui/yarn.lock" }}
# more commands defined in commands/
commands:
restore_yarn_cache:
steps:
- restore_cache:
key: *YARN_LOCK_CACHE_KEY
save_yarn_cache:
steps:
- save_cache:
key: *YARN_LOCK_CACHE_KEY
paths:
- ui/node_modules
restore_go_cache:
steps:
- restore_cache:
key: *GO_SUM_CACHE_KEY
save_go_cache:
steps:
- save_cache:
key: *GO_SUM_CACHE_KEY
paths:
- /go/pkg/mod
executors:
go:
docker:
- image: *GOLANG_IMAGE
working_directory: /src
go-machine:
machine: true
environment:
CIRCLECI_CLI_VERSION: 0.1.5546 # Pin CircleCI CLI to patch version (ex: 1.2.3)
GO_VERSION: 1.12.4 # Pin Go to patch version (ex: 1.2.3)
GOTESTSUM_VERSION: 0.3.3 # Pin gotestsum to patch version (ex: 1.2.3)
GO_TAGS:
working_directory: ~/src
node:
docker:
- image: *NODE_IMAGE
working_directory: /src

View file

@ -0,0 +1,55 @@
description: run go tests
parameters:
extra_flags:
type: string
default: ""
steps:
- run:
name: Run Go tests
no_output_timeout: 20m
command: |
set -eux -o pipefail
# Install Go
curl -sSLO "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz"
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "go${GO_VERSION}.linux-amd64.tar.gz"
rm -f "go${GO_VERSION}.linux-amd64.tar.gz"
export GOPATH=/go
export PATH="${PATH}:${GOPATH}/bin:/usr/local/go/bin"
# Install CircleCI CLI
curl -sSL \
"https://github.com/CircleCI-Public/circleci-cli/releases/download/v${CIRCLECI_CLI_VERSION}/circleci-cli_${CIRCLECI_CLI_VERSION}_linux_amd64.tar.gz" \
| sudo tar --overwrite -xz \
-C /usr/local/bin \
"circleci-cli_${CIRCLECI_CLI_VERSION}_linux_amd64/circleci"
# Split Go tests by prior test times
package_names=$(go list \
-tags "${GO_TAGS}" \
./... \
| grep -v /integ \
| grep -v /vendor/ \
| sort \
| circleci tests split --split-by=timings --timings-type=classname)
# Install gotestsum
curl -sSL "https://github.com/gotestyourself/gotestsum/releases/download/v${GOTESTSUM_VERSION}/gotestsum_${GOTESTSUM_VERSION}_linux_amd64.tar.gz" \
| sudo tar --overwrite -xz -C /usr/local/bin gotestsum
# Run tests
make prep
mkdir -p test-results/go-test
CGO_ENABLED= \
VAULT_ADDR= \
VAULT_TOKEN= \
VAULT_DEV_ROOT_TOKEN_ID= \
VAULT_ACC= \
gotestsum --format=short-verbose --junitfile test-results/go-test/results.xml -- \
-tags "${GO_TAGS}" \
-timeout=40m \
-parallel=20 \
<< parameters.extra_flags >> \
${package_names}

View file

@ -0,0 +1,21 @@
executor: go
steps:
- checkout
- restore_go_cache
- attach_workspace:
at: .
- run:
name: Build dev binary
command: |
set -eux -o pipefail
# Move dev UI assets to expected location
rm -rf ./pkg
mkdir ./pkg
# Build dev binary
make bootstrap dev
- persist_to_workspace:
root: .
paths:
- bin

View file

@ -0,0 +1,15 @@
executor: go
steps:
- add_ssh_keys:
fingerprints:
# "CircleCI SSH Checkout" SSH key associated with hashicorp-ci GitHub user
- "c6:96:98:82:dc:04:6c:39:dd:ac:83:05:e3:15:1c:98"
- checkout
- restore_go_cache
- run:
name: Download Go modules
command: go mod download
- run:
name: Verify checksums of Go modules
command: go mod verify
- save_go_cache

View file

@ -0,0 +1,13 @@
executor: node
steps:
- checkout
- restore_yarn_cache
- run:
name: Install UI dependencies
command: |
set -eux -o pipefail
cd ui
yarn install --ignore-optional
npm rebuild node-sass
- save_yarn_cache

View file

@ -0,0 +1,17 @@
executor: go-machine
steps:
- checkout
- run:
name: Allow circleci user to restore Go modules cache
command: |
set -eux -o pipefail
sudo mkdir /go
sudo chown -R circleci:circleci /go
- restore_go_cache
- go_test:
extra_flags: "-race"
- store_artifacts:
path: test-results
- store_test_results:
path: test-results

View file

@ -0,0 +1,17 @@
executor: go-machine
parallelism: 2
steps:
- checkout
- run:
name: Allow circleci user to restore Go modules cache
command: |
set -eux -o pipefail
sudo mkdir /go
sudo chown -R circleci:circleci /go
- restore_go_cache
- go_test
- store_artifacts:
path: test-results
- store_test_results:
path: test-results

View file

@ -0,0 +1,33 @@
executor: node
resource_class: medium+
steps:
- checkout
- restore_yarn_cache
- attach_workspace:
at: .
- run:
name: Test UI
command: |
set -eux -o pipefail
# Install Chrome
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub \
| apt-key add -
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" \
| tee /etc/apt/sources.list.d/google-chrome.list
apt-get update
apt-get -y install google-chrome-stable
rm /etc/apt/sources.list.d/google-chrome.list
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
# Add ./bin to the PATH so vault binary can be run by Ember tests
export PATH="${PWD}/bin:${PATH}"
# Run Ember tests
cd ui
mkdir -p test-results/qunit
yarn run test-oss
- store_artifacts:
path: ui/test-results
- store_test_results:
path: ui/test-results

View file

@ -0,0 +1,16 @@
jobs:
- install-ui-dependencies
- go-mod-download
- build-go-dev:
requires:
- go-mod-download
- test-ui:
requires:
- install-ui-dependencies
- build-go-dev
- test-go:
requires:
- build-go-dev
- test-go-race:
requires:
- build-go-dev

104
.hooks/pre-commit Executable file
View file

@ -0,0 +1,104 @@
#!/usr/bin/env bash
# READ THIS BEFORE MAKING CHANGES:
#
# If you want to add a new pre-commit check, here are the rules:
#
# 1. Create a bash function for your check (see e.g. ui_lint below).
# NOTE: Each function will be called in a sub-shell so you can freely
# change directory without worrying about interference.
# 2. Add the name of the function to the CHECKS variable.
# 3. If no changes relevant to your new check are staged, then
# do not output anything at all - this would be annoying noise.
# In this case, call 'return 0' from your check function to return
# early without blocking the commit.
# 4. If any non-trivial check-specific thing has to be invoked,
# then output '==> [check description]' as the first line of
# output. Each sub-check should output '--> [subcheck description]'
# after it has run, indicating success or failure.
# 5. Call 'block [reason]' to block the commit. This ensures the last
# line of output calls out that the commit was blocked - which may not
# be obvious from random error messages generated in 4.
#
# At the moment, there are no automated tests for this hook, so please run it
# locally to check you have not broken anything - breaking this will interfere
# with other peoples' workflows significantly, so be sure, check everything twice.
set -euo pipefail
# Call block to block the commit with a message.
block() {
echo "$@"
echo "Commit blocked - see errors above."
exit 1
}
# Add all check functions to this space separated list.
# They are executed in this order (see end of file).
CHECKS="ui_lint circleci_verify"
# Run ui linter if changes in that dir detected.
ui_lint() {
local DIR=ui LINTER=node_modules/.bin/lint-staged
# Silently succeed if no changes staged for $DIR
if git diff --name-only --cached --exit-code -- $DIR/; then
return 0
fi
# Silently succeed if the linter has not been installed.
# We assume that if you're doing UI dev, you will have installed the linter
# by running yarn.
if [ ! -x $DIR/$LINTER ]; then
return 0
fi
echo "==> Changes detected in $DIR/: Running linter..."
# Run the linter from the UI dir.
cd $DIR
$LINTER || block "UI lint failed"
}
# Check .circleci/config.yml is up to date and valid, and that all changes are
# included together in this commit.
circleci_verify() {
# Change to the root dir of the repo.
cd "$(git rev-parse --show-toplevel)"
# Fail early if we accidentally used '.yaml' instead of '.yml'
if ! git diff --name-only --cached --exit-code -- '.circleci/***.yaml'; then
# This is just for consistency, as I keep making this mistake - Sam.
block "ERROR: File(s) with .yaml extension detected. Please rename them .yml instead."
fi
# Succeed early if no changes to yml files in .circleci/ are currently staged.
# make ci-verify is slow so we really don't want to run it unnecessarily.
if git diff --name-only --cached --exit-code -- '.circleci/***.yml'; then
return 0
fi
# Make sure to add no explicit output before this line, as it would just be noise
# for those making non-circleci changes.
echo "==> Verifying config changes in .circleci/"
echo "--> OK: All files are .yml not .yaml"
# Ensure commit includes _all_ files in .circleci/
# So not only are the files up to date, but we are also committing them in one go.
if ! git diff --name-only --exit-code -- '.circleci/***.yml'; then
echo "ERROR: Some .yml diffs in .circleci/ are staged, others not."
block "Please commit the entire .circleci/ directory together, or omit it altogether."
fi
echo "--> OK: All .yml files in .circleci are staged."
if ! make -C .circleci ci-verify; then
block "ERROR: make ci-verify failed"
fi
echo "--> OK: make ci-verify succeeded."
}
for CHECK in $CHECKS; do
# Force each check into a subshell to avoid crosstalk.
( $CHECK ) || exit $?
done

View file

@ -2,6 +2,13 @@
CHANGES:
* auth/token: Token store roles use new, common token fields for the values
that overlap with other auth backends. `period`, `explicit_max_ttl`, and
`bound_cidrs` will continue to work, with priority being given to the
`token_` prefixed versions of those parameters. They will also be returned
when doing a read on the role if they were used to provide values initially;
however, in Vault 1.4 if `period` or `explicit_max_ttl` is zero they will no
longer be returned. (`explicit_max_ttl` was already not returned if empty.)
* Due to underlying changes in Go version 1.12 and Go > 1.11.5, Vault is now
stricter about what characters it will accept in path names. Whereas before
it would filter out unprintable characters (and this could be turned off),
@ -50,6 +57,9 @@ IMPROVEMENTS:
BUG FIXES:
* identity: Fix a case where modifying aliases of an entity could end up
moving the entity into the wrong namespace
## 1.1.3 (June 5th, 2019)
IMPROVEMENTS:

View file

@ -102,8 +102,15 @@ vet:
prep: fmtcheck
@sh -c "'$(CURDIR)/scripts/goversioncheck.sh' '$(GO_VERSION_MIN)'"
@go generate $(go list ./... | grep -v /vendor/)
@# Remove old (now broken) husky git hooks.
@[ ! -d .git/hooks ] || grep -l '^# husky$$' .git/hooks/* | xargs rm -f
@if [ -d .git/hooks ]; then cp .hooks/* .git/hooks/; fi
ci-config:
@$(MAKE) -C .circleci
ci-verify:
@$(MAKE) -C .circleci ci-verify
# bootstrap the build by downloading additional tools
bootstrap:
@for tool in $(EXTERNAL_TOOLS) ; do \

View file

@ -11,7 +11,7 @@ require (
github.com/hashicorp/go-retryablehttp v0.5.3
github.com/hashicorp/go-rootcerts v1.0.0
github.com/hashicorp/hcl v1.0.0
github.com/hashicorp/vault/sdk v0.1.8
github.com/hashicorp/vault/sdk v0.1.12-0.20190614165924-47d4e5b1f688
github.com/mitchellh/mapstructure v1.1.2
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4

View file

@ -234,7 +234,7 @@ func (c *Sys) RekeyRetrieveBackup() (*RekeyRetrieveResponse, error) {
}
func (c *Sys) RekeyRetrieveRecoveryBackup() (*RekeyRetrieveResponse, error) {
r := c.c.NewRequest("GET", "/v1/sys/rekey/recovery-backup")
r := c.c.NewRequest("GET", "/v1/sys/rekey/recovery-key-backup")
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
@ -275,7 +275,7 @@ func (c *Sys) RekeyDeleteBackup() error {
}
func (c *Sys) RekeyDeleteRecoveryBackup() error {
r := c.c.NewRequest("DELETE", "/v1/sys/rekey/recovery-backup")
r := c.c.NewRequest("DELETE", "/v1/sys/rekey/recovery-key-backup")
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()

View file

@ -153,6 +153,7 @@ func (f *AuditFormatter) FormatRequest(ctx context.Context, w io.Writer, config
TokenPolicies: auth.TokenPolicies,
IdentityPolicies: auth.IdentityPolicies,
ExternalNamespacePolicies: auth.ExternalNamespacePolicies,
NoDefaultPolicy: auth.NoDefaultPolicy,
Metadata: auth.Metadata,
EntityID: auth.EntityID,
RemainingUses: req.ClientTokenRemainingUses,
@ -352,6 +353,7 @@ func (f *AuditFormatter) FormatResponse(ctx context.Context, w io.Writer, config
TokenPolicies: resp.Auth.TokenPolicies,
IdentityPolicies: resp.Auth.IdentityPolicies,
ExternalNamespacePolicies: resp.Auth.ExternalNamespacePolicies,
NoDefaultPolicy: resp.Auth.NoDefaultPolicy,
Metadata: resp.Auth.Metadata,
NumUses: resp.Auth.NumUses,
EntityID: resp.Auth.EntityID,
@ -397,6 +399,7 @@ func (f *AuditFormatter) FormatResponse(ctx context.Context, w io.Writer, config
TokenPolicies: auth.TokenPolicies,
IdentityPolicies: auth.IdentityPolicies,
ExternalNamespacePolicies: auth.ExternalNamespacePolicies,
NoDefaultPolicy: auth.NoDefaultPolicy,
Metadata: auth.Metadata,
RemainingUses: req.ClientTokenRemainingUses,
EntityID: auth.EntityID,
@ -496,6 +499,7 @@ type AuditAuth struct {
TokenPolicies []string `json:"token_policies,omitempty"`
IdentityPolicies []string `json:"identity_policies,omitempty"`
ExternalNamespacePolicies map[string][]string `json:"external_namespace_policies,omitempty"`
NoDefaultPolicy bool `json:"no_default_policy,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
NumUses int `json:"num_uses,omitempty"`
RemainingUses int `json:"remaining_uses,omitempty"`

View file

@ -38,12 +38,13 @@ func TestFormatJSON_formatRequest(t *testing.T) {
}{
"auth, request": {
&logical.Auth{
ClientToken: "foo",
Accessor: "bar",
EntityID: "foobarentity",
DisplayName: "testtoken",
Policies: []string{"root"},
TokenType: logical.TokenTypeService,
ClientToken: "foo",
Accessor: "bar",
DisplayName: "testtoken",
EntityID: "foobarentity",
NoDefaultPolicy: true,
Policies: []string{"root"},
TokenType: logical.TokenTypeService,
},
&logical.Request{
Operation: logical.UpdateOperation,
@ -64,12 +65,13 @@ func TestFormatJSON_formatRequest(t *testing.T) {
},
"auth, request with prefix": {
&logical.Auth{
ClientToken: "foo",
Accessor: "bar",
EntityID: "foobarentity",
DisplayName: "testtoken",
Policies: []string{"root"},
TokenType: logical.TokenTypeService,
ClientToken: "foo",
Accessor: "bar",
EntityID: "foobarentity",
DisplayName: "testtoken",
NoDefaultPolicy: true,
Policies: []string{"root"},
TokenType: logical.TokenTypeService,
},
&logical.Request{
Operation: logical.UpdateOperation,
@ -141,5 +143,5 @@ func TestFormatJSON_formatRequest(t *testing.T) {
}
}
const testFormatJSONReqBasicStrFmt = `{"time":"2015-08-05T13:45:46Z","type":"request","auth":{"client_token":"%s","accessor":"bar","display_name":"testtoken","policies":["root"],"metadata":null,"entity_id":"foobarentity","token_type":"service"},"request":{"operation":"update","path":"/foo","data":null,"wrap_ttl":60,"remote_address":"127.0.0.1","headers":{"foo":["bar"]}},"error":"this is an error"}
const testFormatJSONReqBasicStrFmt = `{"time":"2015-08-05T13:45:46Z","type":"request","auth":{"client_token":"%s","accessor":"bar","display_name":"testtoken","policies":["root"],"no_default_policy":true,"metadata":null,"entity_id":"foobarentity","token_type":"service"},"request":{"operation":"update","path":"/foo","data":null,"wrap_ttl":60,"remote_address":"127.0.0.1","headers":{"foo":["bar"]}},"error":"this is an error"}
`

View file

@ -37,12 +37,13 @@ func TestFormatJSONx_formatRequest(t *testing.T) {
}{
"auth, request": {
&logical.Auth{
ClientToken: "foo",
Accessor: "bar",
EntityID: "foobarentity",
DisplayName: "testtoken",
Policies: []string{"root"},
TokenType: logical.TokenTypeService,
ClientToken: "foo",
Accessor: "bar",
DisplayName: "testtoken",
EntityID: "foobarentity",
NoDefaultPolicy: true,
Policies: []string{"root"},
TokenType: logical.TokenTypeService,
},
&logical.Request{
ID: "request",
@ -64,17 +65,18 @@ func TestFormatJSONx_formatRequest(t *testing.T) {
errors.New("this is an error"),
"",
"",
fmt.Sprintf(`<json:object name="auth"><json:string name="accessor">bar</json:string><json:string name="client_token">%s</json:string><json:string name="display_name">testtoken</json:string><json:string name="entity_id">foobarentity</json:string><json:array name="policies"><json:string>root</json:string></json:array><json:string name="token_type">service</json:string></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token">%s</json:string><json:string name="client_token_accessor">bar</json:string><json:object name="headers"><json:array name="foo"><json:string>bar</json:string></json:array></json:object><json:string name="id">request</json:string><json:object name="namespace"><json:string name="id">root</json:string></json:object><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:boolean name="policy_override">true</json:boolean><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
fmt.Sprintf(`<json:object name="auth"><json:string name="accessor">bar</json:string><json:string name="client_token">%s</json:string><json:string name="display_name">testtoken</json:string><json:string name="entity_id">foobarentity</json:string><json:boolean name="no_default_policy">true</json:boolean><json:array name="policies"><json:string>root</json:string></json:array><json:string name="token_type">service</json:string></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token">%s</json:string><json:string name="client_token_accessor">bar</json:string><json:object name="headers"><json:array name="foo"><json:string>bar</json:string></json:array></json:object><json:string name="id">request</json:string><json:object name="namespace"><json:string name="id">root</json:string></json:object><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:boolean name="policy_override">true</json:boolean><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
fooSalted, fooSalted),
},
"auth, request with prefix": {
&logical.Auth{
ClientToken: "foo",
Accessor: "bar",
EntityID: "foobarentity",
DisplayName: "testtoken",
Policies: []string{"root"},
TokenType: logical.TokenTypeService,
ClientToken: "foo",
Accessor: "bar",
DisplayName: "testtoken",
NoDefaultPolicy: true,
EntityID: "foobarentity",
Policies: []string{"root"},
TokenType: logical.TokenTypeService,
},
&logical.Request{
ID: "request",
@ -96,7 +98,7 @@ func TestFormatJSONx_formatRequest(t *testing.T) {
errors.New("this is an error"),
"",
"@cee: ",
fmt.Sprintf(`<json:object name="auth"><json:string name="accessor">bar</json:string><json:string name="client_token">%s</json:string><json:string name="display_name">testtoken</json:string><json:string name="entity_id">foobarentity</json:string><json:array name="policies"><json:string>root</json:string></json:array><json:string name="token_type">service</json:string></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token">%s</json:string><json:string name="client_token_accessor">bar</json:string><json:object name="headers"><json:array name="foo"><json:string>bar</json:string></json:array></json:object><json:string name="id">request</json:string><json:object name="namespace"><json:string name="id">root</json:string></json:object><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:boolean name="policy_override">true</json:boolean><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
fmt.Sprintf(`<json:object name="auth"><json:string name="accessor">bar</json:string><json:string name="client_token">%s</json:string><json:string name="display_name">testtoken</json:string><json:string name="entity_id">foobarentity</json:string><json:boolean name="no_default_policy">true</json:boolean><json:array name="policies"><json:string>root</json:string></json:array><json:string name="token_type">service</json:string></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token">%s</json:string><json:string name="client_token_accessor">bar</json:string><json:object name="headers"><json:array name="foo"><json:string>bar</json:string></json:array></json:object><json:string name="id">request</json:string><json:object name="namespace"><json:string name="id">root</json:string></json:object><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:boolean name="policy_override">true</json:boolean><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
fooSalted, fooSalted),
},
}

View file

@ -685,12 +685,22 @@ func (c *OperatorRekeyCommand) printUnsealKeys(client *api.Client, status *api.R
if len(resp.PGPFingerprints) > 0 && resp.Backup {
c.UI.Output("")
c.UI.Output(wrapAtLength(fmt.Sprintf(
"The encrypted unseal keys are backed up to \"core/unseal-keys-backup\"" +
"in the storage backend. Remove these keys at any time using " +
"\"vault operator rekey -backup-delete\". Vault does not automatically " +
"remove these keys.",
)))
switch strings.ToLower(strings.TrimSpace(c.flagTarget)) {
case "barrier":
c.UI.Output(wrapAtLength(fmt.Sprintf(
"The encrypted unseal keys are backed up to \"core/unseal-keys-backup\" " +
"in the storage backend. Remove these keys at any time using " +
"\"vault operator rekey -backup-delete\". Vault does not automatically " +
"remove these keys.",
)))
case "recovery", "hsm":
c.UI.Output(wrapAtLength(fmt.Sprintf(
"The encrypted unseal keys are backed up to \"core/recovery-keys-backup\" " +
"in the storage backend. Remove these keys at any time using " +
"\"vault operator rekey -backup-delete -target=recovery\". Vault does not automatically " +
"remove these keys.",
)))
}
}
switch status.VerificationRequired {

4
go.mod
View file

@ -81,8 +81,8 @@ require (
github.com/hashicorp/vault-plugin-secrets-gcp v0.5.2
github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.1
github.com/hashicorp/vault-plugin-secrets-kv v0.5.2-0.20190416155133-fd495225dea0
github.com/hashicorp/vault/api v1.0.1
github.com/hashicorp/vault/sdk v0.1.11
github.com/hashicorp/vault/api v1.0.3-0.20190614165924-47d4e5b1f688
github.com/hashicorp/vault/sdk v0.1.12-0.20190614165924-47d4e5b1f688
github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
github.com/jackc/pgx v3.3.0+incompatible // indirect

View file

@ -265,10 +265,6 @@ func ConfClusterAndCore(t testing.T, conf *vault.CoreConfig, opts *vault.TestClu
"approle": credAppRole.Factory,
"userpass": credUserpass.Factory,
}
coreConfig.LogicalBackends = map[string]logical.Factory{
"local-kv": PassthroughWithLocalPathsFactory,
"leased-kv": vault.LeasedPassthroughBackendFactory,
}
vault.AddNoopAudit(&coreConfig)
cluster := vault.NewTestCluster(t, &coreConfig, opts)
cluster.Start()
@ -281,13 +277,6 @@ func ConfClusterAndCore(t testing.T, conf *vault.CoreConfig, opts *vault.TestClu
return cluster, core
}
func GetClusterAndCore(t testing.T, logger log.Logger, handlerFunc func(*vault.HandlerProperties) http.Handler) (*vault.TestCluster, *vault.TestClusterCore) {
return ConfClusterAndCore(t, &vault.CoreConfig{}, &vault.TestClusterOptions{
Logger: logger,
HandlerFunc: handlerFunc,
})
}
func GetPerfReplicatedClusters(t testing.T, conf *vault.CoreConfig, opts *vault.TestClusterOptions) *ReplicatedTestClusters {
ret := &ReplicatedTestClusters{}
@ -305,13 +294,18 @@ func GetPerfReplicatedClusters(t testing.T, conf *vault.CoreConfig, opts *vault.
// Set this lower so that state populates quickly to standby nodes
cluster.HeartbeatInterval = 2 * time.Second
opts1 := *opts
opts1.Logger = logger.Named("perf-pri")
ret.PerfPrimaryCluster, _ = ConfClusterAndCore(t, conf, &opts1)
numCores := opts.NumCores
if numCores == 0 {
numCores = vault.DefaultNumCores
}
opts2 := *opts
opts1.Logger = logger.Named("perf-sec")
ret.PerfSecondaryCluster, _ = ConfClusterAndCore(t, conf, &opts2)
localopts := *opts
localopts.Logger = logger.Named("perf-pri")
ret.PerfPrimaryCluster, _ = ConfClusterAndCore(t, conf, &localopts)
localopts.Logger = logger.Named("perf-sec")
localopts.FirstCoreNumber += numCores
ret.PerfSecondaryCluster, _ = ConfClusterAndCore(t, conf, &localopts)
SetupTwoClusterPerfReplication(t, ret.PerfPrimaryCluster, ret.PerfSecondaryCluster)
@ -319,6 +313,12 @@ func GetPerfReplicatedClusters(t testing.T, conf *vault.CoreConfig, opts *vault.
}
func GetFourReplicatedClusters(t testing.T, handlerFunc func(*vault.HandlerProperties) http.Handler) *ReplicatedTestClusters {
return GetFourReplicatedClustersWithConf(t, &vault.CoreConfig{}, &vault.TestClusterOptions{
HandlerFunc: handlerFunc,
})
}
func GetFourReplicatedClustersWithConf(t testing.T, conf *vault.CoreConfig, opts *vault.TestClusterOptions) *ReplicatedTestClusters {
ret := &ReplicatedTestClusters{}
logger := log.New(&log.LoggerOptions{
@ -328,13 +328,26 @@ func GetFourReplicatedClusters(t testing.T, handlerFunc func(*vault.HandlerPrope
// Set this lower so that state populates quickly to standby nodes
cluster.HeartbeatInterval = 2 * time.Second
ret.PerfPrimaryCluster, _ = GetClusterAndCore(t, logger.Named("perf-pri"), handlerFunc)
numCores := opts.NumCores
if numCores == 0 {
numCores = vault.DefaultNumCores
}
ret.PerfSecondaryCluster, _ = GetClusterAndCore(t, logger.Named("perf-sec"), handlerFunc)
localopts := *opts
localopts.Logger = logger.Named("perf-pri")
ret.PerfPrimaryCluster, _ = ConfClusterAndCore(t, conf, &localopts)
ret.PerfPrimaryDRCluster, _ = GetClusterAndCore(t, logger.Named("perf-pri-dr"), handlerFunc)
localopts.Logger = logger.Named("perf-sec")
localopts.FirstCoreNumber += numCores
ret.PerfSecondaryCluster, _ = ConfClusterAndCore(t, conf, &localopts)
ret.PerfSecondaryDRCluster, _ = GetClusterAndCore(t, logger.Named("perf-sec-dr"), handlerFunc)
localopts.Logger = logger.Named("perf-pri-dr")
localopts.FirstCoreNumber += numCores
ret.PerfPrimaryDRCluster, _ = ConfClusterAndCore(t, conf, &localopts)
localopts.Logger = logger.Named("perf-sec-dr")
localopts.FirstCoreNumber += numCores
ret.PerfSecondaryDRCluster, _ = ConfClusterAndCore(t, conf, &localopts)
builder := &ReplicatedTestClustersBuilder{clusters: ret}
builder.setupFourClusterReplication(t)

View file

@ -237,9 +237,7 @@ func NewConsulBackend(conf map[string]string, logger log.Logger) (physical.Backe
logger.Debug("config address parsed", "scheme", parts[0])
logger.Debug("config scheme parsed", "address", parts[1])
}
} else {
return nil, errors.New("address should be host[:port], not URL")
}
} // allow "unix:" or whatever else consul supports in the future
}
}
if scheme, ok := conf["scheme"]; ok {

View file

@ -231,6 +231,24 @@ func TestConsul_newConsulBackend(t *testing.T) {
max_parallel: 4,
consistencyMode: "strong",
},
{
name: "Unix socket",
consulConfig: map[string]string{
"address": "unix:///tmp/.consul.http.sock",
},
address: "/tmp/.consul.http.sock",
scheme: "http", // Default, not overridden?
// Defaults
checkTimeout: 5 * time.Second,
redirectAddr: "http://127.0.0.1:8200",
path: "vault/",
service: "vault",
token: "",
max_parallel: 4,
disableReg: false,
consistencyMode: "default",
},
{
name: "Scheme in address",
consulConfig: map[string]string{

View file

@ -107,103 +107,92 @@ func testPostgresSQLLockTTL(t *testing.T, ha physical.HABackend) {
// Set much smaller lock times to speed up the test.
lockTTL := 3
renewInterval := time.Second * 1
watchInterval := time.Second * 1
retryInterval := time.Second * 1
longRenewInterval := time.Duration(lockTTL*2) * time.Second
lockkey := "postgresttl"
var leaderCh <-chan struct{}
// Get the lock
origLock, err := ha.LockWith("dynamodbttl", "bar")
origLock, err := ha.LockWith(lockkey, "bar")
if err != nil {
t.Fatalf("err: %v", err)
}
// set the first lock renew period to double the expected TTL.
lock := origLock.(*PostgreSQLLock)
lock.renewInterval = time.Duration(lockTTL*2) * time.Second
lock.ttlSeconds = lockTTL
// lock.retryInterval = watchInterval
{
// set the first lock renew period to double the expected TTL.
lock := origLock.(*PostgreSQLLock)
lock.renewInterval = longRenewInterval
lock.ttlSeconds = lockTTL
// Attempt to lock
leaderCh, err := lock.Lock(nil)
if err != nil {
t.Fatalf("err: %v", err)
}
if leaderCh == nil {
t.Fatalf("failed to get leader ch")
}
// Attempt to lock
leaderCh, err = lock.Lock(nil)
if err != nil {
t.Fatalf("err: %v", err)
}
if leaderCh == nil {
t.Fatalf("failed to get leader ch")
}
// Check the value
held, val, err := lock.Value()
if err != nil {
t.Fatalf("err: %v", err)
}
if !held {
t.Fatalf("should be held")
}
if val != "bar" {
t.Fatalf("bad value: %v", err)
// Check the value
held, val, err := lock.Value()
if err != nil {
t.Fatalf("err: %v", err)
}
if !held {
t.Fatalf("should be held")
}
if val != "bar" {
t.Fatalf("bad value: %v", val)
}
}
// Second acquisition should succeed because the first lock should
// not renew within the 3 sec TTL.
origLock2, err := ha.LockWith("dynamodbttl", "baz")
origLock2, err := ha.LockWith(lockkey, "baz")
if err != nil {
t.Fatalf("err: %v", err)
}
{
lock2 := origLock2.(*PostgreSQLLock)
lock2.renewInterval = renewInterval
lock2.ttlSeconds = lockTTL
lock2.retryInterval = retryInterval
lock2 := origLock2.(*PostgreSQLLock)
lock2.renewInterval = renewInterval
lock2.ttlSeconds = lockTTL
// lock2.retryInterval = watchInterval
// Cancel attempt in 6 sec so as not to block unit tests forever
stopCh := make(chan struct{})
time.AfterFunc(time.Duration(lockTTL*2)*time.Second, func() {
close(stopCh)
})
// Cancel attempt in 6 sec so as not to block unit tests forever
stopCh := make(chan struct{})
time.AfterFunc(time.Duration(lockTTL*2)*time.Second, func() {
close(stopCh)
})
// Attempt to lock should work
leaderCh2, err := lock2.Lock(stopCh)
if err != nil {
t.Fatalf("err: %v", err)
}
if leaderCh2 == nil {
t.Fatalf("should get leader ch")
}
defer lock2.Unlock()
// Attempt to lock should work
leaderCh2, err := lock2.Lock(stopCh)
if err != nil {
t.Fatalf("err: %v", err)
}
if leaderCh2 == nil {
t.Fatalf("should get leader ch")
}
// Check the value
held, val, err = lock2.Value()
if err != nil {
t.Fatalf("err: %v", err)
}
if !held {
t.Fatalf("should be held")
}
if val != "baz" {
t.Fatalf("bad value: %v", err)
// Check the value
held, val, err := lock2.Value()
if err != nil {
t.Fatalf("err: %v", err)
}
if !held {
t.Fatalf("should be held")
}
if val != "baz" {
t.Fatalf("bad value: %v", val)
}
}
// The first lock should have lost the leader channel
leaderChClosed := false
blocking := make(chan struct{})
// Attempt to read from the leader or the blocking channel, which ever one
// happens first.
go func() {
select {
case <-time.After(watchInterval * 3):
return
case <-leaderCh:
leaderChClosed = true
close(blocking)
case <-blocking:
return
}
}()
<-blocking
if !leaderChClosed {
select {
case <-time.After(longRenewInterval * 2):
t.Fatalf("original lock did not have its leader channel closed.")
case <-leaderCh:
}
// Cleanup
lock2.Unlock()
}
// Verify that once Unlock is called, we don't keep trying to renew the original
@ -237,7 +226,7 @@ func testPostgresSQLLockRenewal(t *testing.T, ha physical.HABackend) {
t.Fatalf("should be held")
}
if val != "bar" {
t.Fatalf("bad value: %v", err)
t.Fatalf("bad value: %v", val)
}
// Release the lock, which will delete the stored item
@ -280,7 +269,7 @@ func testPostgresSQLLockRenewal(t *testing.T, ha physical.HABackend) {
t.Fatalf("should be held")
}
if val != "baz" {
t.Fatalf("bad value: %v", err)
t.Fatalf("bad value: %v", val)
}
// Cleanup

View file

@ -21,7 +21,7 @@ RUN apt-get update -y && apt-get install -y -q nodejs yarn=1.12.1-1
RUN rm -rf /var/lib/apt/lists/*
ENV GOVERSION 1.12.4
ENV GOVERSION 1.12.6
RUN mkdir /goroot && mkdir /gopath
RUN curl https://storage.googleapis.com/golang/go${GOVERSION}.linux-amd64.tar.gz \
| tar xvzf - -C /goroot --strip-components=1

View file

@ -0,0 +1,233 @@
package tokenutil
import (
"errors"
"fmt"
"time"
sockaddr "github.com/hashicorp/go-sockaddr"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/parseutil"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/hashicorp/vault/sdk/logical"
)
// TokenParams contains a set of common parameters that auth plugins can use
// for setting token behavior
type TokenParams struct {
// The set of CIDRs that tokens generated using this role will be bound to
TokenBoundCIDRs []*sockaddr.SockAddrMarshaler `json:"token_bound_cidrs"`
// If set, the token entry will have an explicit maximum TTL set, rather
// than deferring to role/mount values
TokenExplicitMaxTTL time.Duration `json:"token_explicit_max_ttl" mapstructure:"token_explicit_max_ttl"`
// The max TTL to use for the token
TokenMaxTTL time.Duration `json:"token_max_ttl" mapstructure:"token_max_ttl"`
// If set, core will not automatically add default to the policy list
TokenNoDefaultPolicy bool `json:"token_no_default_policy" mapstructure:"token_no_default_policy"`
// The maximum number of times a token issued from this role may be used.
TokenNumUses int `json:"token_num_uses" mapstructure:"token_num_uses"`
// If non-zero, tokens created using this role will be able to be renewed
// forever, but will have a fixed renewal period of this value
TokenPeriod time.Duration `json:"token_period" mapstructure:"token_period"`
// The policies to set
TokenPolicies []string `json:"token_policies" mapstructure:"token_policies"`
// The type of token this role should issue
TokenType logical.TokenType `json:"token_type" mapstructure:"token_type"`
// The TTL to user for the token
TokenTTL time.Duration `json:"token_ttl" mapstructure:"token_ttl"`
}
// AddTokenFields adds fields to an existing role. It panics if it would
// overwrite an existing field.
func AddTokenFields(m map[string]*framework.FieldSchema) {
AddTokenFieldsWithAllowList(m, nil)
}
// AddTokenFields adds fields to an existing role. It panics if it would
// overwrite an existing field. Allowed can be use to restrict the set, e.g. if
// there would be conflicts.
func AddTokenFieldsWithAllowList(m map[string]*framework.FieldSchema, allowed []string) {
r := TokenFields()
for k, v := range r {
if len(allowed) > 0 && !strutil.StrListContains(allowed, k) {
continue
}
if _, has := m[k]; has {
panic(fmt.Sprintf("adding role field %s would overwrite existing field", k))
}
m[k] = v
}
}
// TokenFields provides a set of field schemas for the parameters
func TokenFields() map[string]*framework.FieldSchema {
return map[string]*framework.FieldSchema{
"token_bound_cidrs": &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: `Comma separated string or JSON list of CIDR blocks. If set, specifies the blocks of IP addresses which are allowed to use the generated token.`,
},
"token_explicit_max_ttl": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Description: tokenExplicitMaxTTLHelp,
},
"token_max_ttl": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Description: "The maximum lifetime of the generated token",
},
"token_no_default_policy": &framework.FieldSchema{
Type: framework.TypeBool,
Description: "If true, the 'default' policy will not automatically be added to generated tokens",
},
"token_period": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Description: tokenPeriodHelp,
},
"token_policies": &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: "Comma-separated list of policies",
},
"token_type": &framework.FieldSchema{
Type: framework.TypeString,
Default: "default-service",
Description: "The type of token to generate, service or batch",
},
"token_ttl": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Description: "The initial ttl of the token to generate",
},
"token_num_uses": &framework.FieldSchema{
Type: framework.TypeInt,
Description: "The maximum number of times a token may be used, a value of zero means unlimited",
},
}
}
// ParseTokenFields provides common field parsing functionality into a TokenFields struct
func (t *TokenParams) ParseTokenFields(req *logical.Request, d *framework.FieldData) error {
if boundCIDRsRaw, ok := d.GetOk("token_bound_cidrs"); ok {
boundCIDRs, err := parseutil.ParseAddrs(boundCIDRsRaw.([]string))
if err != nil {
return err
}
t.TokenBoundCIDRs = boundCIDRs
}
if explicitMaxTTLRaw, ok := d.GetOk("token_explicit_max_ttl"); ok {
t.TokenExplicitMaxTTL = time.Duration(explicitMaxTTLRaw.(int)) * time.Second
}
if maxTTLRaw, ok := d.GetOk("token_max_ttl"); ok {
t.TokenMaxTTL = time.Duration(maxTTLRaw.(int)) * time.Second
}
if t.TokenMaxTTL < 0 {
return errors.New("'token_max_ttl' cannot be negative")
}
if noDefaultRaw, ok := d.GetOk("token_no_default_policy"); ok {
t.TokenNoDefaultPolicy = noDefaultRaw.(bool)
}
if periodRaw, ok := d.GetOk("token_period"); ok {
t.TokenPeriod = time.Duration(periodRaw.(int)) * time.Second
}
if t.TokenPeriod < 0 {
return errors.New("'token_period' cannot be negative")
}
if policiesRaw, ok := d.GetOk("token_policies"); ok {
t.TokenPolicies = policiesRaw.([]string)
}
if tokenTypeRaw, ok := d.GetOk("token_type"); ok {
var tokenType logical.TokenType
tokenTypeStr := tokenTypeRaw.(string)
switch tokenTypeStr {
case "service":
tokenType = logical.TokenTypeService
case "batch":
tokenType = logical.TokenTypeBatch
case "", "default", "default-service":
tokenType = logical.TokenTypeDefaultService
case "default-batch":
tokenType = logical.TokenTypeDefaultBatch
default:
return fmt.Errorf("invalid 'token_type' value %q", tokenTypeStr)
}
t.TokenType = tokenType
}
if ttlRaw, ok := d.GetOk("token_ttl"); ok {
t.TokenTTL = time.Duration(ttlRaw.(int)) * time.Second
}
if t.TokenTTL < 0 {
return errors.New("'token_ttl' cannot be negative")
}
if t.TokenTTL > 0 && t.TokenMaxTTL > 0 && t.TokenTTL > t.TokenMaxTTL {
return errors.New("'token_ttl' cannot be greater than 'token_max_ttl'")
}
if tokenNumUses, ok := d.GetOk("token_num_uses"); ok {
t.TokenNumUses = tokenNumUses.(int)
}
if t.TokenNumUses < 0 {
return errors.New("'token_num_uses' cannot be negative")
}
return nil
}
// PopulateTokenData adds information from TokenParams into the map
func (t *TokenParams) PopulateTokenData(m map[string]interface{}) {
m["token_bound_cidrs"] = t.TokenBoundCIDRs
m["token_explicit_max_ttl"] = t.TokenExplicitMaxTTL.Seconds()
m["token_max_ttl"] = t.TokenMaxTTL.Seconds()
m["token_no_default_policy"] = t.TokenNoDefaultPolicy
m["token_period"] = t.TokenPeriod.Seconds()
m["token_policies"] = t.TokenPolicies
m["token_type"] = t.TokenType.String()
m["token_ttl"] = t.TokenTTL.Seconds()
m["token_num_uses"] = t.TokenNumUses
}
// PopulateTokenAuth populates Auth with parameters
func (t *TokenParams) PopulateTokenAuth(auth *logical.Auth) {
auth.BoundCIDRs = t.TokenBoundCIDRs
auth.ExplicitMaxTTL = t.TokenExplicitMaxTTL
auth.MaxTTL = t.TokenMaxTTL
auth.NoDefaultPolicy = t.TokenNoDefaultPolicy
auth.Period = t.TokenPeriod
auth.Policies = t.TokenPolicies
auth.TokenType = t.TokenType
auth.TTL = t.TokenTTL
auth.NumUses = t.TokenNumUses
}
const (
tokenPeriodHelp = `If set, tokens created via this role
will have no max lifetime; instead, their
renewal period will be fixed to this value.
This takes an integer number of seconds,
or a string duration (e.g. "24h").`
tokenExplicitMaxTTLHelp = `If set, tokens created via this role
carry an explicit maximum TTL. During renewal,
the current maximum TTL values of the role
and the mount are not checked for changes,
and any updates to these values will have
no effect on the token being renewed.`
)

View file

@ -38,6 +38,11 @@ type Auth struct {
// different namespaces indexed by respective namespace identifiers
ExternalNamespacePolicies map[string][]string `json:"external_namespace_policies" mapstructure:"external_namespace_policies" structs:"external_namespace_policies"`
// Indicates that the default policy should not be added by core when
// creating a token. The default policy will still be added if it's
// explicitly defined.
NoDefaultPolicy bool `json:"no_default_policy" mapstructure:"no_default_policy" structs:"no_default_policy"`
// Metadata is used to attach arbitrary string-type metadata to
// an authenticated user. This metadata will be outputted into the
// audit log.

View file

@ -72,6 +72,7 @@ type SystemView interface {
type ExtendedSystemView interface {
Auditor() Auditor
ForwardGenericRequest(context.Context, *Request) (*Response, error)
}
type StaticSystemView struct {
@ -104,6 +105,10 @@ func (d StaticSystemView) Auditor() Auditor {
return noopAuditor{}
}
func (d StaticSystemView) ForwardGenericRequest(ctx context.Context, req *Request) (*Response, error) {
return nil, errors.New("ForwardGenericRequest is not implemented in StaticSystemView")
}
func (d StaticSystemView) DefaultLeaseTTL() time.Duration {
return d.DefaultLeaseTTLVal
}

View file

@ -526,7 +526,9 @@ type Auth struct {
// TTL is a hard limit and cannot be exceeded, also counts for periodic tokens.
ExplicitMaxTTL int64 `sentinel:"" protobuf:"varint,16,opt,name=explicit_max_ttl,json=explicitMaxTtl,proto3" json:"explicit_max_ttl,omitempty"`
// TokenType is the type of token being requested
TokenType uint32 `sentinel:"" protobuf:"varint,17,opt,name=token_type,json=tokenType,proto3" json:"token_type,omitempty"`
TokenType uint32 `sentinel:"" protobuf:"varint,17,opt,name=token_type,json=tokenType,proto3" json:"token_type,omitempty"`
// Whether the default policy should be added automatically by core
NoDefaultPolicy bool `sentinel:"" protobuf:"varint,18,opt,name=no_default_policy,json=noDefaultPolicy,proto3" json:"no_default_policy,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -676,6 +678,13 @@ func (m *Auth) GetTokenType() uint32 {
return 0
}
func (m *Auth) GetNoDefaultPolicy() bool {
if m != nil {
return m.NoDefaultPolicy
}
return false
}
type TokenEntry struct {
ID string `sentinel:"" protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Accessor string `sentinel:"" protobuf:"bytes,2,opt,name=accessor,proto3" json:"accessor,omitempty"`
@ -2713,164 +2722,165 @@ func init() {
func init() { proto.RegisterFile("sdk/plugin/pb/backend.proto", fileDescriptor_4dbf1dfe0c11846b) }
var fileDescriptor_4dbf1dfe0c11846b = []byte{
// 2499 bytes of a gzipped FileDescriptorProto
// 2519 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0xdb, 0x72, 0x1b, 0xc7,
0xd1, 0x2e, 0x00, 0xc4, 0xa9, 0x71, 0x22, 0x46, 0xb4, 0xfe, 0x15, 0x24, 0xff, 0x82, 0xd7, 0x91,
0x0c, 0x2b, 0x36, 0x68, 0x51, 0x71, 0x2c, 0x27, 0x65, 0xa7, 0x68, 0x8a, 0x96, 0x19, 0x93, 0x36,
0x6b, 0x09, 0xc5, 0x39, 0x55, 0xc1, 0x83, 0xdd, 0x21, 0xb8, 0xc5, 0xc5, 0xee, 0x66, 0x76, 0x96,
0x22, 0xae, 0xf2, 0x16, 0x79, 0x8d, 0xdc, 0xa6, 0x72, 0x93, 0xbb, 0x94, 0x2b, 0xf7, 0x79, 0x8d,
0x3c, 0x43, 0x6a, 0x7a, 0x66, 0x4f, 0x00, 0x68, 0xc9, 0x55, 0xce, 0xdd, 0x4c, 0x77, 0xcf, 0xa9,
0xe7, 0xeb, 0xaf, 0x7b, 0x76, 0xe1, 0x6e, 0xe4, 0x5c, 0xee, 0x86, 0x5e, 0x3c, 0x77, 0xfd, 0xdd,
0x70, 0xb6, 0x3b, 0xa3, 0xf6, 0x25, 0xf3, 0x9d, 0x71, 0xc8, 0x03, 0x11, 0x90, 0x72, 0x38, 0x1b,
0xdc, 0x9f, 0x07, 0xc1, 0xdc, 0x63, 0xbb, 0x28, 0x99, 0xc5, 0xe7, 0xbb, 0xc2, 0x5d, 0xb0, 0x48,
0xd0, 0x45, 0xa8, 0x8c, 0x06, 0x03, 0x39, 0x83, 0x17, 0xcc, 0x5d, 0x9b, 0x7a, 0xbb, 0xae, 0xc3,
0x7c, 0xe1, 0x8a, 0xa5, 0xd6, 0x19, 0x79, 0x9d, 0x5a, 0x45, 0x69, 0xcc, 0x3a, 0x54, 0x0f, 0x17,
0xa1, 0x58, 0x9a, 0x43, 0xa8, 0x7d, 0xc1, 0xa8, 0xc3, 0x38, 0xb9, 0x0d, 0xb5, 0x0b, 0x6c, 0x19,
0xa5, 0x61, 0x65, 0xd4, 0xb4, 0x74, 0xcf, 0xfc, 0x03, 0xc0, 0xa9, 0x1c, 0x73, 0xc8, 0x79, 0xc0,
0xc9, 0x1d, 0x68, 0x30, 0xce, 0xa7, 0x62, 0x19, 0x32, 0xa3, 0x34, 0x2c, 0x8d, 0x3a, 0x56, 0x9d,
0x71, 0x3e, 0x59, 0x86, 0x8c, 0xfc, 0x1f, 0xc8, 0xe6, 0x74, 0x11, 0xcd, 0x8d, 0xf2, 0xb0, 0x24,
0x67, 0x60, 0x9c, 0x9f, 0x44, 0xf3, 0x64, 0x8c, 0x1d, 0x38, 0xcc, 0xa8, 0x0c, 0x4b, 0xa3, 0x0a,
0x8e, 0x39, 0x08, 0x1c, 0x66, 0xfe, 0xa5, 0x04, 0xd5, 0x53, 0x2a, 0x2e, 0x22, 0x42, 0x60, 0x8b,
0x07, 0x81, 0xd0, 0x8b, 0x63, 0x9b, 0x8c, 0xa0, 0x17, 0xfb, 0x34, 0x16, 0x17, 0xf2, 0x54, 0x36,
0x15, 0xcc, 0x31, 0xca, 0xa8, 0x5e, 0x15, 0x93, 0xb7, 0xa1, 0xe3, 0x05, 0x36, 0xf5, 0xa6, 0x91,
0x08, 0x38, 0x9d, 0xcb, 0x75, 0xa4, 0x5d, 0x1b, 0x85, 0x67, 0x4a, 0x46, 0x1e, 0x41, 0x3f, 0x62,
0xd4, 0x9b, 0xbe, 0xe4, 0x34, 0x4c, 0x0d, 0xb7, 0xd4, 0x84, 0x52, 0xf1, 0x0d, 0xa7, 0xa1, 0xb6,
0x35, 0xff, 0x51, 0x83, 0xba, 0xc5, 0xfe, 0x14, 0xb3, 0x48, 0x90, 0x2e, 0x94, 0x5d, 0x07, 0x4f,
0xdb, 0xb4, 0xca, 0xae, 0x43, 0xc6, 0x40, 0x2c, 0x16, 0x7a, 0x72, 0x69, 0x37, 0xf0, 0x0f, 0xbc,
0x38, 0x12, 0x8c, 0xeb, 0x33, 0x6f, 0xd0, 0x90, 0x7b, 0xd0, 0x0c, 0x42, 0xc6, 0x51, 0x86, 0x0e,
0x68, 0x5a, 0x99, 0x40, 0x1e, 0x3c, 0xa4, 0xe2, 0xc2, 0xd8, 0x42, 0x05, 0xb6, 0xa5, 0xcc, 0xa1,
0x82, 0x1a, 0x55, 0x25, 0x93, 0x6d, 0x62, 0x42, 0x2d, 0x62, 0x36, 0x67, 0xc2, 0xa8, 0x0d, 0x4b,
0xa3, 0xd6, 0x1e, 0x8c, 0xc3, 0xd9, 0xf8, 0x0c, 0x25, 0x96, 0xd6, 0x90, 0x7b, 0xb0, 0x25, 0xfd,
0x62, 0xd4, 0xd1, 0xa2, 0x21, 0x2d, 0xf6, 0x63, 0x71, 0x61, 0xa1, 0x94, 0xec, 0x41, 0x5d, 0xdd,
0x69, 0x64, 0x34, 0x86, 0x95, 0x51, 0x6b, 0xcf, 0x90, 0x06, 0xfa, 0x94, 0x63, 0x05, 0x83, 0xe8,
0xd0, 0x17, 0x7c, 0x69, 0x25, 0x86, 0xe4, 0x2d, 0x68, 0xdb, 0x9e, 0xcb, 0x7c, 0x31, 0x15, 0xc1,
0x25, 0xf3, 0x8d, 0x26, 0xee, 0xa8, 0xa5, 0x64, 0x13, 0x29, 0x22, 0x7b, 0xf0, 0x46, 0xde, 0x64,
0x4a, 0x6d, 0x9b, 0x45, 0x51, 0xc0, 0x0d, 0x40, 0xdb, 0x5b, 0x39, 0xdb, 0x7d, 0xad, 0x92, 0xd3,
0x3a, 0x6e, 0x14, 0x7a, 0x74, 0x39, 0xf5, 0xe9, 0x82, 0x19, 0x2d, 0x35, 0xad, 0x96, 0x7d, 0x45,
0x17, 0x8c, 0xdc, 0x87, 0xd6, 0x22, 0x88, 0x7d, 0x31, 0x0d, 0x03, 0xd7, 0x17, 0x46, 0x1b, 0x2d,
0x00, 0x45, 0xa7, 0x52, 0x42, 0xde, 0x04, 0xd5, 0x53, 0x60, 0xec, 0x28, 0xbf, 0xa2, 0x04, 0xe1,
0xf8, 0x00, 0xba, 0x4a, 0x9d, 0xee, 0xa7, 0x8b, 0x26, 0x1d, 0x94, 0xa6, 0x3b, 0xf9, 0x00, 0x9a,
0x88, 0x07, 0xd7, 0x3f, 0x0f, 0x8c, 0x1e, 0xfa, 0xed, 0x56, 0xce, 0x2d, 0x12, 0x13, 0x47, 0xfe,
0x79, 0x60, 0x35, 0x5e, 0xea, 0x16, 0xf9, 0x04, 0xee, 0x16, 0xce, 0xcb, 0xd9, 0x82, 0xba, 0xbe,
0xeb, 0xcf, 0xa7, 0x71, 0xc4, 0x22, 0x63, 0x1b, 0x11, 0x6e, 0xe4, 0x4e, 0x6d, 0x25, 0x06, 0x2f,
0x22, 0x16, 0x91, 0xbb, 0xd0, 0x54, 0x41, 0x3a, 0x75, 0x1d, 0xa3, 0x8f, 0x5b, 0x6a, 0x28, 0xc1,
0x91, 0x43, 0xde, 0x81, 0x5e, 0x18, 0x78, 0xae, 0xbd, 0x9c, 0x06, 0x57, 0x8c, 0x73, 0xd7, 0x61,
0x06, 0x19, 0x96, 0x46, 0x0d, 0xab, 0xab, 0xc4, 0x5f, 0x6b, 0xe9, 0xa6, 0xd0, 0xb8, 0x85, 0x86,
0x6b, 0xa1, 0x31, 0x06, 0xb0, 0x03, 0xdf, 0x67, 0x36, 0xc2, 0x6f, 0x07, 0x4f, 0xd8, 0x95, 0x27,
0x3c, 0x48, 0xa5, 0x56, 0xce, 0x62, 0xf0, 0x39, 0xb4, 0xf3, 0x50, 0x20, 0xdb, 0x50, 0xb9, 0x64,
0x4b, 0x0d, 0x7f, 0xd9, 0x24, 0x43, 0xa8, 0x5e, 0x51, 0x2f, 0x66, 0x08, 0x79, 0x0d, 0x44, 0x35,
0xc4, 0x52, 0x8a, 0x5f, 0x94, 0x9f, 0x96, 0xcc, 0xbf, 0x57, 0x61, 0x4b, 0x82, 0x8f, 0x7c, 0x08,
0x1d, 0x8f, 0xd1, 0x88, 0x4d, 0x83, 0x50, 0x2e, 0x10, 0xe1, 0x54, 0xad, 0xbd, 0x6d, 0x39, 0xec,
0x58, 0x2a, 0xbe, 0x56, 0x72, 0xab, 0xed, 0xe5, 0x7a, 0x32, 0xa4, 0x5d, 0x5f, 0x30, 0xee, 0x53,
0x6f, 0x8a, 0xc1, 0xa0, 0x02, 0xac, 0x9d, 0x08, 0x9f, 0xc9, 0xa0, 0x58, 0xc5, 0x51, 0x65, 0x1d,
0x47, 0x03, 0x68, 0xa0, 0xef, 0x5c, 0x16, 0xe9, 0x60, 0x4f, 0xfb, 0x64, 0x0f, 0x1a, 0x0b, 0x26,
0xa8, 0x8e, 0x35, 0x19, 0x12, 0xb7, 0x93, 0x98, 0x19, 0x9f, 0x68, 0x85, 0x0a, 0x88, 0xd4, 0x6e,
0x2d, 0x22, 0x6a, 0xeb, 0x11, 0x31, 0x80, 0x46, 0x0a, 0xba, 0xba, 0xba, 0xe1, 0xa4, 0x2f, 0x69,
0x36, 0x64, 0xdc, 0x0d, 0x1c, 0xa3, 0x81, 0x40, 0xd1, 0x3d, 0x49, 0x92, 0x7e, 0xbc, 0x50, 0x10,
0x6a, 0x2a, 0x92, 0xf4, 0xe3, 0xc5, 0x3a, 0x62, 0x60, 0x05, 0x31, 0x3f, 0x81, 0x2a, 0xf5, 0x5c,
0x1a, 0x61, 0x08, 0xc9, 0x9b, 0xd5, 0x7c, 0x3f, 0xde, 0x97, 0x52, 0x4b, 0x29, 0xc9, 0x13, 0xe8,
0xcc, 0x79, 0x10, 0x87, 0x53, 0xec, 0xb2, 0xc8, 0x68, 0xe3, 0x69, 0x57, 0xad, 0xdb, 0x68, 0xb4,
0xaf, 0x6c, 0x64, 0x04, 0xce, 0x82, 0xd8, 0x77, 0xa6, 0xb6, 0xeb, 0xf0, 0xc8, 0xe8, 0xa0, 0xf3,
0x00, 0x45, 0x07, 0x52, 0x22, 0x43, 0x4c, 0x85, 0x40, 0xea, 0xe0, 0x2e, 0xda, 0x74, 0x50, 0x7a,
0x9a, 0x78, 0xf9, 0xa7, 0xd0, 0x4f, 0x12, 0x53, 0x66, 0xd9, 0x43, 0xcb, 0xed, 0x44, 0x91, 0x1a,
0x8f, 0x60, 0x9b, 0x5d, 0x4b, 0x0a, 0x75, 0xc5, 0x74, 0x41, 0xaf, 0xa7, 0x42, 0x78, 0x3a, 0xa4,
0xba, 0x89, 0xfc, 0x84, 0x5e, 0x4f, 0x84, 0x27, 0xe3, 0x5f, 0xad, 0x8e, 0xf1, 0xdf, 0xc7, 0x64,
0xd4, 0x44, 0x89, 0x8c, 0xff, 0xc1, 0x2f, 0xa1, 0x53, 0xb8, 0xc2, 0x0d, 0x40, 0xde, 0xc9, 0x03,
0xb9, 0x99, 0x07, 0xef, 0xbf, 0xb6, 0x00, 0xf0, 0x2e, 0xd5, 0xd0, 0xd5, 0x0c, 0x90, 0xbf, 0xe0,
0xf2, 0x86, 0x0b, 0xa6, 0x9c, 0xf9, 0x42, 0x83, 0x51, 0xf7, 0xbe, 0x17, 0x87, 0x49, 0x0e, 0xa8,
0xe6, 0x72, 0xc0, 0x7b, 0xb0, 0x25, 0x31, 0x67, 0xd4, 0x32, 0xaa, 0xce, 0x76, 0x84, 0xe8, 0x54,
0xc8, 0x44, 0xab, 0xb5, 0x40, 0xa8, 0xaf, 0x07, 0x42, 0x1e, 0x61, 0x8d, 0x22, 0xc2, 0xde, 0x86,
0x8e, 0xcd, 0x19, 0xe6, 0xa3, 0xa9, 0x2c, 0x30, 0x34, 0x02, 0xdb, 0x89, 0x70, 0xe2, 0x2e, 0x98,
0xf4, 0x9f, 0xbc, 0x0c, 0x40, 0x95, 0x6c, 0x6e, 0xbc, 0xab, 0xd6, 0xc6, 0xbb, 0xc2, 0xec, 0xee,
0x31, 0xcd, 0xe2, 0xd8, 0xce, 0x45, 0x42, 0xa7, 0x10, 0x09, 0x05, 0xb8, 0x77, 0x57, 0xe0, 0xbe,
0x82, 0xc9, 0xde, 0x1a, 0x26, 0xdf, 0x82, 0xb6, 0x74, 0x40, 0x14, 0x52, 0x9b, 0xc9, 0x09, 0xb6,
0x95, 0x23, 0x52, 0xd9, 0x91, 0x83, 0x11, 0x1c, 0xcf, 0x66, 0xcb, 0x8b, 0xc0, 0x63, 0x19, 0x09,
0xb7, 0x52, 0xd9, 0x91, 0x23, 0xf7, 0x8b, 0xa8, 0x22, 0x88, 0x2a, 0x6c, 0x0f, 0x3e, 0x82, 0x66,
0xea, 0xf5, 0x1f, 0x04, 0xa6, 0xbf, 0x96, 0xa0, 0x9d, 0x27, 0x3a, 0x39, 0x78, 0x32, 0x39, 0xc6,
0xc1, 0x15, 0x4b, 0x36, 0x65, 0x89, 0xc0, 0x99, 0xcf, 0x5e, 0xd2, 0x99, 0xa7, 0x26, 0x68, 0x58,
0x99, 0x40, 0x6a, 0x5d, 0xdf, 0xe6, 0x6c, 0x91, 0xa0, 0xaa, 0x62, 0x65, 0x02, 0xf2, 0x31, 0x80,
0x1b, 0x45, 0x31, 0x53, 0x37, 0xb7, 0x85, 0x34, 0x30, 0x18, 0xab, 0xba, 0x71, 0x9c, 0xd4, 0x8d,
0xe3, 0x49, 0x52, 0x37, 0x5a, 0x4d, 0xb4, 0xc6, 0x2b, 0xbd, 0x0d, 0x35, 0x79, 0x41, 0x93, 0x63,
0x44, 0x5e, 0xc5, 0xd2, 0x3d, 0xf3, 0xcf, 0x50, 0x53, 0x95, 0xc5, 0xff, 0x94, 0xbc, 0xef, 0x40,
0x43, 0xcd, 0xed, 0x3a, 0x3a, 0x56, 0xea, 0xd8, 0x3f, 0x72, 0xcc, 0xef, 0xca, 0xd0, 0xb0, 0x58,
0x14, 0x06, 0x7e, 0xc4, 0x72, 0x95, 0x4f, 0xe9, 0x95, 0x95, 0x4f, 0x79, 0x63, 0xe5, 0x93, 0xd4,
0x53, 0x95, 0x5c, 0x3d, 0x35, 0x80, 0x06, 0x67, 0x8e, 0xcb, 0x99, 0x2d, 0x74, 0xed, 0x95, 0xf6,
0xa5, 0xee, 0x25, 0xe5, 0x32, 0x65, 0x47, 0x98, 0x17, 0x9a, 0x56, 0xda, 0x27, 0x8f, 0xf3, 0x05,
0x83, 0x2a, 0xc5, 0x76, 0x54, 0xc1, 0xa0, 0xb6, 0xbb, 0xa1, 0x62, 0x78, 0x92, 0x15, 0x5e, 0x75,
0x8c, 0xe6, 0x3b, 0xf9, 0x01, 0x9b, 0x2b, 0xaf, 0x1f, 0x2d, 0x0f, 0x7f, 0x57, 0x86, 0xed, 0xd5,
0xbd, 0x6d, 0x40, 0xe0, 0x0e, 0x54, 0x55, 0x3e, 0xd3, 0xf0, 0x15, 0x6b, 0x99, 0xac, 0xb2, 0x42,
0x74, 0xbf, 0x5a, 0x25, 0x8d, 0x57, 0x43, 0xaf, 0x48, 0x28, 0xef, 0xc2, 0xb6, 0x74, 0x51, 0xc8,
0x9c, 0xac, 0x46, 0x53, 0x0c, 0xd8, 0xd3, 0xf2, 0xb4, 0x4a, 0x7b, 0x04, 0xfd, 0xc4, 0x34, 0xe3,
0x86, 0x5a, 0xc1, 0xf6, 0x30, 0xa1, 0x88, 0xdb, 0x50, 0x3b, 0x0f, 0xf8, 0x82, 0x0a, 0x4d, 0x82,
0xba, 0x57, 0x20, 0x39, 0x64, 0xdb, 0x86, 0xc2, 0x64, 0x22, 0x94, 0xef, 0x10, 0x49, 0x3e, 0xe9,
0x1b, 0x01, 0x59, 0xb0, 0x61, 0x35, 0x92, 0xb7, 0x81, 0xf9, 0x5b, 0xe8, 0xad, 0x94, 0x85, 0x1b,
0x1c, 0x99, 0x2d, 0x5f, 0x2e, 0x2c, 0x5f, 0x98, 0xb9, 0xb2, 0x32, 0xf3, 0xef, 0xa0, 0xff, 0x05,
0xf5, 0x1d, 0x8f, 0xe9, 0xf9, 0xf7, 0xf9, 0x3c, 0x92, 0x09, 0x4e, 0xbf, 0x52, 0xa6, 0x3a, 0xfb,
0x74, 0xac, 0xa6, 0x96, 0x1c, 0x39, 0xe4, 0x01, 0xd4, 0xb9, 0xb2, 0xd6, 0x00, 0x68, 0xe5, 0xea,
0x56, 0x2b, 0xd1, 0x99, 0xdf, 0x02, 0x29, 0x4c, 0x2d, 0x1f, 0x28, 0x4b, 0x32, 0x92, 0xe8, 0x57,
0xa0, 0xd0, 0x51, 0xd5, 0xce, 0x63, 0xd2, 0x4a, 0xb5, 0x64, 0x08, 0x15, 0xc6, 0xb9, 0x5e, 0x02,
0x0b, 0xc7, 0xec, 0x39, 0x68, 0x49, 0x95, 0xf9, 0x33, 0xe8, 0x9f, 0x85, 0xcc, 0x76, 0xa9, 0x87,
0x4f, 0x39, 0xb5, 0xc0, 0x7d, 0xa8, 0x4a, 0x27, 0x27, 0x84, 0xd1, 0xc4, 0x81, 0xa8, 0x56, 0x72,
0xf3, 0x5b, 0x30, 0xd4, 0xbe, 0x0e, 0xaf, 0xdd, 0x48, 0x30, 0xdf, 0x66, 0x07, 0x17, 0xcc, 0xbe,
0xfc, 0x11, 0x4f, 0x7e, 0x05, 0x77, 0x36, 0xad, 0x90, 0xec, 0xaf, 0x65, 0xcb, 0xde, 0xf4, 0x5c,
0xe6, 0x0e, 0x5c, 0xa3, 0x61, 0x01, 0x8a, 0x3e, 0x97, 0x12, 0x79, 0x8f, 0x4c, 0x8e, 0x8b, 0x34,
0x1f, 0xeb, 0x5e, 0xe2, 0x8f, 0xca, 0xcd, 0xfe, 0xf8, 0x5b, 0x09, 0x9a, 0x67, 0x4c, 0xc4, 0x21,
0x9e, 0xe5, 0x2e, 0x34, 0x67, 0x3c, 0xb8, 0x64, 0x3c, 0x3b, 0x4a, 0x43, 0x09, 0x8e, 0x1c, 0xf2,
0x18, 0x6a, 0x07, 0x81, 0x7f, 0xee, 0xce, 0xf1, 0x61, 0xab, 0x89, 0x21, 0x1d, 0x3b, 0x56, 0x3a,
0x45, 0x0c, 0xda, 0x90, 0x0c, 0xa1, 0xa5, 0x3f, 0x13, 0xbc, 0x78, 0x71, 0xf4, 0x2c, 0xa9, 0x78,
0x73, 0xa2, 0xc1, 0xc7, 0xd0, 0xca, 0x0d, 0xfc, 0x41, 0xa9, 0xea, 0xff, 0x01, 0x70, 0x75, 0xe5,
0xa3, 0x6d, 0x75, 0x54, 0x3d, 0x52, 0x1e, 0xed, 0x3e, 0x34, 0x65, 0x71, 0xa5, 0xd4, 0x49, 0x92,
0x2c, 0x65, 0x49, 0xd2, 0x7c, 0x00, 0xfd, 0x23, 0xff, 0x8a, 0x7a, 0xae, 0x43, 0x05, 0xfb, 0x92,
0x2d, 0xd1, 0x05, 0x6b, 0x3b, 0x30, 0xcf, 0xa0, 0xad, 0x5f, 0xda, 0xaf, 0xb5, 0xc7, 0xb6, 0xde,
0xe3, 0xf7, 0x07, 0xd1, 0xbb, 0xd0, 0xd3, 0x93, 0x1e, 0xbb, 0x3a, 0x84, 0x64, 0x8d, 0xc1, 0xd9,
0xb9, 0x7b, 0xad, 0xa7, 0xd6, 0x3d, 0xf3, 0x29, 0x6c, 0xe7, 0x4c, 0xd3, 0xe3, 0x5c, 0xb2, 0x65,
0x94, 0x7c, 0x81, 0x90, 0xed, 0xc4, 0x03, 0xe5, 0xcc, 0x03, 0x26, 0x74, 0xf5, 0xc8, 0xe7, 0x4c,
0xdc, 0x70, 0xba, 0x2f, 0xd3, 0x8d, 0x3c, 0x67, 0x7a, 0xf2, 0x87, 0x50, 0x65, 0xf2, 0xa4, 0xf9,
0xfc, 0x99, 0xf7, 0x80, 0xa5, 0xd4, 0x1b, 0x16, 0x7c, 0x9a, 0x2e, 0x78, 0x1a, 0xab, 0x05, 0x5f,
0x73, 0x2e, 0xf3, 0xed, 0x74, 0x1b, 0xa7, 0xb1, 0xb8, 0xe9, 0x46, 0x1f, 0x40, 0x5f, 0x1b, 0x3d,
0x63, 0x1e, 0x13, 0xec, 0x86, 0x23, 0x3d, 0x04, 0x52, 0x30, 0xbb, 0x69, 0xba, 0x7b, 0xd0, 0x98,
0x4c, 0x8e, 0x53, 0x6d, 0x91, 0x1b, 0xcd, 0x4f, 0xa0, 0x7f, 0x16, 0x3b, 0xc1, 0x29, 0x77, 0xaf,
0x5c, 0x8f, 0xcd, 0xd5, 0x62, 0x49, 0xf1, 0x5b, 0xca, 0x15, 0xbf, 0x1b, 0xb3, 0x91, 0x39, 0x02,
0x52, 0x18, 0x9e, 0xde, 0x5b, 0x14, 0x3b, 0x81, 0x0e, 0x61, 0x6c, 0x9b, 0x23, 0x68, 0x4f, 0xa8,
0x2c, 0x36, 0x1c, 0x65, 0x63, 0x40, 0x5d, 0xa8, 0xbe, 0x36, 0x4b, 0xba, 0xe6, 0x1e, 0xec, 0x1c,
0x50, 0xfb, 0xc2, 0xf5, 0xe7, 0xcf, 0xdc, 0x48, 0x56, 0x5b, 0x7a, 0xc4, 0x00, 0x1a, 0x8e, 0x16,
0xe8, 0x21, 0x69, 0xdf, 0x7c, 0x1f, 0xde, 0xc8, 0x7d, 0xe6, 0x39, 0x13, 0x34, 0xf1, 0xc7, 0x0e,
0x54, 0x23, 0xd9, 0xc3, 0x11, 0x55, 0x4b, 0x75, 0xcc, 0xaf, 0x60, 0x27, 0x9f, 0x80, 0x65, 0xed,
0x93, 0x1c, 0x1c, 0xab, 0x92, 0x52, 0xae, 0x2a, 0xd1, 0x3e, 0x2b, 0x67, 0xf9, 0x64, 0x1b, 0x2a,
0xbf, 0xfe, 0x66, 0xa2, 0xc1, 0x2e, 0x9b, 0xe6, 0x1f, 0xe5, 0xf2, 0xc5, 0xf9, 0xd4, 0xf2, 0x85,
0xd2, 0xa4, 0xf4, 0x5a, 0xa5, 0xc9, 0x3a, 0xde, 0xde, 0x87, 0xfe, 0x89, 0x17, 0xd8, 0x97, 0x87,
0x7e, 0xce, 0x1b, 0x06, 0xd4, 0x99, 0x9f, 0x77, 0x46, 0xd2, 0x35, 0xdf, 0x81, 0xde, 0x71, 0x60,
0x53, 0xef, 0x24, 0x88, 0x7d, 0x91, 0x7a, 0x01, 0xbf, 0xbb, 0x69, 0x53, 0xd5, 0x31, 0xdf, 0x87,
0xae, 0x4e, 0xd1, 0xfe, 0x79, 0x90, 0x30, 0x63, 0x96, 0xcc, 0x4b, 0xc5, 0x42, 0xdf, 0x3c, 0x86,
0x5e, 0x66, 0xae, 0xe6, 0x7d, 0x07, 0x6a, 0x4a, 0xad, 0xcf, 0xd6, 0x4b, 0x5f, 0xaf, 0xca, 0xd2,
0xd2, 0xea, 0x0d, 0x87, 0x5a, 0x40, 0xf7, 0x14, 0xbf, 0x7f, 0x1e, 0xfa, 0x57, 0x6a, 0xb2, 0x23,
0x20, 0xea, 0x8b, 0xe8, 0x94, 0xf9, 0x57, 0x2e, 0x0f, 0x7c, 0x2c, 0xae, 0x4b, 0xba, 0x84, 0x49,
0x26, 0x4e, 0x07, 0x25, 0x16, 0x56, 0x3f, 0x5c, 0x15, 0x6d, 0xf4, 0x21, 0x64, 0x5f, 0x57, 0x64,
0xaa, 0xe1, 0x6c, 0x11, 0x08, 0x36, 0xa5, 0x8e, 0x93, 0x44, 0x0b, 0x28, 0xd1, 0xbe, 0xe3, 0xf0,
0xbd, 0xff, 0x94, 0xa1, 0xfe, 0x99, 0x22, 0x70, 0xf2, 0x29, 0x74, 0x0a, 0xe9, 0x9a, 0xbc, 0x81,
0x65, 0xdd, 0x6a, 0x71, 0x30, 0xb8, 0xbd, 0x26, 0x56, 0xe7, 0xfa, 0x00, 0xda, 0xf9, 0x64, 0x4c,
0x30, 0xf1, 0xe2, 0xb7, 0xde, 0x01, 0xce, 0xb4, 0x9e, 0xa9, 0xcf, 0x60, 0x67, 0x53, 0x9a, 0x24,
0xf7, 0xb2, 0x15, 0xd6, 0x53, 0xf4, 0xe0, 0xcd, 0x9b, 0xb4, 0x49, 0x7a, 0xad, 0x1f, 0x78, 0x8c,
0xfa, 0x71, 0x98, 0xdf, 0x41, 0xd6, 0x24, 0x8f, 0xa1, 0x53, 0x48, 0x14, 0xea, 0x9c, 0x6b, 0xb9,
0x23, 0x3f, 0xe4, 0x21, 0x54, 0x31, 0x39, 0x91, 0x4e, 0x21, 0x4b, 0x0e, 0xba, 0x69, 0x57, 0xad,
0x3d, 0x84, 0x2d, 0xfc, 0x02, 0x98, 0x5b, 0x18, 0x47, 0xa4, 0x99, 0x6b, 0xef, 0xdf, 0x25, 0xa8,
0x27, 0x5f, 0x85, 0x1f, 0xc3, 0x96, 0xcc, 0x01, 0xe4, 0x56, 0x8e, 0x46, 0x93, 0xfc, 0x31, 0xd8,
0x59, 0x11, 0xaa, 0x05, 0xc6, 0x50, 0x79, 0xce, 0x04, 0x21, 0x39, 0xa5, 0x4e, 0x06, 0x83, 0x5b,
0x45, 0x59, 0x6a, 0x7f, 0x1a, 0x17, 0xed, 0x35, 0x97, 0x17, 0xec, 0x53, 0x96, 0xfe, 0x08, 0x6a,
0x8a, 0x65, 0x95, 0x53, 0xd6, 0xf8, 0x59, 0x5d, 0xfe, 0x3a, 0x1f, 0xef, 0xfd, 0x73, 0x0b, 0xe0,
0x6c, 0x19, 0x09, 0xb6, 0xf8, 0x8d, 0xcb, 0x5e, 0x92, 0x47, 0xd0, 0x7b, 0xc6, 0xce, 0x69, 0xec,
0x09, 0x7c, 0xaa, 0x49, 0x36, 0xc9, 0xf9, 0x04, 0x0b, 0xbe, 0x94, 0xac, 0x1f, 0x42, 0xeb, 0x84,
0x5e, 0xbf, 0xda, 0xee, 0x53, 0xe8, 0x14, 0x38, 0x58, 0x6f, 0x71, 0x95, 0xd5, 0xf5, 0x16, 0xd7,
0xd9, 0xfa, 0x21, 0xd4, 0x35, 0x33, 0xe7, 0xd7, 0xc0, 0x1c, 0x56, 0x60, 0xec, 0x9f, 0x43, 0x6f,
0x85, 0x97, 0xf3, 0xf6, 0xf8, 0x39, 0x64, 0x23, 0x6f, 0x3f, 0x95, 0xaf, 0x9d, 0x22, 0x37, 0xe7,
0x07, 0xea, 0x97, 0xd7, 0x26, 0xf2, 0x7e, 0x5e, 0x7c, 0x27, 0xe1, 0x13, 0xd5, 0x58, 0xa5, 0xcf,
0x84, 0xbc, 0x07, 0x77, 0x36, 0x69, 0xd2, 0x10, 0xcc, 0x33, 0xe8, 0x5a, 0x08, 0xae, 0xd3, 0xeb,
0x7b, 0x00, 0x19, 0x89, 0xe6, 0xed, 0x11, 0x1e, 0xab, 0xfc, 0xfa, 0x21, 0x40, 0x46, 0x8d, 0x0a,
0x55, 0x45, 0x66, 0x55, 0xc3, 0x56, 0xe9, 0xf3, 0x11, 0x34, 0x53, 0x3a, 0xcb, 0xaf, 0x81, 0x13,
0x14, 0xd9, 0xf1, 0xb3, 0x47, 0xbf, 0x1f, 0xcd, 0x5d, 0x71, 0x11, 0xcf, 0xc6, 0x76, 0xb0, 0xd8,
0xbd, 0xa0, 0xd1, 0x85, 0x6b, 0x07, 0x3c, 0xdc, 0xbd, 0x92, 0x60, 0xda, 0x2d, 0xfc, 0xb4, 0x9a,
0xd5, 0xf0, 0xa1, 0xf7, 0xe4, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x5b, 0x0c, 0x01, 0xf3, 0xcc,
0x1a, 0x00, 0x00,
0x0c, 0x33, 0x36, 0x68, 0xd1, 0x71, 0x2c, 0x27, 0x65, 0xa7, 0x68, 0x8a, 0x96, 0x19, 0x93, 0x36,
0x6b, 0x09, 0xc7, 0x39, 0x55, 0xc1, 0x83, 0xdd, 0x21, 0xb8, 0xc5, 0xc5, 0xee, 0x66, 0x76, 0x96,
0x22, 0xae, 0xf2, 0x16, 0x79, 0x8d, 0xdc, 0xe6, 0x2e, 0x77, 0x29, 0x57, 0xee, 0xf3, 0x0a, 0xb9,
0xcc, 0x33, 0xa4, 0xa6, 0x67, 0xf6, 0x04, 0x80, 0x96, 0x5c, 0xe5, 0xdc, 0xcd, 0x74, 0xf7, 0x9c,
0x7a, 0xbe, 0xfe, 0xba, 0x67, 0x17, 0xee, 0x47, 0xce, 0xd5, 0x5e, 0xe8, 0xc5, 0x73, 0xd7, 0xdf,
0x0b, 0x67, 0x7b, 0x33, 0x6a, 0x5f, 0x31, 0xdf, 0x19, 0x87, 0x3c, 0x10, 0x01, 0x29, 0x87, 0xb3,
0xc1, 0xc3, 0x79, 0x10, 0xcc, 0x3d, 0xb6, 0x87, 0x92, 0x59, 0x7c, 0xb1, 0x27, 0xdc, 0x05, 0x8b,
0x04, 0x5d, 0x84, 0xca, 0x68, 0x30, 0x90, 0x33, 0x78, 0xc1, 0xdc, 0xb5, 0xa9, 0xb7, 0xe7, 0x3a,
0xcc, 0x17, 0xae, 0x58, 0x6a, 0x9d, 0x91, 0xd7, 0xa9, 0x55, 0x94, 0xc6, 0xac, 0x43, 0xf5, 0x68,
0x11, 0x8a, 0xa5, 0x39, 0x84, 0xda, 0xe7, 0x8c, 0x3a, 0x8c, 0x93, 0xbb, 0x50, 0xbb, 0xc4, 0x96,
0x51, 0x1a, 0x56, 0x46, 0x4d, 0x4b, 0xf7, 0xcc, 0x3f, 0x00, 0x9c, 0xc9, 0x31, 0x47, 0x9c, 0x07,
0x9c, 0xdc, 0x83, 0x06, 0xe3, 0x7c, 0x2a, 0x96, 0x21, 0x33, 0x4a, 0xc3, 0xd2, 0xa8, 0x63, 0xd5,
0x19, 0xe7, 0x93, 0x65, 0xc8, 0xc8, 0xff, 0x81, 0x6c, 0x4e, 0x17, 0xd1, 0xdc, 0x28, 0x0f, 0x4b,
0x72, 0x06, 0xc6, 0xf9, 0x69, 0x34, 0x4f, 0xc6, 0xd8, 0x81, 0xc3, 0x8c, 0xca, 0xb0, 0x34, 0xaa,
0xe0, 0x98, 0xc3, 0xc0, 0x61, 0xe6, 0x5f, 0x4a, 0x50, 0x3d, 0xa3, 0xe2, 0x32, 0x22, 0x04, 0xb6,
0x78, 0x10, 0x08, 0xbd, 0x38, 0xb6, 0xc9, 0x08, 0x7a, 0xb1, 0x4f, 0x63, 0x71, 0x29, 0x4f, 0x65,
0x53, 0xc1, 0x1c, 0xa3, 0x8c, 0xea, 0x55, 0x31, 0x79, 0x13, 0x3a, 0x5e, 0x60, 0x53, 0x6f, 0x1a,
0x89, 0x80, 0xd3, 0xb9, 0x5c, 0x47, 0xda, 0xb5, 0x51, 0x78, 0xae, 0x64, 0x64, 0x17, 0xfa, 0x11,
0xa3, 0xde, 0xf4, 0x05, 0xa7, 0x61, 0x6a, 0xb8, 0xa5, 0x26, 0x94, 0x8a, 0x6f, 0x38, 0x0d, 0xb5,
0xad, 0xf9, 0xf7, 0x1a, 0xd4, 0x2d, 0xf6, 0xa7, 0x98, 0x45, 0x82, 0x74, 0xa1, 0xec, 0x3a, 0x78,
0xda, 0xa6, 0x55, 0x76, 0x1d, 0x32, 0x06, 0x62, 0xb1, 0xd0, 0x93, 0x4b, 0xbb, 0x81, 0x7f, 0xe8,
0xc5, 0x91, 0x60, 0x5c, 0x9f, 0x79, 0x83, 0x86, 0x3c, 0x80, 0x66, 0x10, 0x32, 0x8e, 0x32, 0x74,
0x40, 0xd3, 0xca, 0x04, 0xf2, 0xe0, 0x21, 0x15, 0x97, 0xc6, 0x16, 0x2a, 0xb0, 0x2d, 0x65, 0x0e,
0x15, 0xd4, 0xa8, 0x2a, 0x99, 0x6c, 0x13, 0x13, 0x6a, 0x11, 0xb3, 0x39, 0x13, 0x46, 0x6d, 0x58,
0x1a, 0xb5, 0xf6, 0x61, 0x1c, 0xce, 0xc6, 0xe7, 0x28, 0xb1, 0xb4, 0x86, 0x3c, 0x80, 0x2d, 0xe9,
0x17, 0xa3, 0x8e, 0x16, 0x0d, 0x69, 0x71, 0x10, 0x8b, 0x4b, 0x0b, 0xa5, 0x64, 0x1f, 0xea, 0xea,
0x4e, 0x23, 0xa3, 0x31, 0xac, 0x8c, 0x5a, 0xfb, 0x86, 0x34, 0xd0, 0xa7, 0x1c, 0x2b, 0x18, 0x44,
0x47, 0xbe, 0xe0, 0x4b, 0x2b, 0x31, 0x24, 0x6f, 0x40, 0xdb, 0xf6, 0x5c, 0xe6, 0x8b, 0xa9, 0x08,
0xae, 0x98, 0x6f, 0x34, 0x71, 0x47, 0x2d, 0x25, 0x9b, 0x48, 0x11, 0xd9, 0x87, 0xd7, 0xf2, 0x26,
0x53, 0x6a, 0xdb, 0x2c, 0x8a, 0x02, 0x6e, 0x00, 0xda, 0xde, 0xc9, 0xd9, 0x1e, 0x68, 0x95, 0x9c,
0xd6, 0x71, 0xa3, 0xd0, 0xa3, 0xcb, 0xa9, 0x4f, 0x17, 0xcc, 0x68, 0xa9, 0x69, 0xb5, 0xec, 0x4b,
0xba, 0x60, 0xe4, 0x21, 0xb4, 0x16, 0x41, 0xec, 0x8b, 0x69, 0x18, 0xb8, 0xbe, 0x30, 0xda, 0x68,
0x01, 0x28, 0x3a, 0x93, 0x12, 0xf2, 0x3a, 0xa8, 0x9e, 0x02, 0x63, 0x47, 0xf9, 0x15, 0x25, 0x08,
0xc7, 0x47, 0xd0, 0x55, 0xea, 0x74, 0x3f, 0x5d, 0x34, 0xe9, 0xa0, 0x34, 0xdd, 0xc9, 0x7b, 0xd0,
0x44, 0x3c, 0xb8, 0xfe, 0x45, 0x60, 0xf4, 0xd0, 0x6f, 0x77, 0x72, 0x6e, 0x91, 0x98, 0x38, 0xf6,
0x2f, 0x02, 0xab, 0xf1, 0x42, 0xb7, 0xc8, 0xc7, 0x70, 0xbf, 0x70, 0x5e, 0xce, 0x16, 0xd4, 0xf5,
0x5d, 0x7f, 0x3e, 0x8d, 0x23, 0x16, 0x19, 0xdb, 0x88, 0x70, 0x23, 0x77, 0x6a, 0x2b, 0x31, 0xf8,
0x3a, 0x62, 0x11, 0xb9, 0x0f, 0x4d, 0x15, 0xa4, 0x53, 0xd7, 0x31, 0xfa, 0xb8, 0xa5, 0x86, 0x12,
0x1c, 0x3b, 0xe4, 0x2d, 0xe8, 0x85, 0x81, 0xe7, 0xda, 0xcb, 0x69, 0x70, 0xcd, 0x38, 0x77, 0x1d,
0x66, 0x90, 0x61, 0x69, 0xd4, 0xb0, 0xba, 0x4a, 0xfc, 0x95, 0x96, 0x6e, 0x0a, 0x8d, 0x3b, 0x68,
0xb8, 0x16, 0x1a, 0x63, 0x00, 0x3b, 0xf0, 0x7d, 0x66, 0x23, 0xfc, 0x76, 0xf0, 0x84, 0x5d, 0x79,
0xc2, 0xc3, 0x54, 0x6a, 0xe5, 0x2c, 0x06, 0x9f, 0x41, 0x3b, 0x0f, 0x05, 0xb2, 0x0d, 0x95, 0x2b,
0xb6, 0xd4, 0xf0, 0x97, 0x4d, 0x32, 0x84, 0xea, 0x35, 0xf5, 0x62, 0x86, 0x90, 0xd7, 0x40, 0x54,
0x43, 0x2c, 0xa5, 0xf8, 0x45, 0xf9, 0x69, 0xc9, 0xfc, 0x77, 0x15, 0xb6, 0x24, 0xf8, 0xc8, 0x07,
0xd0, 0xf1, 0x18, 0x8d, 0xd8, 0x34, 0x08, 0xe5, 0x02, 0x11, 0x4e, 0xd5, 0xda, 0xdf, 0x96, 0xc3,
0x4e, 0xa4, 0xe2, 0x2b, 0x25, 0xb7, 0xda, 0x5e, 0xae, 0x27, 0x43, 0xda, 0xf5, 0x05, 0xe3, 0x3e,
0xf5, 0xa6, 0x18, 0x0c, 0x2a, 0xc0, 0xda, 0x89, 0xf0, 0x99, 0x0c, 0x8a, 0x55, 0x1c, 0x55, 0xd6,
0x71, 0x34, 0x80, 0x06, 0xfa, 0xce, 0x65, 0x91, 0x0e, 0xf6, 0xb4, 0x4f, 0xf6, 0xa1, 0xb1, 0x60,
0x82, 0xea, 0x58, 0x93, 0x21, 0x71, 0x37, 0x89, 0x99, 0xf1, 0xa9, 0x56, 0xa8, 0x80, 0x48, 0xed,
0xd6, 0x22, 0xa2, 0xb6, 0x1e, 0x11, 0x03, 0x68, 0xa4, 0xa0, 0xab, 0xab, 0x1b, 0x4e, 0xfa, 0x92,
0x66, 0x43, 0xc6, 0xdd, 0xc0, 0x31, 0x1a, 0x08, 0x14, 0xdd, 0x93, 0x24, 0xe9, 0xc7, 0x0b, 0x05,
0xa1, 0xa6, 0x22, 0x49, 0x3f, 0x5e, 0xac, 0x23, 0x06, 0x56, 0x10, 0xf3, 0x13, 0xa8, 0x52, 0xcf,
0xa5, 0x11, 0x86, 0x90, 0xbc, 0x59, 0xcd, 0xf7, 0xe3, 0x03, 0x29, 0xb5, 0x94, 0x92, 0xbc, 0x0f,
0x9d, 0x39, 0x0f, 0xe2, 0x70, 0x8a, 0x5d, 0x16, 0x19, 0x6d, 0x3c, 0xed, 0xaa, 0x75, 0x1b, 0x8d,
0x0e, 0x94, 0x8d, 0x8c, 0xc0, 0x59, 0x10, 0xfb, 0xce, 0xd4, 0x76, 0x1d, 0x1e, 0x19, 0x1d, 0x74,
0x1e, 0xa0, 0xe8, 0x50, 0x4a, 0x64, 0x88, 0xa9, 0x10, 0x48, 0x1d, 0xdc, 0x45, 0x9b, 0x0e, 0x4a,
0xcf, 0x12, 0x2f, 0xff, 0x14, 0xfa, 0x49, 0x62, 0xca, 0x2c, 0x7b, 0x68, 0xb9, 0x9d, 0x28, 0x52,
0xe3, 0x11, 0x6c, 0xb3, 0x1b, 0x49, 0xa1, 0xae, 0x98, 0x2e, 0xe8, 0xcd, 0x54, 0x08, 0x4f, 0x87,
0x54, 0x37, 0x91, 0x9f, 0xd2, 0x9b, 0x89, 0xf0, 0x64, 0xfc, 0xab, 0xd5, 0x31, 0xfe, 0xfb, 0x98,
0x8c, 0x9a, 0x28, 0xc1, 0xf8, 0xdf, 0x85, 0xbe, 0x1f, 0x4c, 0x1d, 0x76, 0x41, 0x63, 0x4f, 0xa8,
0x75, 0x97, 0x3a, 0x98, 0x7a, 0x7e, 0xf0, 0x4c, 0xc9, 0x71, 0xd9, 0xe5, 0xe0, 0x97, 0xd0, 0x29,
0x5c, 0xf7, 0x06, 0xd0, 0xef, 0xe4, 0x41, 0xdf, 0xcc, 0x03, 0xfd, 0x9f, 0x5b, 0x00, 0x78, 0xef,
0x6a, 0xe8, 0x6a, 0xb6, 0xc8, 0x83, 0xa1, 0xbc, 0x01, 0x0c, 0x94, 0x33, 0x5f, 0x68, 0xe0, 0xea,
0xde, 0xf7, 0x62, 0x36, 0xc9, 0x17, 0xd5, 0x5c, 0xbe, 0x78, 0x07, 0xb6, 0x24, 0x3e, 0x8d, 0x5a,
0x46, 0xeb, 0xd9, 0x8e, 0x10, 0xc9, 0x0a, 0xc5, 0x68, 0xb5, 0x16, 0x34, 0xf5, 0xf5, 0xa0, 0xc9,
0xa3, 0xb1, 0x51, 0x44, 0xe3, 0x9b, 0xd0, 0xb1, 0x39, 0xc3, 0xdc, 0x35, 0x95, 0xc5, 0x88, 0x46,
0x6b, 0x3b, 0x11, 0x4e, 0xdc, 0x05, 0x93, 0xfe, 0x93, 0x17, 0x07, 0xa8, 0x92, 0xcd, 0x8d, 0xf7,
0xda, 0xda, 0x78, 0xaf, 0x58, 0x09, 0x78, 0x4c, 0x33, 0x3e, 0xb6, 0x73, 0x51, 0xd3, 0x29, 0x44,
0x4d, 0x21, 0x34, 0xba, 0x2b, 0xa1, 0xb1, 0x82, 0xdf, 0xde, 0x1a, 0x7e, 0xdf, 0x80, 0xb6, 0x74,
0x40, 0x14, 0x52, 0x9b, 0xc9, 0x09, 0xb6, 0x95, 0x23, 0x52, 0xd9, 0xb1, 0x83, 0xd1, 0x1e, 0xcf,
0x66, 0xcb, 0xcb, 0xc0, 0x63, 0x19, 0x61, 0xb7, 0x52, 0xd9, 0xb1, 0x23, 0xf7, 0x8b, 0x08, 0x24,
0x88, 0x40, 0x6c, 0x0f, 0x3e, 0x84, 0x66, 0xea, 0xf5, 0x1f, 0x04, 0xa6, 0xbf, 0x96, 0xa0, 0x9d,
0x27, 0x45, 0x39, 0x78, 0x32, 0x39, 0xc1, 0xc1, 0x15, 0x4b, 0x36, 0x65, 0x39, 0xc1, 0x99, 0xcf,
0x5e, 0xd0, 0x99, 0xa7, 0x26, 0x68, 0x58, 0x99, 0x40, 0x6a, 0x5d, 0xdf, 0xe6, 0x6c, 0x91, 0xa0,
0xaa, 0x62, 0x65, 0x02, 0xf2, 0x11, 0x80, 0x1b, 0x45, 0x31, 0x53, 0x37, 0xb7, 0x85, 0x94, 0x31,
0x18, 0xab, 0x1a, 0x73, 0x9c, 0xd4, 0x98, 0xe3, 0x49, 0x52, 0x63, 0x5a, 0x4d, 0xb4, 0xc6, 0x2b,
0xbd, 0x0b, 0x35, 0x79, 0x41, 0x93, 0x13, 0x44, 0x5e, 0xc5, 0xd2, 0x3d, 0xf3, 0xcf, 0x50, 0x53,
0x55, 0xc8, 0xff, 0x94, 0xe8, 0xef, 0x41, 0x43, 0xcd, 0xed, 0x3a, 0x3a, 0x56, 0xea, 0xd8, 0x3f,
0x76, 0xcc, 0xef, 0xca, 0xd0, 0xb0, 0x58, 0x14, 0x06, 0x7e, 0xc4, 0x72, 0x55, 0x52, 0xe9, 0xa5,
0x55, 0x52, 0x79, 0x63, 0x95, 0x94, 0xd4, 0x5e, 0x95, 0x5c, 0xed, 0x35, 0x80, 0x06, 0x67, 0x8e,
0xcb, 0x99, 0x2d, 0x74, 0x9d, 0x96, 0xf6, 0xa5, 0xee, 0x05, 0xe5, 0x32, 0xbd, 0x47, 0x98, 0x43,
0x9a, 0x56, 0xda, 0x27, 0x4f, 0xf2, 0xc5, 0x85, 0x2a, 0xdb, 0x76, 0x54, 0x71, 0xa1, 0xb6, 0xbb,
0xa1, 0xba, 0x78, 0x3f, 0x2b, 0xd2, 0xea, 0x18, 0xcd, 0xf7, 0xf2, 0x03, 0x36, 0x57, 0x69, 0x3f,
0x5a, 0xce, 0xfe, 0xae, 0x0c, 0xdb, 0xab, 0x7b, 0xdb, 0x80, 0xc0, 0x1d, 0xa8, 0xaa, 0xdc, 0xa7,
0xe1, 0x2b, 0xd6, 0xb2, 0x5e, 0x65, 0x85, 0xe8, 0x7e, 0xb5, 0x4a, 0x1a, 0x2f, 0x87, 0x5e, 0x91,
0x50, 0xde, 0x86, 0x6d, 0xe9, 0xa2, 0x90, 0x39, 0x59, 0x3d, 0xa7, 0x18, 0xb0, 0xa7, 0xe5, 0x69,
0x45, 0xb7, 0x0b, 0xfd, 0xc4, 0x34, 0xe3, 0x86, 0x5a, 0xc1, 0xf6, 0x28, 0xa1, 0x88, 0xbb, 0x50,
0xbb, 0x08, 0xf8, 0x82, 0x0a, 0x4d, 0x82, 0xba, 0x57, 0x20, 0x39, 0x64, 0xdb, 0x86, 0xc2, 0x64,
0x22, 0x94, 0x6f, 0x16, 0x49, 0x3e, 0xe9, 0x7b, 0x02, 0x59, 0xb0, 0x61, 0x35, 0x92, 0x77, 0x84,
0xf9, 0x5b, 0xe8, 0xad, 0x94, 0x90, 0x1b, 0x1c, 0x99, 0x2d, 0x5f, 0x2e, 0x2c, 0x5f, 0x98, 0xb9,
0xb2, 0x32, 0xf3, 0xef, 0xa0, 0xff, 0x39, 0xf5, 0x1d, 0x8f, 0xe9, 0xf9, 0x0f, 0xf8, 0x3c, 0x92,
0xc9, 0x50, 0xbf, 0x68, 0xa6, 0x3a, 0xfb, 0x74, 0xac, 0xa6, 0x96, 0x1c, 0x3b, 0xe4, 0x11, 0xd4,
0xb9, 0xb2, 0xd6, 0x00, 0x68, 0xe5, 0x6a, 0x5c, 0x2b, 0xd1, 0x99, 0xdf, 0x02, 0x29, 0x4c, 0x2d,
0x1f, 0x33, 0x4b, 0x32, 0x92, 0xe8, 0x57, 0xa0, 0xd0, 0x51, 0xd5, 0xce, 0x63, 0xd2, 0x4a, 0xb5,
0x64, 0x08, 0x15, 0xc6, 0xb9, 0x5e, 0x02, 0x8b, 0xcc, 0xec, 0xe9, 0x68, 0x49, 0x95, 0xf9, 0x33,
0xe8, 0x9f, 0x87, 0xcc, 0x76, 0xa9, 0x87, 0xcf, 0x3e, 0xb5, 0xc0, 0x43, 0xa8, 0x4a, 0x27, 0x27,
0x84, 0xd1, 0xc4, 0x81, 0xa8, 0x56, 0x72, 0xf3, 0x5b, 0x30, 0xd4, 0xbe, 0x8e, 0x6e, 0xdc, 0x48,
0x30, 0xdf, 0x66, 0x87, 0x97, 0xcc, 0xbe, 0xfa, 0x11, 0x4f, 0x7e, 0x0d, 0xf7, 0x36, 0xad, 0x90,
0xec, 0xaf, 0x65, 0xcb, 0xde, 0xf4, 0x42, 0xe6, 0x0e, 0x5c, 0xa3, 0x61, 0x01, 0x8a, 0x3e, 0x93,
0x12, 0x79, 0x8f, 0x4c, 0x8e, 0x8b, 0x34, 0x1f, 0xeb, 0x5e, 0xe2, 0x8f, 0xca, 0xed, 0xfe, 0xf8,
0x5b, 0x09, 0x9a, 0xe7, 0x4c, 0xc4, 0x21, 0x9e, 0xe5, 0x3e, 0x34, 0x67, 0x3c, 0xb8, 0x62, 0x3c,
0x3b, 0x4a, 0x43, 0x09, 0x8e, 0x1d, 0xf2, 0x04, 0x6a, 0x87, 0x81, 0x7f, 0xe1, 0xce, 0xf1, 0x11,
0xac, 0x89, 0x21, 0x1d, 0x3b, 0x56, 0x3a, 0x45, 0x0c, 0xda, 0x90, 0x0c, 0xa1, 0xa5, 0x3f, 0x29,
0x7c, 0xfd, 0xf5, 0xf1, 0xb3, 0xa4, 0x3a, 0xce, 0x89, 0x06, 0x1f, 0x41, 0x2b, 0x37, 0xf0, 0x07,
0xa5, 0xaa, 0xff, 0x07, 0xc0, 0xd5, 0x95, 0x8f, 0xb6, 0xd5, 0x51, 0xf5, 0x48, 0x79, 0xb4, 0x87,
0xd0, 0x94, 0x85, 0x98, 0x52, 0x27, 0x49, 0xb2, 0x94, 0x25, 0x49, 0xf3, 0x11, 0xf4, 0x8f, 0xfd,
0x6b, 0xea, 0xb9, 0x0e, 0x15, 0xec, 0x0b, 0xb6, 0x44, 0x17, 0xac, 0xed, 0xc0, 0x3c, 0x87, 0xb6,
0x7e, 0x95, 0xbf, 0xd2, 0x1e, 0xdb, 0x7a, 0x8f, 0xdf, 0x1f, 0x44, 0x6f, 0x43, 0x4f, 0x4f, 0x7a,
0xe2, 0xea, 0x10, 0x92, 0x35, 0x06, 0x67, 0x17, 0xee, 0x8d, 0x9e, 0x5a, 0xf7, 0xcc, 0xa7, 0xb0,
0x9d, 0x33, 0x4d, 0x8f, 0x73, 0xc5, 0x96, 0x51, 0xf2, 0xb5, 0x42, 0xb6, 0x13, 0x0f, 0x94, 0x33,
0x0f, 0x98, 0xd0, 0xd5, 0x23, 0x9f, 0x33, 0x71, 0xcb, 0xe9, 0xbe, 0x48, 0x37, 0xf2, 0x9c, 0xe9,
0xc9, 0x1f, 0x43, 0x95, 0xc9, 0x93, 0xe6, 0xf3, 0x67, 0xde, 0x03, 0x96, 0x52, 0x6f, 0x58, 0xf0,
0x69, 0xba, 0xe0, 0x59, 0xac, 0x16, 0x7c, 0xc5, 0xb9, 0xcc, 0x37, 0xd3, 0x6d, 0x9c, 0xc5, 0xe2,
0xb6, 0x1b, 0x7d, 0x04, 0x7d, 0x6d, 0xf4, 0x8c, 0x79, 0x4c, 0xb0, 0x5b, 0x8e, 0xf4, 0x18, 0x48,
0xc1, 0xec, 0xb6, 0xe9, 0x1e, 0x40, 0x63, 0x32, 0x39, 0x49, 0xb5, 0x45, 0x6e, 0x34, 0x3f, 0x86,
0xfe, 0x79, 0xec, 0x04, 0x67, 0xdc, 0xbd, 0x76, 0x3d, 0x36, 0x57, 0x8b, 0x25, 0xc5, 0x6f, 0x29,
0x57, 0xfc, 0x6e, 0xcc, 0x46, 0xe6, 0x08, 0x48, 0x61, 0x78, 0x7a, 0x6f, 0x51, 0xec, 0x04, 0x3a,
0x84, 0xb1, 0x6d, 0x8e, 0xa0, 0x3d, 0xa1, 0xb2, 0xd8, 0x70, 0x94, 0x8d, 0x01, 0x75, 0xa1, 0xfa,
0xda, 0x2c, 0xe9, 0x9a, 0xfb, 0xb0, 0x73, 0x48, 0xed, 0x4b, 0xd7, 0x9f, 0x3f, 0x73, 0x23, 0x59,
0x6d, 0xe9, 0x11, 0x03, 0x68, 0x38, 0x5a, 0xa0, 0x87, 0xa4, 0x7d, 0xf3, 0x5d, 0x78, 0x2d, 0xf7,
0x49, 0xe8, 0x5c, 0xd0, 0xc4, 0x1f, 0x3b, 0x50, 0x8d, 0x64, 0x0f, 0x47, 0x54, 0x2d, 0xd5, 0x31,
0xbf, 0x84, 0x9d, 0x7c, 0x02, 0x96, 0xb5, 0x4f, 0x72, 0x70, 0xac, 0x4a, 0x4a, 0xb9, 0xaa, 0x44,
0xfb, 0xac, 0x9c, 0xe5, 0x93, 0x6d, 0xa8, 0xfc, 0xfa, 0x9b, 0x89, 0x06, 0xbb, 0x6c, 0x9a, 0x7f,
0x94, 0xcb, 0x17, 0xe7, 0x53, 0xcb, 0x17, 0x4a, 0x93, 0xd2, 0x2b, 0x95, 0x26, 0xeb, 0x78, 0x7b,
0x17, 0xfa, 0xa7, 0x5e, 0x60, 0x5f, 0x1d, 0xf9, 0x39, 0x6f, 0x18, 0x50, 0x67, 0x7e, 0xde, 0x19,
0x49, 0xd7, 0x7c, 0x0b, 0x7a, 0x27, 0x81, 0x4d, 0xbd, 0xd3, 0x20, 0xf6, 0x45, 0xea, 0x05, 0xfc,
0x46, 0xa7, 0x4d, 0x55, 0xc7, 0x7c, 0x17, 0xba, 0x3a, 0x45, 0xfb, 0x17, 0x41, 0xc2, 0x8c, 0x59,
0x32, 0x2f, 0x15, 0x0b, 0x7d, 0xf3, 0x04, 0x7a, 0x99, 0xb9, 0x9a, 0xf7, 0x2d, 0xa8, 0x29, 0xb5,
0x3e, 0x5b, 0x2f, 0x7d, 0xe9, 0x2a, 0x4b, 0x4b, 0xab, 0x37, 0x1c, 0x6a, 0x01, 0xdd, 0x33, 0xfc,
0x56, 0x7a, 0xe4, 0x5f, 0xab, 0xc9, 0x8e, 0x81, 0xa8, 0xaf, 0xa7, 0x53, 0xe6, 0x5f, 0xbb, 0x3c,
0xf0, 0xb1, 0xb8, 0x2e, 0xe9, 0x12, 0x26, 0x99, 0x38, 0x1d, 0x94, 0x58, 0x58, 0xfd, 0x70, 0x55,
0xb4, 0xd1, 0x87, 0x90, 0x7d, 0x89, 0x91, 0xa9, 0x86, 0xb3, 0x45, 0x20, 0xd8, 0x94, 0x3a, 0x4e,
0x12, 0x2d, 0xa0, 0x44, 0x07, 0x8e, 0xc3, 0xf7, 0xff, 0x53, 0x86, 0xfa, 0xa7, 0x8a, 0xc0, 0xc9,
0x27, 0xd0, 0x29, 0xa4, 0x6b, 0xf2, 0x1a, 0x96, 0x75, 0xab, 0xc5, 0xc1, 0xe0, 0xee, 0x9a, 0x58,
0x9d, 0xeb, 0x3d, 0x68, 0xe7, 0x93, 0x31, 0xc1, 0xc4, 0x8b, 0xdf, 0x85, 0x07, 0x38, 0xd3, 0x7a,
0xa6, 0x3e, 0x87, 0x9d, 0x4d, 0x69, 0x92, 0x3c, 0xc8, 0x56, 0x58, 0x4f, 0xd1, 0x83, 0xd7, 0x6f,
0xd3, 0x26, 0xe9, 0xb5, 0x7e, 0xe8, 0x31, 0xea, 0xc7, 0x61, 0x7e, 0x07, 0x59, 0x93, 0x3c, 0x81,
0x4e, 0x21, 0x51, 0xa8, 0x73, 0xae, 0xe5, 0x8e, 0xfc, 0x90, 0xc7, 0x50, 0xc5, 0xe4, 0x44, 0x3a,
0x85, 0x2c, 0x39, 0xe8, 0xa6, 0x5d, 0xb5, 0xf6, 0x10, 0xb6, 0xf0, 0x6b, 0x41, 0x6e, 0x61, 0x1c,
0x91, 0x66, 0xae, 0xfd, 0x7f, 0x95, 0xa0, 0x9e, 0x7c, 0x41, 0x7e, 0x02, 0x5b, 0x32, 0x07, 0x90,
0x3b, 0x39, 0x1a, 0x4d, 0xf2, 0xc7, 0x60, 0x67, 0x45, 0xa8, 0x16, 0x18, 0x43, 0xe5, 0x39, 0x13,
0x84, 0xe4, 0x94, 0x3a, 0x19, 0x0c, 0xee, 0x14, 0x65, 0xa9, 0xfd, 0x59, 0x5c, 0xb4, 0xd7, 0x5c,
0x5e, 0xb0, 0x4f, 0x59, 0xfa, 0x43, 0xa8, 0x29, 0x96, 0x55, 0x4e, 0x59, 0xe3, 0x67, 0x75, 0xf9,
0xeb, 0x7c, 0xbc, 0xff, 0x8f, 0x2d, 0x80, 0xf3, 0x65, 0x24, 0xd8, 0xe2, 0x37, 0x2e, 0x7b, 0x41,
0x76, 0xa1, 0xa7, 0xbf, 0x89, 0xe0, 0x53, 0x4d, 0xb2, 0x49, 0xce, 0x27, 0x58, 0xf0, 0xa5, 0x64,
0xfd, 0x18, 0x5a, 0xa7, 0xf4, 0xe6, 0xe5, 0x76, 0x9f, 0x40, 0xa7, 0xc0, 0xc1, 0x7a, 0x8b, 0xab,
0xac, 0xae, 0xb7, 0xb8, 0xce, 0xd6, 0x8f, 0xa1, 0xae, 0x99, 0x39, 0xbf, 0x06, 0xe6, 0xb0, 0x02,
0x63, 0xff, 0x1c, 0x7a, 0x2b, 0xbc, 0x9c, 0xb7, 0xc7, 0xcf, 0x21, 0x1b, 0x79, 0xfb, 0xa9, 0x7c,
0xed, 0x14, 0xb9, 0x39, 0x3f, 0x50, 0xbf, 0xbc, 0x36, 0x91, 0xf7, 0xf3, 0xe2, 0x3b, 0x09, 0x9f,
0xa8, 0xc6, 0x2a, 0x7d, 0x26, 0xe4, 0x3d, 0xb8, 0xb7, 0x49, 0x93, 0x86, 0x60, 0x9e, 0x41, 0xd7,
0x42, 0x70, 0x9d, 0x5e, 0xdf, 0x01, 0xc8, 0x48, 0x34, 0x6f, 0x8f, 0xf0, 0x58, 0xe5, 0xd7, 0x0f,
0x00, 0x32, 0x6a, 0x54, 0xa8, 0x2a, 0x32, 0xab, 0x1a, 0xb6, 0x4a, 0x9f, 0xbb, 0xd0, 0x4c, 0xe9,
0x2c, 0xbf, 0x06, 0x4e, 0x50, 0x64, 0xc7, 0x4f, 0x77, 0x7f, 0x3f, 0x9a, 0xbb, 0xe2, 0x32, 0x9e,
0x8d, 0xed, 0x60, 0xb1, 0x77, 0x49, 0xa3, 0x4b, 0xd7, 0x0e, 0x78, 0xb8, 0x77, 0x2d, 0xc1, 0xb4,
0x57, 0xf8, 0xc1, 0x35, 0xab, 0xe1, 0x43, 0xef, 0xfd, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xbd,
0xc6, 0x6e, 0xfa, 0xf8, 0x1a, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View file

@ -210,6 +210,9 @@ message Auth {
// TokenType is the type of token being requested
uint32 token_type = 17;
// Whether the default policy should be added automatically by core
bool no_default_policy = 18;
}
message TokenEntry {

View file

@ -507,6 +507,7 @@ func LogicalAuthToProtoAuth(a *logical.Auth) (*Auth, error) {
Policies: a.Policies,
TokenPolicies: a.TokenPolicies,
IdentityPolicies: a.IdentityPolicies,
NoDefaultPolicy: a.NoDefaultPolicy,
Metadata: a.Metadata,
ClientToken: a.ClientToken,
Accessor: a.Accessor,
@ -554,6 +555,7 @@ func ProtoAuthToLogicalAuth(a *Auth) (*logical.Auth, error) {
Policies: a.Policies,
TokenPolicies: a.TokenPolicies,
IdentityPolicies: a.IdentityPolicies,
NoDefaultPolicy: a.NoDefaultPolicy,
Metadata: a.Metadata,
ClientToken: a.ClientToken,
Accessor: a.Accessor,

View file

@ -1,18 +0,0 @@
import { computed } from '@ember/object';
import Component from '@ember/component';
export default Component.extend({
tagName: 'span',
classNames: 'tag is-outlined edition-badge',
attributeBindings: ['edition:aria-label'],
icon: computed('edition', function() {
const edition = this.get('edition');
const entEditions = ['Enterprise', 'Premium', 'Pro'];
if (entEditions.includes(edition)) {
return 'edition-enterprise';
} else {
return 'edition-oss';
}
}),
});

View file

@ -2,7 +2,7 @@
align-items: center;
color: $grey;
display: flex;
background: $ui-gray-050;
background: $ui-gray-010;
justify-content: center;
padding: $spacing-xxl $spacing-s;
box-shadow: 0 -2px 0 -1px $ui-gray-300;

View file

@ -1,63 +0,0 @@
.upgrade-overlay {
font-size: 1rem;
opacity: 0;
text-align: left;
transition: opacity $speed-slow;
will-change: opacity;
z-index: 300;
&.is-animated {
opacity: 1;
}
.modal-background {
background-image: url('/ui/vault-hex.svg'), linear-gradient(90deg, #191a1c, #1b212d);
opacity: 0.97;
}
.modal-content {
overflow: auto;
overflow-x: hidden;
transform: translateY(20%) scale(0.9);
transition: transform $speed-slow;
will-change: transform;
}
&.is-animated {
.modal-content {
transform: translateY(0) scale(1);
}
}
.upgrade-overlay-title {
border-bottom: 1px solid $grey;
padding-bottom: $size-10;
.icon {
width: 32px;
#edition-enterprise-hexagon {
fill: $white;
}
}
}
.columns {
margin-bottom: $size-4;
margin-top: $size-4;
}
.column {
display: flex;
.box {
border-radius: $radius;
box-shadow: inset 0 0 0 1px $grey;
width: 100%;
}
}
li {
list-style: inside disc;
}
}

View file

@ -81,7 +81,6 @@
@import './components/toolbar';
@import './components/tool-tip';
@import './components/unseal-warning';
@import './components/upgrade-overlay';
@import './components/ui-wizard';
@import './components/vault-loading';

View file

@ -1,4 +0,0 @@
{{#if icon}}
<Icon @glyph={{icon}} />
{{/if}}
{{edition}}

View file

@ -1,76 +1,67 @@
<div class="popup-menu-content">
<div class="box">
{{#if (and activeCluster.unsealed auth.currentToken)}}
{{#if (has-permission 'status' routeParams='replication')}}
<nav class="menu">
<p class="menu-label">Replication</p>
<ul>
{{#if cluster.anyReplicationEnabled}}
<li>
{{#link-to
"vault.cluster.replication.mode.index"
"dr"
disabled=(not currentToken)
invokeAction=(action onLinkClick)
}}
{{replication-mode-summary
mode="dr"
display='menu'
cluster=cluster
}}
{{/link-to}}
</li>
<li>
{{#if (has-feature "Performance Replication")}}
{{#unless version.isOSS}}
{{#if (and activeCluster.unsealed auth.currentToken)}}
{{#if (has-permission 'status' routeParams='replication')}}
<nav class="menu">
<p class="menu-label">Replication</p>
<ul>
{{#if cluster.anyReplicationEnabled}}
<li>
{{#link-to
"vault.cluster.replication.mode.index"
"performance"
"dr"
disabled=(not currentToken)
invokeAction=(action onLinkClick)
}}
{{replication-mode-summary
mode="dr"
display='menu'
cluster=cluster
}}
{{/link-to}}
</li>
<li>
{{#if (has-feature "Performance Replication")}}
{{#link-to
"vault.cluster.replication.mode.index"
"performance"
disabled=(not currentToken)
invokeAction=(action onLinkClick)
}}
{{replication-mode-summary
mode="performance"
display="menu"
cluster=cluster
tagName="span"
}}
{{/link-to}}
{{else}}
{{replication-mode-summary
mode="performance"
display="menu"
cluster=cluster
tagName="span"
class="menu-item"
}}
{{/link-to}}
{{else}}
{{replication-mode-summary
mode="performance"
display="menu"
cluster=cluster
class="menu-item"
{{/if}}
</li>
{{else}}
<li>
{{#link-to "vault.cluster.replication"
invokeAction=(action onLinkClick)
}}
{{/if}}
</li>
{{else if version.isOSS}}
<li>
{{#link-to "vault.cluster.replication"}}
<div class="level is-mobile">
<span class="level-left">Learn more</span>
<Icon @glyph="edition-enterprise" @class="level-right" />
</div>
{{/link-to}}
</li>
{{else}}
<li>
{{#link-to "vault.cluster.replication"
invokeAction=(action onLinkClick)
}}
<div class="level is-mobile">
<span class="level-left">Enable</span>
<Icon @glyph="minus-circle-outline" @class="has-text-grey-light level-right" />
</div>
{{/link-to}}
</li>
{{/if}}
</ul>
</nav>
<hr/>
<div class="level is-mobile">
<span class="level-left">Enable</span>
<Icon @glyph="plus-circle-outline" @class="has-text-grey-light level-right" />
</div>
{{/link-to}}
</li>
{{/if}}
</ul>
</nav>
<hr/>
{{/if}}
{{/if}}
{{/if}}
{{#unless version.isOSS}}
{{#if (has-permission 'status' routeParams='license')}}
<nav class="menu">
<div class="menu-label">

View file

@ -14,9 +14,12 @@
</span>
{{#if (is-version "OSS")}}
<span>
{{#upgrade-link linkClass="has-text-grey"}}
<a
href="https://hashicorp.com/products/vault/trial?source=vaultui"
class="link has-text-grey"
>
Upgrade to Vault Enterprise
{{/upgrade-link}}
</a>
</span>
{{/if}}
<span>

View file

@ -28,29 +28,17 @@
{{/link-to}}
</li>
{{/if}}
{{#if (has-permission "access" routeParams="namespaces")}}
{{#if (and (has-feature "Namespaces") (has-permission "access" routeParams="namespaces"))}}
<li>
{{#link-to "vault.cluster.access.namespaces" data-test-link=true }}
Namespaces
{{#unless (has-feature "Namespaces")}}
{{#if (is-version "OSS")}}
{{edition-badge edition="Enterprise"}}
{{/if}}
{{/unless}}
{{/link-to}}
</li>
{{/if}}
{{#if (has-permission "access" routeParams="control-groups")}}
{{#if (and (has-feature "Control Groups") (has-permission "access" routeParams="control-groups"))}}
<li>
{{#link-to "vault.cluster.access.control-groups" data-test-link=true current-when="vault.cluster.access.control-groups vault.cluster.access.control-group-accessor vault.cluster.access.control-groups-configure"}}
Control Groups
{{#unless (has-feature "Control Groups")}}
{{#if (is-version "OSS")}}
{{edition-badge edition="Enterprise"}}
{{else}}
{{edition-badge edition="Premium"}}
{{/if}}
{{/unless}}
{{/link-to}}
</li>
{{/if}}

View file

@ -1,44 +1,32 @@
<div class="columns">
{{#menu-sidebar title="Policies" class="is-3" data-test-sidebar=true}}
{{#if (has-permission "policies" routeParams="acl")}}
<li>
{{#link-to "vault.cluster.policies" "acl" data-test-link=true class=(if (is-active-route "vault.cluster.policies" "acl") "is-active")}}
ACL Policies
{{/link-to}}
</li>
{{/if}}
{{#if (has-permission "policies" routeParams="rgp")}}
<li>
{{#link-to "vault.cluster.policies" "rgp" data-test-link=true class=(if (is-active-route "vault.cluster.policies" "rgp") "is-active")}}
Role Governing Policies
{{#unless (has-feature "Sentinel")}}
{{#if (is-version "OSS")}}
{{edition-badge edition="Enterprise"}}
{{else}}
{{edition-badge edition="Premium"}}
{{/if}}
{{/unless}}
{{/link-to}}
</li>
{{/if}}
{{#if (has-permission "policies" routeParams="egp")}}
<li>
{{#link-to "vault.cluster.policies" "egp" data-test-link=true class=(if (is-active-route "vault.cluster.policies" "egp") "is-active")}}
Endpoint Governing Policies
{{#unless (has-feature "Sentinel")}}
{{#if (is-version "OSS")}}
{{edition-badge edition="Enterprise"}}
{{else}}
{{edition-badge edition="Premium"}}
{{/if}}
{{/unless}}
{{/link-to}}
</li>
{{/if}}
{{/menu-sidebar}}
<div class="column is-9">
{{outlet}}
{{#if (and (has-feature "Sentinel") (or (has-permission "policies" routeParams="rgp") (has-permission "policies" routeParams="egp")))}}
<div class="columns">
{{#menu-sidebar title="Policies" class="is-3" data-test-sidebar=true}}
{{#if (has-permission "policies" routeParams="acl")}}
<li>
{{#link-to "vault.cluster.policies" "acl" data-test-link=true class=(if (is-active-route "vault.cluster.policies" "acl") "is-active")}}
ACL Policies
{{/link-to}}
</li>
{{/if}}
{{#if (has-permission "policies" routeParams="rgp")}}
<li>
{{#link-to "vault.cluster.policies" "rgp" data-test-link=true class=(if (is-active-route "vault.cluster.policies" "rgp") "is-active")}}
Role Governing Policies
{{/link-to}}
</li>
{{/if}}
{{#if (has-permission "policies" routeParams="egp")}}
<li>
{{#link-to "vault.cluster.policies" "egp" data-test-link=true class=(if (is-active-route "vault.cluster.policies" "egp") "is-active")}}
Endpoint Governing Policies
{{/link-to}}
</li>
{{/if}}
{{/menu-sidebar}}
<div class="column is-9">
{{outlet}}
</div>
</div>
</div>
{{else}}
{{outlet}}
{{/if}}

View file

@ -156,9 +156,11 @@
>
{{#link-to "vault.cluster.policies.create" class="link"}}
Create {{uppercase policyType}} policy
<Chevron />
{{/link-to}}
<LearnLink @path="/vault/getting-started/policies">
Learn more
<Chevron />
</LearnLink>
</EmptyState>
{{/if}}

View file

@ -7,33 +7,21 @@
{{/link-to}}
</li>
{{/if}}
{{#if (has-permission "policies" routeParams="rgp")}}
<li>
{{#link-to "vault.cluster.policies" "rgp" data-test-link=true class=(if (is-active-route "vault.cluster.policy" "rgp") "is-active")}}
Role Governing Policies
{{#unless (has-feature "Sentinel")}}
{{#if (is-version "OSS")}}
{{edition-badge edition="Enterprise"}}
{{else}}
{{edition-badge edition="Premium"}}
{{/if}}
{{/unless}}
{{/link-to}}
</li>
{{/if}}
{{#if (has-permission "policies" routeParams="egp")}}
<li>
{{#link-to "vault.cluster.policies" "egp" data-test-link=true class=(if (is-active-route "vault.cluster.policy" "egp") "is-active")}}
Endpoint Governing Policies
{{#unless (has-feature "Sentinel")}}
{{#if (is-version "OSS")}}
{{edition-badge edition="Enterprise"}}
{{else}}
{{edition-badge edition="Premium"}}
{{/if}}
{{/unless}}
{{/link-to}}
</li>
{{#if (has-feature "Sentinel")}}
{{#if (has-permission "policies" routeParams="rgp")}}
<li>
{{#link-to "vault.cluster.policies" "rgp" data-test-link=true class=(if (is-active-route "vault.cluster.policy" "rgp") "is-active")}}
Role Governing Policies
{{/link-to}}
</li>
{{/if}}
{{#if (has-permission "policies" routeParams="egp")}}
<li>
{{#link-to "vault.cluster.policies" "egp" data-test-link=true class=(if (is-active-route "vault.cluster.policy" "egp") "is-active")}}
Endpoint Governing Policies
{{/link-to}}
</li>
{{/if}}
{{/if}}
{{/menu-sidebar}}
<div class="column is-9">

View file

@ -1,44 +0,0 @@
import { later } from '@ember/runloop';
import Component from '@ember/component';
import { computed } from '@ember/object';
import layout from '../templates/components/upgrade-link';
export default Component.extend({
layout,
modalContainer: computed('isActive', function() {
return document.getElementById('modal-wormhole');
}),
isAnimated: false,
isActive: false,
tagName: 'span',
trackingSource: computed('pageName', function() {
let trackingSource = 'vaultui';
let pageName = this.get('pageName');
if (pageName) {
trackingSource = trackingSource + '_' + encodeURIComponent(pageName);
}
return trackingSource;
}),
actions: {
openOverlay() {
this.set('isActive', true);
later(
this,
function() {
this.set('isAnimated', true);
},
10
);
},
closeOverlay() {
this.set('isAnimated', false);
later(
this,
function() {
this.set('isActive', false);
},
300
);
},
},
});

View file

@ -7,7 +7,7 @@ export default Component.extend({
title: 'Vault Enterprise',
featureName: computed('title', function() {
let title = this.get('title');
return title === 'Vault Enterprise' ? 'This' : title;
return title === 'Vault Enterprise' ? 'this feature' : title;
}),
minimumEdition: 'Vault Enterprise',
});

View file

@ -1,6 +1,6 @@
<div class="empty-state" ...attributes>
<div class="empty-state-content">
<h3 class="empty-state-title">
<h3 class="empty-state-title" data-test-empty-state-title>
{{title}}
</h3>
{{#if message}}

View file

@ -58,10 +58,14 @@
Performance Replication is a feature of Vault Enterprise Premium.
</p>
<p class="has-text-centered">
{{#upgrade-link linkClass="button is-ghost has-icon-right" pageName="Performance Replication"}}
<a
href="https://hashicorp.com/products/vault/trial?source=vaultui_Performance%20Replication"
class="button is-ghost has-icon-right"
data-test-upgrade-link="true"
>
Learn more
<Icon @glyph="chevron-right" />
{{/upgrade-link}}
<Chevron />
</a>
</p>
{{else if replicationEnabled}}
<h5 class="title is-7 is-uppercase is-marginless">

View file

@ -1,79 +0,0 @@
<button class="link {{linkClass}}" {{action "openOverlay"}}>
{{yield}}
</button>
{{#maybe-in-element modalContainer false}}
<div id="upgrade-modal" class="modal upgrade-overlay has-text-white {{if isActive "is-active"}} {{if isAnimated "is-animated"}}">
<div class="modal-background"></div>
<div class="modal-content">
<h2 class="title upgrade-overlay-title is-2 has-text-white">
<Icon @glyph="edition-enterprise" aria-hidden="true" @size="xl" />
Try Vault Enterprise free for 30 days
</h2>
<h3 class="title is-5 has-text-white">
Collaborate on secrets management and access
</h3>
<p>
Vault Enterprise has features to help unify disparate users and roles,
use collaboration workflows, and disaster recovery for system recovery,
provide governance over secrets management and access with multi-factor
authentication. You'll have access to all the features below.
</p>
<div class="columns">
<div class="column is-flex">
<div class="box has-background-transparent has-text-white ">
<div class="level">
<div class="level-left">
<h3 class="title is-4 has-text-white">
Pro
{{#unless (is-version "OSS")}}
{{#unless version.hasPerfReplication}}
{{edition-badge edition="Current"}}
{{/unless}}
{{/unless}}
</h3>
</div>
</div>
<ul class="upgrade-features-list">
<li>All Open Source features</li>
<li>Disaster Recovery Replication</li>
<li>Cluster management</li>
<li>Init and unseal workflow</li>
<li>GCP Cloud KMS Auto-unseal</li>
<li>Silver support: 9x5 support w/SLA</li>
</ul>
</div>
</div>
<div class="column is-flex">
<div class="box has-background-transparent has-text-white">
<div class="level">
<div class="level-left">
<h3 class="title is-4 has-text-white">
Premium
</h3>
</div>
</div>
<ul class="upgrade-features-list">
<li>All Pro features</li>
<li>Performance Replication</li>
<li>HSM Autounseal</li>
<li>Mount Filters</li>
<li>Multi-Factor Authentication</li>
<li>Sentinel Integration</li>
<li>Control Groups</li>
<li>Seal Wrap / FIPS 140-2 Compliance</li>
<li>Gold support: 24&times;7 support w/SLA</li>
</ul>
</div>
</div>
</div>
<p class="has-text-centered">
<a href="https://hashicorp.com/products/vault/trial?source={{trackingSource}}" class="button is-primary" target="_blank" rel="noreferrer noopener">
Start trial
<Chevron @isButton={{true}} />
</a>
</p>
</div>
<button class="modal-close is-large" aria-label="close" {{action "closeOverlay"}}></button>
</div>
{{/maybe-in-element}}

View file

@ -6,17 +6,18 @@
</p.levelLeft>
</PageHeader>
<div class="box is-sideless is-bottomless has-text-centered has-background-white-bis">
<p class="has-text-grey-dark">
<span data-test-upgrade-feature-description>
{{featureName}} is a {{minimumEdition}} feature.
</span>
You can upgrade to {{minimumEdition}} to unlock additional collaboration and security features
</p>
<p>
{{#upgrade-link linkClass="button is-ghost has-icon-right" data-test-upgrade-link="true" pageName=featureName}}
Vault Enterprise
<Chevron />
{{/upgrade-link}}
</p>
</div>
<EmptyState
@title="Upgrade to use {{featureName}}"
@message="You will need {{minimumEdition}} with {{featureName}} included to use this feature."
>
<a
href="https://www.hashicorp.com/products/vault/enterprise?source=vaultui_{{featureName}}"
class="link has-icon-right"
target="_blank"
rel="noopener"
data-test-upgrade-link="true"
>
Vault Enterprise
<Chevron />
</a>
</EmptyState>

View file

@ -1 +0,0 @@
export { default } from 'core/components/upgrade-link';

View file

@ -58,14 +58,14 @@
Performance Replication
</h3>
{{#if (not (has-feature "Performance Replication"))}}
<p class="help has-text-grey-dark">
Performance Replication is a feature of {{#upgrade-link pageName="Performance Replication"}}Vault Enterprise Premium{{/upgrade-link}}
</p>
{{else}}
<p class="help has-text-grey-dark">
Performance replication scales workloads horizontally across clusters to make requests faster. Local secondaries handle read requests but forward writes to the primary to be handled.
</p>
{{/if}}
<p class="help has-text-grey-dark">
Performance Replication is a feature of Vault Enterprise Premium
</p>
{{else}}
<p class="help has-text-grey-dark">
Performance replication scales workloads horizontally across clusters to make requests faster. Local secondaries handle read requests but forward writes to the primary to be handled.
</p>
{{/if}}
{{/if}}
{{else}}
<p class="has-text-grey-dark box is-shadowless is-fullwidth has-slim-padding">
@ -111,13 +111,10 @@
@glyph="perf-replication"
/>
Performance
{{#if (not (has-feature "Performance Replication"))}}
{{edition-badge edition="Premium"}}
{{/if}}
</h3>
{{#if (not (has-feature "Performance Replication"))}}
<p class="help has-text-grey-dark">
Performance Replication is a feature of {{#upgrade-link pageName="Performance Replication"}}Vault Enterprise Premium{{/upgrade-link}}
Performance Replication is a feature of Vault Enterprise Premium
</p>
{{else}}
<p class="help has-text-grey-dark">

View file

@ -139,7 +139,6 @@
"@storybook/ember": "^5.0.5",
"@storybook/ember-cli-storybook": "meirish/ember-cli-storybook#6bd58326d8c21e986d390b541ae5e49089d61b93",
"babel-loader": "^8.0.5",
"husky": "^1.1.3",
"jsdoc-to-markdown": "^4.0.1",
"lint-staged": "^8.0.4"
},
@ -154,10 +153,5 @@
"lib/replication"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"dependencies": {}
}

View file

@ -1,17 +0,0 @@
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="c">
<stop stop-color="#FFF" stop-opacity=".25" offset="0%"/>
<stop stop-color="#FFF" stop-opacity=".5" offset="100%"/>
</linearGradient>
</defs>
<g fill="none" fill-rule="evenodd">
<mask id="b" fill="#fff">
<path d="M14 9.079V4.625L8 1.25 2 4.625v6.75l6 3.375 6-3.375V9.079zm-.5.264l-1 .529V5.5L8 3 3.5 5.5v4.372l-1-.529V4.875L8.001 1.75 13.5 4.875v4.468zM8.192 12.15l-.191.1L4 10.126v-4.25L8.001 3.75 12 5.875v4.25l-3.808 2.024zM8 0l7 4v8l-7 4-7-4V4l7-4zm0 13l5.5-3.1v1.2L8 14.25 2.5 11.1V9.9L8 13z"/>
</mask>
<g mask="url(#b)">
<path d="M0 0h16v16H0z" id="edition-enterprise-hexagon" fill="#6a7786"/>
</g>
<path fill="url(#c)" opacity=".5" mask="url(#b)" d="M8 0l7 4v8l-7 4z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 895 B

View file

@ -1,17 +0,0 @@
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs>
<path d="M8 0l7 4v8l-7 4-7-4V4l7-4zm0 1.25L2 4.625v6.75l6 3.375 6-3.375v-6.75L8 1.25zm.001.5L13.5 4.875v6.25L8.001 14.25 2.5 11.125v-6.25L8.001 1.75z" id="a"/>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="c">
<stop stop-color="#FFF" stop-opacity=".25" offset="0%"/>
<stop stop-color="#FFF" stop-opacity=".5" offset="100%"/>
</linearGradient>
</defs>
<g fill="none" fill-rule="evenodd">
<mask id="b" fill="#fff">
<use href="#a"/>
</mask>
<use fill="#fff" href="#a"/>
<g mask="url(#b)" fill="#BAC1CC"><path d="M0 0h16v16H0z"/></g>
<path fill="url(#c)" opacity=".5" mask="url(#b)" d="M8 0l7 4v8l-7 4z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 769 B

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="74px" height="128px" viewBox="0 0 74 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="vault-hex" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" opacity="0.0299999993">
<path d="M36,-1.96752179 L73.7513243,62 L-1.75132433,62 L36,-1.96752179 Z" id="Triangle" stroke="#FFFFFF" stroke-width="2"></path>
<rect id="Rectangle" fill="#FFFFFF" x="0" y="125" width="72" height="2"></rect>
<path d="M36,61.0324782 L73.7513243,125 L-1.75132433,125 L36,61.0324782 Z" id="Triangle" stroke="#FFFFFF" stroke-width="2" transform="translate(36.000000, 93.500000) scale(1, -1) translate(-36.000000, -93.500000) "></path>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 753 B

View file

@ -1,22 +0,0 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | edition badge', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
await render(hbs`
{{edition-badge edition="Custom"}}
`);
assert.equal(find('.edition-badge').textContent.trim(), 'Custom', 'contains edition');
await render(hbs`
{{edition-badge edition="Enterprise"}}
`);
assert.equal(find('.edition-badge').textContent.trim(), 'Enterprise', 'renders edition');
});
});

View file

@ -1,48 +0,0 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find, findAll } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | upgrade link', function(hooks) {
setupRenderingTest(hooks);
test('it renders with overlay', async function(assert) {
await render(hbs`
<div id="modal-wormhole"></div>
<div class="upgrade-link-container">
{{#upgrade-link data-test-link}}upgrade{{/upgrade-link}}
</div>
`);
assert.equal(
find('.upgrade-link-container button').textContent.trim(),
'upgrade',
'renders link content'
);
assert.equal(
find('#modal-wormhole .upgrade-overlay-title').textContent.trim(),
'Try Vault Enterprise free for 30 days',
'contains overlay content'
);
assert.equal(
findAll('#modal-wormhole a[href^="https://hashicorp.com/products/vault/trial?source=vaultui"]').length,
1,
'contains info link'
);
});
test('it adds custom classes', async function(assert) {
await render(hbs`
<div id="modal-wormhole"></div>
<div class="upgrade-link-container">
{{#upgrade-link linkClass="button upgrade-button"}}upgrade{{/upgrade-link}}
</div>
`);
assert.equal(
find('.upgrade-link-container button').getAttribute('class'),
'link button upgrade-button',
'adds classes to link'
);
});
});

View file

@ -12,30 +12,44 @@ module('Integration | Component | upgrade page', function(hooks) {
<div id="modal-wormhole"></div>
`);
assert.equal(find('.page-header .title').textContent.trim(), 'Vault Enterprise', 'renders default title');
assert.equal(
find('[data-test-upgrade-feature-description]').textContent.trim(),
'This is a Vault Enterprise feature.',
'renders default description'
find('.page-header .title').textContent.trim(),
'Vault Enterprise',
'renders default page title'
);
assert.equal(
find('[data-test-empty-state-title]').textContent.trim(),
'Upgrade to use this feature',
'renders default title'
);
assert.equal(
find('[data-test-empty-state-message]').textContent.trim(),
'You will need Vault Enterprise with this feature included to use this feature.',
'renders default message'
);
assert.equal(findAll('[data-test-upgrade-link]').length, 1, 'renders upgrade link');
});
test('it renders with custom attributes', async function(assert) {
await render(hbs`
{{upgrade-page title="Test Feature Title" featureName="Specific Feature Name" minimumEdition="Premium"}}
{{upgrade-page title="Test Feature Title" featureName="Specific Feature Name" minimumEdition="Vault Enterprise Premium"}}
<div id="modal-wormhole"></div>
`);
assert.equal(
find('.page-header .title').textContent.trim(),
'Test Feature Title',
'renders default title'
'renders custom page title'
);
assert.equal(
find('[data-test-upgrade-feature-description]').textContent.trim(),
'Specific Feature Name is a Premium feature.',
'renders default description'
find('[data-test-empty-state-title]').textContent.trim(),
'Upgrade to use Specific Feature Name',
'renders custom title'
);
assert.equal(
find('[data-test-empty-state-message]').textContent.trim(),
'You will need Vault Enterprise Premium with Specific Feature Name included to use this feature.',
'renders custom message'
);
});
});

View file

@ -5479,11 +5479,6 @@ ci-info@^1.3.0, ci-info@^1.4.0:
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.5.0.tgz#38327c69e98dab18487744b84e5d6e841a09a1a7"
integrity sha512-Bx/xWOzip4whERIvC97aIHjWCa8FxEn0ezng0oVn4kma6p+90Fbs3bTcJw6ZL0da2EPHydxsXJPZxNUv5oWb1Q==
ci-info@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==
cidr-regex@^2.0.8:
version "2.0.9"
resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-2.0.9.tgz#9c17bb2b18e15af07f7d0c3b994b961d687ed1c9"
@ -6194,7 +6189,7 @@ cosmiconfig@^5.0.1:
js-yaml "^3.9.0"
parse-json "^4.0.0"
cosmiconfig@^5.0.2, cosmiconfig@^5.0.6:
cosmiconfig@^5.0.2:
version "5.0.7"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.7.tgz#39826b292ee0d78eda137dfa3173bd1c21a43b04"
integrity sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA==
@ -8578,19 +8573,6 @@ execa@^0.7.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
execa@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.9.0.tgz#adb7ce62cf985071f60580deb4a88b9e34712d01"
integrity sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==
dependencies:
cross-spawn "^5.0.1"
get-stream "^3.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
execa@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
@ -10242,22 +10224,6 @@ humanize-ms@^1.2.1:
dependencies:
ms "^2.0.0"
husky@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/husky/-/husky-1.1.3.tgz#3ccfdb4d7332896bf7cd0e618c6fb8be09d9de4b"
integrity sha512-6uc48B/A2Mqi65yeg37d/TPcTb0bZ1GTkMYOM0nXLOPuPaTRhXCeee80/noOrbavWd12x72Tusja7GJ5rzvV6g==
dependencies:
cosmiconfig "^5.0.6"
execa "^0.9.0"
find-up "^3.0.0"
get-stdin "^6.0.0"
is-ci "^1.2.1"
pkg-dir "^3.0.0"
please-upgrade-node "^3.1.1"
read-pkg "^4.0.1"
run-node "^1.0.0"
slash "^2.0.0"
iconv-lite@0.4.19:
version "0.4.19"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
@ -10676,13 +10642,6 @@ is-ci@^1.0.10:
dependencies:
ci-info "^1.3.0"
is-ci@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==
dependencies:
ci-info "^1.5.0"
is-cidr@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-2.0.6.tgz#4b01c9693d8e18399dacd18a4f3d60ea5871ac60"
@ -14388,7 +14347,7 @@ pkg-up@2.0.0, pkg-up@^2.0.0:
dependencies:
find-up "^2.1.0"
please-upgrade-node@^3.0.2, please-upgrade-node@^3.1.1:
please-upgrade-node@^3.0.2:
version "3.1.1"
resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz#ed320051dfcc5024fae696712c8288993595e8ac"
integrity sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==
@ -15344,7 +15303,7 @@ read-pkg@^3.0.0:
normalize-package-data "^2.3.2"
path-type "^3.0.0"
read-pkg@^4.0.0, read-pkg@^4.0.1:
read-pkg@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237"
integrity sha1-ljYlN48+HE1IyFhytabsfV0JMjc=
@ -16031,11 +15990,6 @@ run-async@^2.2.0:
dependencies:
is-promise "^2.1.0"
run-node@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/run-node/-/run-node-1.0.0.tgz#46b50b946a2aa2d4947ae1d886e9856fd9cabe5e"
integrity sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==
run-queue@^1.0.0, run-queue@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"
@ -16511,11 +16465,6 @@ slash@^1.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
slash@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
slice-ansi@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"

View file

@ -287,6 +287,7 @@ func (b *AESGCMBarrier) ReloadKeyring(ctx context.Context) error {
}
// Setup the keyring and finish
b.cache = make(map[uint32]cipher.AEAD)
b.keyring = keyring
return nil
}

View file

@ -516,3 +516,82 @@ func TestEncrypt_BarrierEncryptor(t *testing.T) {
t.Fatalf("bad: %s", plain)
}
}
func TestAESGCMBarrier_ReloadKeyring(t *testing.T) {
inm, err := inmem.NewInmem(nil, logger)
if err != nil {
t.Fatalf("err: %v", err)
}
b, err := NewAESGCMBarrier(inm)
if err != nil {
t.Fatalf("err: %v", err)
}
// Initialize and unseal
key, _ := b.GenerateKey()
b.Initialize(context.Background(), key)
b.Unseal(context.Background(), key)
keyringRaw, err := inm.Get(context.Background(), keyringPath)
if err != nil {
t.Fatalf("err: %v", err)
}
// Encrypt something to test cache invalidation
_, err = b.Encrypt(context.Background(), "foo", []byte("quick brown fox"))
if err != nil {
t.Fatalf("err: %v", err)
}
{
// Create a second barrier and rotate the keyring
b2, err := NewAESGCMBarrier(inm)
if err != nil {
t.Fatalf("err: %v", err)
}
b2.Unseal(context.Background(), key)
_, err = b2.Rotate(context.Background())
if err != nil {
t.Fatalf("err: %v", err)
}
}
// Reload the keyring on the first
err = b.ReloadKeyring(context.Background())
if err != nil {
t.Fatalf("err: %v", err)
}
if b.keyring.ActiveTerm() != 2 {
t.Fatal("failed to reload keyring")
}
if len(b.cache) != 0 {
t.Fatal("failed to clear cache")
}
// Encrypt something to test cache invalidation
_, err = b.Encrypt(context.Background(), "foo", []byte("quick brown fox"))
if err != nil {
t.Fatalf("err: %v", err)
}
// Restore old keyring to test rolling back
err = inm.Put(context.Background(), keyringRaw)
if err != nil {
t.Fatalf("err: %v", err)
}
// Reload the keyring on the first
err = b.ReloadKeyring(context.Background())
if err != nil {
t.Fatalf("err: %v", err)
}
if b.keyring.ActiveTerm() != 1 {
t.Fatal("failed to reload keyring")
}
if len(b.cache) != 0 {
t.Fatal("failed to clear cache")
}
}

View file

@ -427,6 +427,8 @@ type Core struct {
// Stores request counters
counters counters
coreNumber int
}
// CoreConfig is used to parameterize a core

View file

@ -16,6 +16,12 @@ import (
"github.com/hashicorp/vault/sdk/version"
)
type ctxKeyForwardedRequestMountAccessor struct{}
func (c ctxKeyForwardedRequestMountAccessor) String() string {
return "forwarded-req-mount-accessor"
}
type dynamicSystemView struct {
core *Core
mountEntry *MountEntry
@ -33,6 +39,17 @@ func (e extendedSystemView) Auditor() logical.Auditor {
}
}
func (e extendedSystemView) ForwardGenericRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) {
// Forward the request if allowed
if couldForward(e.core) {
ctx = namespace.ContextWithNamespace(ctx, e.mountEntry.Namespace())
ctx = context.WithValue(ctx, ctxKeyForwardedRequestMountAccessor{}, e.mountEntry.Accessor)
return forward(ctx, e.core, req)
}
return nil, logical.ErrReadOnly
}
func (d dynamicSystemView) DefaultLeaseTTL() time.Duration {
def, _ := d.fetchTTLs()
return def

View file

@ -0,0 +1,89 @@
package policy
// This is TODO once tokenhelper is added to ldaputil
/*
import (
"testing"
"github.com/go-test/deep"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/builtin/credential/ldap"
vaulthttp "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"
)
func TestNoDefaultPolicy(t *testing.T) {
var err error
coreConfig := &vault.CoreConfig{
DisableMlock: true,
DisableCache: true,
Logger: hclog.NewNullLogger(),
CredentialBackends: map[string]logical.Factory{
"ldap": ldap.Factory,
},
}
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
HandlerFunc: vaulthttp.Handler,
})
cluster.Start()
defer cluster.Cleanup()
cores := cluster.Cores
vault.TestWaitActive(t, cores[0].Core)
client := cores[0].Client
err = client.Sys().EnableAuthWithOptions("ldap", &api.EnableAuthOptions{
Type: "ldap",
})
if err != nil {
t.Fatal(err)
}
// Configure LDAP auth backend
secret, err := client.Logical().Write("auth/ldap/config", map[string]interface{}{
"url": "ldap://ldap.forumsys.com",
"userattr": "uid",
"userdn": "dc=example,dc=com",
"groupdn": "dc=example,dc=com",
"binddn": "cn=read-only-admin,dc=example,dc=com",
"token_no_default_policy": true,
})
if err != nil {
t.Fatal(err)
}
// Create a local user in LDAP
secret, err = client.Logical().Write("auth/ldap/users/tesla", map[string]interface{}{
"policies": "foo",
})
if err != nil {
t.Fatal(err)
}
// Login with LDAP and create a token
secret, err = client.Logical().Write("auth/ldap/login/tesla", map[string]interface{}{
"password": "password",
})
if err != nil {
t.Fatal(err)
}
token := secret.Auth.ClientToken
// Lookup the token to get the entity ID
secret, err = client.Auth().Token().Lookup(token)
if err != nil {
t.Fatal(err)
}
if diff := deep.Equal(secret.Data["policies"], []interface{}{"foo"}); diff != nil {
t.Fatal(diff)
}
}
*/

View file

@ -46,7 +46,7 @@ This field is deprecated, use canonical_id.`,
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.UpdateOperation: i.handleAliasUpdateCommon(),
logical.UpdateOperation: i.handleAliasCreateUpdate(),
},
HelpSynopsis: strings.TrimSpace(aliasHelp["alias"][0]),
@ -79,7 +79,7 @@ This field is deprecated, use canonical_id.`,
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.UpdateOperation: i.handleAliasUpdateCommon(),
logical.UpdateOperation: i.handleAliasCreateUpdate(),
logical.ReadOperation: i.pathAliasIDRead(),
logical.DeleteOperation: i.pathAliasIDDelete(),
},
@ -99,31 +99,25 @@ This field is deprecated, use canonical_id.`,
}
}
// handleAliasUpdateCommon is used to update an alias
func (i *IdentityStore) handleAliasUpdateCommon() framework.OperationFunc {
// handleAliasCreateUpdate is used to create or update an alias
func (i *IdentityStore) handleAliasCreateUpdate() framework.OperationFunc {
return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
var err error
var alias *identity.Alias
var entity *identity.Entity
var previousEntity *identity.Entity
i.lock.Lock()
defer i.lock.Unlock()
// Check for update or create
aliasID := d.Get("id").(string)
if aliasID != "" {
alias, err = i.MemDBAliasByID(aliasID, true, false)
if err != nil {
return nil, err
}
if alias == nil {
return logical.ErrorResponse("invalid alias id"), nil
}
} else {
alias = &identity.Alias{}
ns, err := namespace.FromContext(ctx)
if err != nil {
return nil, err
}
// Get alias name, if any
name := d.Get("name").(string)
// Get mount accessor, if any
mountAccessor := d.Get("mount_accessor").(string)
// Get ID, if any
id := d.Get("id").(string)
// Get entity id
canonicalID := d.Get("canonical_id").(string)
if canonicalID == "" {
@ -131,155 +125,252 @@ func (i *IdentityStore) handleAliasUpdateCommon() framework.OperationFunc {
canonicalID = d.Get("entity_id").(string)
}
// Get alias name
if aliasName := d.Get("name").(string); aliasName == "" {
if alias.Name == "" {
return logical.ErrorResponse("missing alias name"), nil
}
} else {
alias.Name = aliasName
}
i.lock.Lock()
defer i.lock.Unlock()
// Get mount accessor
if mountAccessor := d.Get("mount_accessor").(string); mountAccessor == "" {
if alias.MountAccessor == "" {
return logical.ErrorResponse("missing mount_accessor"), nil
}
} else {
alias.MountAccessor = mountAccessor
}
mountValidationResp := i.core.router.validateMountByAccessor(alias.MountAccessor)
if mountValidationResp == nil {
return logical.ErrorResponse(fmt.Sprintf("invalid mount accessor %q", alias.MountAccessor)), nil
}
if mountValidationResp.MountLocal {
return logical.ErrorResponse(fmt.Sprintf("mount_accessor %q is of a local mount", alias.MountAccessor)), nil
}
// Verify that the combination of alias name and mount is not
// already tied to a different alias
aliasByFactors, err := i.MemDBAliasByFactors(mountValidationResp.MountAccessor, alias.Name, false, false)
if err != nil {
return nil, err
}
if aliasByFactors != nil {
// If it's a create we won't have an alias ID so this will correctly
// bail. If it's an update alias will be the same as aliasbyfactors so
// we don't need to transfer any info over
if aliasByFactors.ID != alias.ID {
return logical.ErrorResponse("combination of mount and alias name is already in use"), nil
}
// Fetch the entity to which the alias is tied. We don't need to append
// here, so the only further checking is whether the canonical ID is
// different
entity, err = i.MemDBEntityByAliasID(alias.ID, true)
if err != nil {
return nil, err
}
if entity == nil {
return nil, fmt.Errorf("existing alias is not associated with an entity")
}
} else if alias.ID != "" {
// This is an update, not a create; if we have an associated entity
// already, load it
entity, err = i.MemDBEntityByAliasID(alias.ID, true)
if err != nil {
return nil, err
}
}
resp := &logical.Response{}
// If we found an existing alias we won't hit this condition because
// canonicalID being empty will result in nil being returned in the block
// above, so in this case we know that creating a new entity is the right
// thing.
if canonicalID == "" {
entity = &identity.Entity{
Aliases: []*identity.Alias{
alias,
},
}
} else {
// If we can look up by the given canonical ID, see if this is a
// transfer; otherwise if we found no previous entity but we find one
// here, use it.
canonicalEntity, err := i.MemDBEntityByID(canonicalID, true)
if err != nil {
return nil, err
}
if canonicalEntity == nil {
return logical.ErrorResponse("invalid canonical ID"), nil
}
if entity == nil {
// If entity is nil, we didn't find a previous alias from factors,
// so append to this entity
entity = canonicalEntity
entity.Aliases = append(entity.Aliases, alias)
} else if entity.ID != canonicalEntity.ID {
// In this case we found an entity from alias factors or given
// alias ID but it's not the same, so it's a migration
previousEntity = entity
entity = canonicalEntity
for aliasIndex, item := range previousEntity.Aliases {
if item.ID == alias.ID {
previousEntity.Aliases = append(previousEntity.Aliases[:aliasIndex], previousEntity.Aliases[aliasIndex+1:]...)
break
}
// This block is run if they provided an ID
{
// If they provide an ID it must be an update. Find the alias, perform
// due diligence, call the update function.
if id != "" {
alias, err := i.MemDBAliasByID(id, true, false)
if err != nil {
return nil, err
}
if alias == nil {
return logical.ErrorResponse("invalid alias ID provided"), nil
}
if alias.NamespaceID != ns.ID {
return logical.ErrorResponse("cannot modify aliases across namespaces"), logical.ErrPermissionDenied
}
entity.Aliases = append(entity.Aliases, alias)
resp.AddWarning(fmt.Sprintf("alias is being transferred from entity %q to %q", previousEntity.ID, entity.ID))
switch {
case mountAccessor == "" && name == "":
// Just a canonical ID update, maybe
if canonicalID == "" {
// Nothing to do, so be idempotent
return nil, nil
}
name = alias.Name
mountAccessor = alias.MountAccessor
case mountAccessor == "":
// No change to mount accessor
mountAccessor = alias.MountAccessor
case name == "":
// No change to mount name
name = alias.Name
default:
// Both provided
}
return i.handleAliasUpdate(ctx, req, canonicalID, name, mountAccessor, alias)
}
}
// ID creation and other validations; This is more useful for new entities
// and may not perform anything for the existing entities. Placing the
// check here to make the flow common for both new and existing entities.
err = i.sanitizeEntity(ctx, entity)
// If they didn't provide an ID, we must have both accessor and name provided
if mountAccessor == "" || name == "" {
return logical.ErrorResponse("'id' or 'mount_accessor' and 'name' must be provided"), nil
}
// Look up the alias by factors; if it's found it's an update
mountEntry := i.core.router.MatchingMountByAccessor(mountAccessor)
if mountEntry == nil {
return logical.ErrorResponse(fmt.Sprintf("invalid mount accessor %q", mountAccessor)), nil
}
if mountEntry.Local {
return logical.ErrorResponse(fmt.Sprintf("mount accessor %q is of a local mount", mountAccessor)), nil
}
if mountEntry.NamespaceID != ns.ID {
return logical.ErrorResponse("matching mount is in a different namespace than request"), logical.ErrPermissionDenied
}
alias, err := i.MemDBAliasByFactors(mountAccessor, name, false, false)
if err != nil {
return nil, err
}
// Explicitly set to empty as in the past we incorrectly saved it
alias.MountPath = ""
alias.MountType = ""
// Set the canonical ID in the alias index. This should be done after
// sanitizing entity.
alias.CanonicalID = entity.ID
// ID creation and other validations
err = i.sanitizeAlias(ctx, alias)
if err != nil {
return nil, err
}
for index, item := range entity.Aliases {
if item.ID == alias.ID {
entity.Aliases[index] = alias
if alias != nil {
if alias.NamespaceID != ns.ID {
return logical.ErrorResponse("cannot modify aliases across namespaces"), logical.ErrPermissionDenied
}
return i.handleAliasUpdate(ctx, req, alias.CanonicalID, name, mountAccessor, alias)
}
// Index entity and its aliases in MemDB and persist entity along with
// aliases in storage. If the alias is being transferred over from
// one entity to another, previous entity needs to get refreshed in MemDB
// and persisted in storage as well.
if err := i.upsertEntity(ctx, entity, previousEntity, true); err != nil {
// At this point we know it's a new creation request
return i.handleAliasCreate(ctx, req, canonicalID, name, mountAccessor)
}
}
func (i *IdentityStore) handleAliasCreate(ctx context.Context, req *logical.Request, canonicalID, name, mountAccessor string) (*logical.Response, error) {
ns, err := namespace.FromContext(ctx)
if err != nil {
return nil, err
}
alias := &identity.Alias{
MountAccessor: mountAccessor,
Name: name,
}
entity := &identity.Entity{}
// If a canonical ID is provided pull up the entity and make sure we're in
// the right NS
if canonicalID != "" {
entity, err = i.MemDBEntityByID(canonicalID, true)
if err != nil {
return nil, err
}
if entity == nil {
return logical.ErrorResponse("invalid canonical ID"), nil
}
if entity.NamespaceID != ns.ID {
return logical.ErrorResponse("entity found with 'canonical_id' not in request namespace"), logical.ErrPermissionDenied
}
}
// Return ID of both alias and entity
resp.Data = map[string]interface{}{
entity.Aliases = append(entity.Aliases, alias)
// ID creation and other validations; This is more useful for new entities
// and may not perform anything for the existing entities. Placing the
// check here to make the flow common for both new and existing entities.
err = i.sanitizeEntity(ctx, entity)
if err != nil {
return nil, err
}
// Set the canonical ID in the alias index. This should be done after
// sanitizing entity in case it's a new entity that didn't have an ID.
alias.CanonicalID = entity.ID
// ID creation and other validations
err = i.sanitizeAlias(ctx, alias)
if err != nil {
return nil, err
}
// Index entity and its aliases in MemDB and persist entity along with
// aliases in storage.
if err := i.upsertEntity(ctx, entity, nil, true); err != nil {
return nil, err
}
// Return ID of both alias and entity
return &logical.Response{
Data: map[string]interface{}{
"id": alias.ID,
"canonical_id": entity.ID,
},
}, nil
}
func (i *IdentityStore) handleAliasUpdate(ctx context.Context, req *logical.Request, canonicalID, name, mountAccessor string, alias *identity.Alias) (*logical.Response, error) {
if name == alias.Name &&
mountAccessor == alias.MountAccessor &&
(canonicalID == alias.CanonicalID || canonicalID == "") {
// Nothing to do; return nil to be idempotent
return nil, nil
}
alias.LastUpdateTime = ptypes.TimestampNow()
// If we're changing one or the other or both of these, make sure that
// there isn't a matching alias already, and make sure it's in the same
// namespace.
if name != alias.Name || mountAccessor != alias.MountAccessor {
// Check here to see if such an alias already exists, if so bail
mountEntry := i.core.router.MatchingMountByAccessor(mountAccessor)
if mountEntry == nil {
return logical.ErrorResponse(fmt.Sprintf("invalid mount accessor %q", mountAccessor)), nil
}
if mountEntry.Local {
return logical.ErrorResponse(fmt.Sprintf("mount_accessor %q is of a local mount", mountAccessor)), nil
}
if mountEntry.NamespaceID != alias.NamespaceID {
return logical.ErrorResponse("given mount accessor is not in the same namespace as the existing alias"), logical.ErrPermissionDenied
}
return resp, nil
existingAlias, err := i.MemDBAliasByFactors(mountAccessor, name, false, false)
if err != nil {
return nil, err
}
// Bail unless it's just a case change
if existingAlias != nil && !strings.EqualFold(existingAlias.Name, name) {
return logical.ErrorResponse("alias with combination of mount accessor and name already exists"), nil
}
// Update the values in the alias
alias.Name = name
alias.MountAccessor = mountAccessor
}
// Get our current entity, which may be the same as the new one if the
// canonical ID hasn't changed
currentEntity, err := i.MemDBEntityByAliasID(alias.ID, true)
if err != nil {
return nil, err
}
if currentEntity == nil {
return logical.ErrorResponse("given alias is not associated with an entity"), nil
}
if currentEntity.NamespaceID != alias.NamespaceID {
return logical.ErrorResponse("alias associated with an entity in a different namespace"), logical.ErrPermissionDenied
}
newEntity := currentEntity
if canonicalID != "" && canonicalID != alias.CanonicalID {
newEntity, err = i.MemDBEntityByID(canonicalID, true)
if err != nil {
return nil, err
}
if newEntity == nil {
return logical.ErrorResponse("given 'canonical_id' is not associated with an entity"), nil
}
if newEntity.NamespaceID != alias.NamespaceID {
return logical.ErrorResponse("given 'canonical_id' associated with entity in a different namespace from the alias"), logical.ErrPermissionDenied
}
// Update the canonical ID value and move it from the current enitity to the new one
alias.CanonicalID = newEntity.ID
newEntity.Aliases = append(newEntity.Aliases, alias)
for aliasIndex, item := range currentEntity.Aliases {
if item.ID == alias.ID {
currentEntity.Aliases = append(currentEntity.Aliases[:aliasIndex], currentEntity.Aliases[aliasIndex+1:]...)
break
}
}
} else {
// If it's not moving we still need to update it in the existing
// entity's aliases
for aliasIndex, item := range currentEntity.Aliases {
if item.ID == alias.ID {
currentEntity.Aliases[aliasIndex] = alias
break
}
}
// newEntity will be pointing to the same entity; set currentEntity nil
// so the upsertCall gets nil for the previous entity as we're only
// changing one.
currentEntity = nil
}
// Index entity and its aliases in MemDB and persist entity along with
// aliases in storage. If the alias is being transferred over from
// one entity to another, previous entity needs to get refreshed in MemDB
// and persisted in storage as well.
if err := i.upsertEntity(ctx, newEntity, currentEntity, true); err != nil {
return nil, err
}
// Return ID of both alias and entity
return &logical.Response{
Data: map[string]interface{}{
"id": alias.ID,
"canonical_id": newEntity.ID,
},
}, nil
}
// pathAliasIDRead returns the properties of an alias for a given
@ -310,7 +401,7 @@ func (i *IdentityStore) handleAliasReadCommon(ctx context.Context, alias *identi
return nil, err
}
if ns.ID != alias.NamespaceID {
return nil, nil
return logical.ErrorResponse("alias and request are in different namespaces"), logical.ErrPermissionDenied
}
respData := map[string]interface{}{}
@ -320,6 +411,7 @@ func (i *IdentityStore) handleAliasReadCommon(ctx context.Context, alias *identi
respData["metadata"] = alias.Metadata
respData["name"] = alias.Name
respData["merged_from_canonical_ids"] = alias.MergedFromCanonicalIDs
respData["namespace_id"] = alias.NamespaceID
if mountValidationResp := i.core.router.validateMountByAccessor(alias.MountAccessor); mountValidationResp != nil {
respData["mount_path"] = mountValidationResp.MountPath
@ -366,7 +458,7 @@ func (i *IdentityStore) pathAliasIDDelete() framework.OperationFunc {
return nil, err
}
if ns.ID != alias.NamespaceID {
return nil, logical.ErrUnsupportedPath
return logical.ErrorResponse("request and alias are in different namespaces"), logical.ErrPermissionDenied
}
// Fetch the associated entity

View file

@ -196,8 +196,8 @@ func TestIdentityStore_AliasSameAliasNames(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if resp == nil || !resp.IsError() {
t.Fatalf("expected an error due to alias name not being unique")
if resp != nil {
t.Fatalf("expected no response since this modification should be idempotent")
}
}

View file

@ -337,6 +337,7 @@ func (i *IdentityStore) handleEntityReadCommon(ctx context.Context, entity *iden
respData["merged_entity_ids"] = entity.MergedEntityIDs
respData["policies"] = entity.Policies
respData["disabled"] = entity.Disabled
respData["namespace_id"] = entity.NamespaceID
// Convert protobuf timestamp into RFC3339 format
respData["creation_time"] = ptypes.TimestampString(entity.CreationTime)

View file

@ -152,16 +152,16 @@ func (i *IdentityStore) handleGroupAliasUpdateCommon(ctx context.Context, req *l
return logical.ErrorResponse("missing mount_accessor"), nil
}
mountValidationResp := i.core.router.validateMountByAccessor(mountAccessor)
if mountValidationResp == nil {
mountEntry := i.core.router.MatchingMountByAccessor(mountAccessor)
if mountEntry == nil {
return logical.ErrorResponse(fmt.Sprintf("invalid mount accessor %q", mountAccessor)), nil
}
if mountValidationResp.MountLocal {
if mountEntry.Local {
return logical.ErrorResponse(fmt.Sprintf("mount_accessor %q is of a local mount", mountAccessor)), nil
}
groupAliasByFactors, err := i.MemDBAliasByFactors(mountValidationResp.MountAccessor, groupAliasName, false, true)
groupAliasByFactors, err := i.MemDBAliasByFactors(mountEntry.Accessor, groupAliasName, false, true)
if err != nil {
return nil, err
}
@ -208,8 +208,13 @@ func (i *IdentityStore) handleGroupAliasUpdateCommon(ctx context.Context, req *l
group.Alias = groupAlias
}
// Check if the group we found belongs to a different namespace than the mount accessor
if group.NamespaceID != mountEntry.NamespaceID {
return logical.ErrorResponse("mount accessor and group are located in different namespaces"), nil
}
group.Alias.Name = groupAliasName
group.Alias.MountAccessor = mountValidationResp.MountAccessor
group.Alias.MountAccessor = mountEntry.Accessor
// Explicitly correct for previous versions that persisted this
group.Alias.MountType = ""

View file

@ -335,6 +335,7 @@ func (i *IdentityStore) handleGroupReadCommon(ctx context.Context, group *identi
respData["last_update_time"] = ptypes.TimestampString(group.LastUpdateTime)
respData["modify_index"] = group.ModifyIndex
respData["type"] = group.Type
respData["namespace_id"] = group.NamespaceID
aliasMap := map[string]interface{}{}
if group.Alias != nil {

View file

@ -115,7 +115,7 @@ vault <command> <path> metadata=key1=value1 metadata=key2=value2
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.UpdateOperation: i.handleAliasUpdateCommon(),
logical.UpdateOperation: i.handleAliasCreateUpdate(),
},
HelpSynopsis: strings.TrimSpace(aliasHelp["alias"][0]),
@ -147,7 +147,7 @@ vault <command> <path> metadata=key1=value1 metadata=key2=value2
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.UpdateOperation: i.handleAliasUpdateCommon(),
logical.UpdateOperation: i.handleAliasCreateUpdate(),
logical.ReadOperation: i.pathAliasIDRead(),
logical.DeleteOperation: i.pathAliasIDDelete(),
},

View file

@ -332,11 +332,19 @@ func (i *IdentityStore) upsertEntityInTxn(ctx context.Context, txn *memdb.Txn, e
var err error
if txn == nil {
return fmt.Errorf("txn is nil")
return errors.New("txn is nil")
}
if entity == nil {
return fmt.Errorf("entity is nil")
return errors.New("entity is nil")
}
if entity.NamespaceID == "" {
entity.NamespaceID = namespace.RootNamespaceID
}
if previousEntity != nil && previousEntity.NamespaceID != entity.NamespaceID {
return errors.New("entity and previous entity are not in the same namespace")
}
aliasFactors := make([]string, len(entity.Aliases))
@ -348,12 +356,24 @@ func (i *IdentityStore) upsertEntityInTxn(ctx context.Context, txn *memdb.Txn, e
return err
}
if alias.NamespaceID == "" {
alias.NamespaceID = namespace.RootNamespaceID
}
switch {
case aliasByFactors == nil:
// Not found, no merging needed
// Not found, no merging needed, just check namespace
if alias.NamespaceID != entity.NamespaceID {
return errors.New("alias and entity are not in the same namespace")
}
case aliasByFactors.CanonicalID == entity.ID:
// Lookup found the same entity, so it's already attached to the
// right place
if aliasByFactors.NamespaceID != entity.NamespaceID {
return errors.New("alias from factors and entity are not in the same namespace")
}
case previousEntity != nil && aliasByFactors.CanonicalID == previousEntity.ID:
// previousEntity isn't upserted yet so may still contain the old
// alias reference in memdb if it was just changed; validate
@ -372,8 +392,10 @@ func (i *IdentityStore) upsertEntityInTxn(ctx context.Context, txn *memdb.Txn, e
}
// Otherwise it's still tied to previousEntity and fall through
// into merging
// into merging. We don't need a namespace check here as existing
// checks when creating the aliases should ensure that all line up.
fallthrough
default:
i.logger.Warn("alias is already tied to a different entity; these entities are being merged", "alias_id", alias.ID, "other_entity_id", aliasByFactors.CanonicalID, "entity_aliases", entity.Aliases, "alias_by_factors", aliasByFactors)
@ -943,7 +965,7 @@ func (i *IdentityStore) sanitizeAlias(ctx context.Context, alias *identity.Alias
return err
}
if ns.ID != alias.NamespaceID {
return fmt.Errorf("alias belongs to a different namespace")
return errors.New("alias belongs to a different namespace")
}
// Set the creation and last update times
@ -983,7 +1005,7 @@ func (i *IdentityStore) sanitizeEntity(ctx context.Context, entity *identity.Ent
entity.NamespaceID = ns.ID
}
if ns.ID != entity.NamespaceID {
return fmt.Errorf("entity does not belong to this namespace")
return errors.New("entity does not belong to this namespace")
}
// Create a name if there isn't one already
@ -1047,7 +1069,7 @@ func (i *IdentityStore) sanitizeAndUpsertGroup(ctx context.Context, group *ident
return err
}
if ns.ID != group.NamespaceID {
return fmt.Errorf("group does not belong to this namespace")
return errors.New("group does not belong to this namespace")
}
// Create a name if there isn't one already

View file

@ -483,6 +483,8 @@ func (c *Core) mountInternal(ctx context.Context, entry *MountEntry, updateStora
addPathCheckers(c, entry, backend, viewPath)
addLicenseCallback(c, backend)
c.setCoreBackend(entry, backend, view)
// If the mount is filtered or we are on a DR secondary we don't want to
@ -1199,6 +1201,7 @@ func (c *Core) newLogicalBackend(ctx context.Context, entry *MountEntry, sysView
BackendUUID: entry.BackendAwareUUID,
}
ctx = context.WithValue(ctx, "core_number", c.coreNumber)
b, err := f(ctx, config)
if err != nil {
return nil, err

View file

@ -17,6 +17,7 @@ func removeAuditPathChecker(*Core, *MountEntry) {}
func addFilterablePath(*Core, string) {}
func preprocessMount(*Core, *MountEntry, *BarrierView) (bool, error) { return false, nil }
func clearIgnoredPaths(context.Context, *Core, logical.Backend, string) error { return nil }
func addLicenseCallback(*Core, logical.Backend) {}
// ViewPath returns storage prefix for the view
func (e *MountEntry) ViewPath() string {

View file

@ -1034,6 +1034,11 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re
var entity *identity.Entity
auth = resp.Auth
// Only the token store can toggle this off, and that's via a different
// path since it's not a login request; it's explicitly disallowed
// above
auth.Renewable = true
mEntry := c.router.MatchingMountEntry(ctx, req.Path)
if auth.Alias != nil &&
@ -1109,7 +1114,7 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re
return nil, nil, ErrInternalError
}
auth.TokenPolicies = policyutil.SanitizePolicies(auth.Policies, policyutil.AddDefaultPolicy)
auth.TokenPolicies = policyutil.SanitizePolicies(auth.Policies, !auth.NoDefaultPolicy)
allPolicies := policyutil.SanitizePolicies(append(auth.TokenPolicies, identityPolicies[ns.ID]...), policyutil.DoNotAddDefaultPolicy)
// Prevent internal policies from being assigned to tokens. We check

View file

@ -989,6 +989,7 @@ type TestClusterOptions struct {
TempDir string
CACert []byte
CAKey *ecdsa.PrivateKey
FirstCoreNumber int
}
var DefaultNumCores = 3
@ -1019,6 +1020,11 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te
numCores = opts.NumCores
}
var firstCoreNumber int
if opts != nil {
firstCoreNumber = opts.FirstCoreNumber
}
certIPs := []net.IP{
net.IPv6loopback,
net.ParseIP("127.0.0.1"),
@ -1371,6 +1377,7 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te
if err != nil {
t.Fatalf("err: %v", err)
}
c.coreNumber = firstCoreNumber + i
cores = append(cores, c)
coreConfigs = append(coreConfigs, &localConfig)
if opts != nil && opts.HandlerFunc != nil {

View file

@ -32,6 +32,7 @@ import (
"github.com/hashicorp/vault/sdk/helper/policyutil"
"github.com/hashicorp/vault/sdk/helper/salt"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/hashicorp/vault/sdk/helper/tokenutil"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/sdk/plugin/pb"
"github.com/mitchellh/mapstructure"
@ -47,7 +48,7 @@ const (
accessorPrefix = "accessor/"
// parentPrefix is the prefix used to store tokens for their
// secondar parent based index
// secondary parent based index
parentPrefix = "parent/"
// tokenSubPath is the sub-path used for the token store
@ -103,7 +104,7 @@ var (
)
func (ts *TokenStore) paths() []*framework.Path {
return []*framework.Path{
p := []*framework.Path{
{
Pattern: "roles/?$",
@ -126,76 +127,6 @@ func (ts *TokenStore) paths() []*framework.Path {
HelpDescription: tokenListAccessorsHelp,
},
{
Pattern: "roles/" + framework.GenericNameRegex("role_name"),
Fields: map[string]*framework.FieldSchema{
"role_name": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Name of the role",
},
"allowed_policies": &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: tokenAllowedPoliciesHelp,
},
"disallowed_policies": &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: tokenDisallowedPoliciesHelp,
},
"orphan": &framework.FieldSchema{
Type: framework.TypeBool,
Default: false,
Description: tokenOrphanHelp,
},
"period": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Default: 0,
Description: tokenPeriodHelp,
},
"path_suffix": &framework.FieldSchema{
Type: framework.TypeString,
Default: "",
Description: tokenPathSuffixHelp + pathSuffixSanitize.String(),
},
"explicit_max_ttl": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Default: 0,
Description: tokenExplicitMaxTTLHelp,
},
"renewable": &framework.FieldSchema{
Type: framework.TypeBool,
Default: true,
Description: tokenRenewableHelp,
},
"bound_cidrs": &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: `Comma separated string or JSON list of CIDR blocks. If set, specifies the blocks of IP addresses which are allowed to use the generated token.`,
},
"token_type": &framework.FieldSchema{
Type: framework.TypeString,
Default: "service",
Description: "The type of token to generate, service or batch",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: ts.tokenStoreRoleRead,
logical.CreateOperation: ts.tokenStoreRoleCreateUpdate,
logical.UpdateOperation: ts.tokenStoreRoleCreateUpdate,
logical.DeleteOperation: ts.tokenStoreRoleDelete,
},
ExistenceCheck: ts.tokenStoreRoleExistenceCheck,
},
{
Pattern: "create-orphan$",
@ -414,6 +345,74 @@ func (ts *TokenStore) paths() []*framework.Path {
HelpDescription: strings.TrimSpace(tokenTidyDesc),
},
}
rolesPath := &framework.Path{
Pattern: "roles/" + framework.GenericNameRegex("role_name"),
Fields: map[string]*framework.FieldSchema{
"role_name": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Name of the role",
},
"allowed_policies": &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: tokenAllowedPoliciesHelp,
},
"disallowed_policies": &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: tokenDisallowedPoliciesHelp,
},
"orphan": &framework.FieldSchema{
Type: framework.TypeBool,
Description: tokenOrphanHelp,
},
"period": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Description: "(DEPRECATED) Use 'token_period' instead. If this and 'token_period' are both specified both will be retained but 'token_period' will take precedence.",
Deprecated: true,
},
"path_suffix": &framework.FieldSchema{
Type: framework.TypeString,
Description: tokenPathSuffixHelp + pathSuffixSanitize.String(),
},
"explicit_max_ttl": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Description: "(DEPRECATED) Use 'token_explicit_max_ttl' instead. If this and 'token_explicit_max_ttl' are both specified both will be retained but 'token_explicit_max_ttl' will take precedence.",
Deprecated: true,
},
"renewable": &framework.FieldSchema{
Type: framework.TypeBool,
Default: true,
Description: tokenRenewableHelp,
},
"bound_cidrs": &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: "(DEPRECATED) Use 'token_bound_cidrs' instead. If this and 'token_bound_cidrs' are both specified both will be retained but 'token_bound_cidrs' will take precedence.",
Deprecated: true,
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: ts.tokenStoreRoleRead,
logical.CreateOperation: ts.tokenStoreRoleCreateUpdate,
logical.UpdateOperation: ts.tokenStoreRoleCreateUpdate,
logical.DeleteOperation: ts.tokenStoreRoleDelete,
},
ExistenceCheck: ts.tokenStoreRoleExistenceCheck,
}
tokenutil.AddTokenFieldsWithAllowList(rolesPath.Fields, []string{"token_bound_cidrs", "token_explicit_max_ttl", "token_period", "token_type", "token_no_default_policy", "token_num_uses"})
p = append(p, rolesPath)
return p
}
// LookupToken returns the properties of the token from the token store. This
@ -540,7 +539,6 @@ func NewTokenStore(ctx context.Context, logger log.Logger, core *Core, config *l
}
func (ts *TokenStore) Invalidate(ctx context.Context, key string) {
//ts.logger.Debug("invalidating key", "key", key)
switch key {
case tokenSubPath + salt.DefaultLocation:
@ -581,6 +579,8 @@ func (ts *TokenStore) Salt(ctx context.Context) (*salt.Salt, error) {
// tsRoleEntry contains token store role information
type tsRoleEntry struct {
tokenutil.TokenParams
// The name of the role. Embedded so it can be used for pathing
Name string `json:"name" mapstructure:"name" structs:"name"`
@ -611,9 +611,6 @@ type tsRoleEntry struct {
// The set of CIDRs that tokens generated using this role will be bound to
BoundCIDRs []*sockaddr.SockAddrMarshaler `json:"bound_cidrs"`
// The type of token this role should issue
TokenType logical.TokenType `json:"token_type" mapstructure:"token_type"`
}
type accessorEntry struct {
@ -2236,6 +2233,16 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
renewable = false
}
// Update te.NumUses which is equal to req.Data["num_uses"] at this point
// 0 means unlimited so 1 is actually less than 0
switch {
case role.TokenNumUses == 0:
case te.NumUses == 0:
te.NumUses = role.TokenNumUses
case role.TokenNumUses < te.NumUses:
te.NumUses = role.TokenNumUses
}
if role.PathSuffix != "" {
te.Path = fmt.Sprintf("%s/%s", te.Path, role.PathSuffix)
}
@ -2284,7 +2291,7 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
// isn't in the disallowed list, add it. This is in line with the idea
// that roles, when allowed/disallowed ar set, allow a subset of
// policies to be set disjoint from the parent token's policies.
if !data.NoDefaultPolicy && !strutil.StrListContains(role.DisallowedPolicies, "default") {
if !data.NoDefaultPolicy && !role.TokenNoDefaultPolicy && !strutil.StrListContains(role.DisallowedPolicies, "default") {
localAddDefault = true
}
@ -2406,8 +2413,8 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
te.Parent = ""
}
if len(role.BoundCIDRs) > 0 {
te.BoundCIDRs = role.BoundCIDRs
if len(role.TokenBoundCIDRs) > 0 {
te.BoundCIDRs = role.TokenBoundCIDRs
}
case data.NoParent:
@ -2501,24 +2508,24 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
// in role. Batch tokens will error out if not set via role, but here we
// need to explicitly check
if role != nil && te.Type != logical.TokenTypeBatch {
if role.ExplicitMaxTTL != 0 {
if role.TokenExplicitMaxTTL != 0 {
switch {
case explicitMaxTTLToUse == 0:
explicitMaxTTLToUse = role.ExplicitMaxTTL
explicitMaxTTLToUse = role.TokenExplicitMaxTTL
default:
if role.ExplicitMaxTTL < explicitMaxTTLToUse {
explicitMaxTTLToUse = role.ExplicitMaxTTL
if role.TokenExplicitMaxTTL < explicitMaxTTLToUse {
explicitMaxTTLToUse = role.TokenExplicitMaxTTL
}
resp.AddWarning(fmt.Sprintf("Explicit max TTL specified both during creation call and in role; using the lesser value of %d seconds", int64(explicitMaxTTLToUse.Seconds())))
}
}
if role.Period != 0 {
if role.TokenPeriod != 0 {
switch {
case periodToUse == 0:
periodToUse = role.Period
periodToUse = role.TokenPeriod
default:
if role.Period < periodToUse {
periodToUse = role.Period
if role.TokenPeriod < periodToUse {
periodToUse = role.TokenPeriod
}
resp.AddWarning(fmt.Sprintf("Period specified both during creation call and in role; using the lesser value of %d seconds", int64(periodToUse.Seconds())))
}
@ -2872,8 +2879,8 @@ func (ts *TokenStore) authRenew(ctx context.Context, req *logical.Request, d *fr
return nil, fmt.Errorf("original token role %q could not be found, not renewing", te.Role)
}
req.Auth.Period = role.Period
req.Auth.ExplicitMaxTTL = role.ExplicitMaxTTL
req.Auth.Period = role.TokenPeriod
req.Auth.ExplicitMaxTTL = role.TokenExplicitMaxTTL
return &logical.Response{Auth: req.Auth}, nil
}
@ -2900,6 +2907,18 @@ func (ts *TokenStore) tokenStoreRole(ctx context.Context, name string) (*tsRoleE
result.TokenType = logical.TokenTypeDefaultService
}
// Token field upgrades. We preserve the original value for read
// compatibility.
if result.Period > 0 && result.TokenPeriod == 0 {
result.TokenPeriod = result.Period
}
if result.ExplicitMaxTTL > 0 && result.TokenExplicitMaxTTL == 0 {
result.TokenExplicitMaxTTL = result.ExplicitMaxTTL
}
if len(result.BoundCIDRs) > 0 && len(result.TokenBoundCIDRs) == 0 {
result.TokenBoundCIDRs = result.BoundCIDRs
}
return &result, nil
}
@ -2945,23 +2964,32 @@ func (ts *TokenStore) tokenStoreRoleRead(ctx context.Context, req *logical.Reque
return nil, nil
}
// TODO (1.4): Remove "period" and "explicit_max_ttl" if they're zero
resp := &logical.Response{
Data: map[string]interface{}{
"period": int64(role.Period.Seconds()),
"explicit_max_ttl": int64(role.ExplicitMaxTTL.Seconds()),
"disallowed_policies": role.DisallowedPolicies,
"allowed_policies": role.AllowedPolicies,
"name": role.Name,
"orphan": role.Orphan,
"path_suffix": role.PathSuffix,
"renewable": role.Renewable,
"token_type": role.TokenType.String(),
"period": int64(role.Period.Seconds()),
"token_period": int64(role.TokenPeriod.Seconds()),
"explicit_max_ttl": int64(role.ExplicitMaxTTL.Seconds()),
"token_explicit_max_ttl": int64(role.TokenExplicitMaxTTL.Seconds()),
"disallowed_policies": role.DisallowedPolicies,
"allowed_policies": role.AllowedPolicies,
"name": role.Name,
"orphan": role.Orphan,
"path_suffix": role.PathSuffix,
"renewable": role.Renewable,
"token_type": role.TokenType.String(),
},
}
if len(role.TokenBoundCIDRs) > 0 {
resp.Data["token_bound_cidrs"] = role.TokenBoundCIDRs
}
if len(role.BoundCIDRs) > 0 {
resp.Data["bound_cidrs"] = role.BoundCIDRs
}
if role.TokenNumUses > 0 {
resp.Data["token_num_uses"] = role.TokenNumUses
}
return resp, nil
}
@ -2997,140 +3025,160 @@ func (ts *TokenStore) tokenStoreRoleCreateUpdate(ctx context.Context, req *logic
}
}
// In this series of blocks, if we do not find a user-provided value and
// it's a creation operation, we call data.Get to get the appropriate
// default
orphanInt, ok := data.GetOk("orphan")
if ok {
entry.Orphan = orphanInt.(bool)
} else if req.Operation == logical.CreateOperation {
entry.Orphan = data.Get("orphan").(bool)
}
periodInt, ok := data.GetOk("period")
if ok {
entry.Period = time.Second * time.Duration(periodInt.(int))
} else if req.Operation == logical.CreateOperation {
entry.Period = time.Second * time.Duration(data.Get("period").(int))
}
renewableInt, ok := data.GetOk("renewable")
if ok {
entry.Renewable = renewableInt.(bool)
} else if req.Operation == logical.CreateOperation {
entry.Renewable = data.Get("renewable").(bool)
}
boundCIDRsRaw, ok := data.GetOk("bound_cidrs")
if ok {
boundCIDRs := boundCIDRsRaw.([]string)
if len(boundCIDRs) == 0 {
entry.BoundCIDRs = nil
} else {
var parsedCIDRs []*sockaddr.SockAddrMarshaler
for _, v := range boundCIDRs {
parsedCIDR, err := sockaddr.NewSockAddr(v)
if err != nil {
return logical.ErrorResponse(errwrap.Wrapf(fmt.Sprintf("invalid value %q when parsing bound cidrs: {{err}}", v), err).Error()), nil
}
parsedCIDRs = append(parsedCIDRs, &sockaddr.SockAddrMarshaler{parsedCIDR})
}
entry.BoundCIDRs = parsedCIDRs
// First parse fields not duplicated by the token helper
{
orphanInt, ok := data.GetOk("orphan")
if ok {
entry.Orphan = orphanInt.(bool)
} else if req.Operation == logical.CreateOperation {
entry.Orphan = data.Get("orphan").(bool)
}
renewableInt, ok := data.GetOk("renewable")
if ok {
entry.Renewable = renewableInt.(bool)
} else if req.Operation == logical.CreateOperation {
entry.Renewable = data.Get("renewable").(bool)
}
pathSuffixInt, ok := data.GetOk("path_suffix")
if ok {
pathSuffix := pathSuffixInt.(string)
switch {
case pathSuffix != "":
matched := pathSuffixSanitize.MatchString(pathSuffix)
if !matched {
return logical.ErrorResponse(fmt.Sprintf(
"given role path suffix contains invalid characters; must match %s",
pathSuffixSanitize.String())), nil
}
}
entry.PathSuffix = pathSuffix
} else if req.Operation == logical.CreateOperation {
entry.PathSuffix = data.Get("path_suffix").(string)
}
if strings.Contains(entry.PathSuffix, "..") {
return logical.ErrorResponse(fmt.Sprintf("error registering path suffix: %s", consts.ErrPathContainsParentReferences)), nil
}
allowedPoliciesRaw, ok := data.GetOk("allowed_policies")
if ok {
entry.AllowedPolicies = policyutil.SanitizePolicies(allowedPoliciesRaw.([]string), policyutil.DoNotAddDefaultPolicy)
} else if req.Operation == logical.CreateOperation {
entry.AllowedPolicies = policyutil.SanitizePolicies(data.Get("allowed_policies").([]string), policyutil.DoNotAddDefaultPolicy)
}
disallowedPoliciesRaw, ok := data.GetOk("disallowed_policies")
if ok {
entry.DisallowedPolicies = strutil.RemoveDuplicates(disallowedPoliciesRaw.([]string), true)
} else if req.Operation == logical.CreateOperation {
entry.DisallowedPolicies = strutil.RemoveDuplicates(data.Get("disallowed_policies").([]string), true)
}
}
// Next parse token fields from the helper
if err := entry.ParseTokenFields(req, data); err != nil {
return logical.ErrorResponse(errwrap.Wrapf("error parsing role fields: {{err}}", err).Error()), nil
}
var resp *logical.Response
explicitMaxTTLInt, ok := data.GetOk("explicit_max_ttl")
if ok {
entry.ExplicitMaxTTL = time.Second * time.Duration(explicitMaxTTLInt.(int))
} else if req.Operation == logical.CreateOperation {
entry.ExplicitMaxTTL = time.Second * time.Duration(data.Get("explicit_max_ttl").(int))
// Now handle backwards compat. Prefer token_ fields over others if both
// are set. We set the original fields here so that on read of token role
// we can return the same values that were set. We clear out the Token*
// values because otherwise when we read the role back we'll read stale
// data since if they're not emptied they'll take precedence.
periodRaw, ok := data.GetOk("token_period")
if !ok {
periodRaw, ok = data.GetOk("period")
if ok {
entry.Period = time.Second * time.Duration(periodRaw.(int))
entry.TokenPeriod = 0
}
} else {
_, ok = data.GetOk("period")
if ok {
if resp == nil {
resp = &logical.Response{}
}
resp.AddWarning("Both 'token_period' and deprecated 'period' value supplied, ignoring the deprecated value")
}
entry.Period = 0
}
if entry.ExplicitMaxTTL != 0 {
boundCIDRsRaw, ok := data.GetOk("token_bound_cidrs")
if !ok {
boundCIDRsRaw, ok = data.GetOk("bound_cidrs")
if ok {
boundCIDRs, err := parseutil.ParseAddrs(boundCIDRsRaw.([]string))
if err != nil {
return logical.ErrorResponse(errwrap.Wrapf("error parsing bound_cidrs: {{err}}", err).Error()), nil
}
entry.BoundCIDRs = boundCIDRs
entry.TokenBoundCIDRs = nil
}
} else {
_, ok = data.GetOk("bound_cidrs")
if ok {
if resp == nil {
resp = &logical.Response{}
}
resp.AddWarning("Both 'token_bound_cidrs' and deprecated 'bound_cidrs' value supplied, ignoring the deprecated value")
}
entry.BoundCIDRs = nil
}
finalExplicitMaxTTL := entry.TokenExplicitMaxTTL
explicitMaxTTLRaw, ok := data.GetOk("token_explicit_max_ttl")
if !ok {
explicitMaxTTLRaw, ok = data.GetOk("explicit_max_ttl")
if ok {
entry.ExplicitMaxTTL = time.Second * time.Duration(explicitMaxTTLRaw.(int))
entry.TokenExplicitMaxTTL = 0
}
finalExplicitMaxTTL = entry.ExplicitMaxTTL
} else {
_, ok = data.GetOk("explicit_max_ttl")
if ok {
if resp == nil {
resp = &logical.Response{}
}
resp.AddWarning("Both 'token_explicit_max_ttl' and deprecated 'explicit_max_ttl' value supplied, ignoring the deprecated value")
}
entry.ExplicitMaxTTL = 0
}
if finalExplicitMaxTTL != 0 {
sysView := ts.System()
if sysView.MaxLeaseTTL() != time.Duration(0) && entry.ExplicitMaxTTL > sysView.MaxLeaseTTL() {
if sysView.MaxLeaseTTL() != time.Duration(0) && finalExplicitMaxTTL > sysView.MaxLeaseTTL() {
if resp == nil {
resp = &logical.Response{}
}
resp.AddWarning(fmt.Sprintf(
"Given explicit max TTL of %d is greater than system/mount allowed value of %d seconds; until this is fixed attempting to create tokens against this role will result in an error",
int64(entry.ExplicitMaxTTL.Seconds()), int64(sysView.MaxLeaseTTL().Seconds())))
int64(finalExplicitMaxTTL.Seconds()), int64(sysView.MaxLeaseTTL().Seconds())))
}
}
pathSuffixInt, ok := data.GetOk("path_suffix")
// no legacy version without the token_ prefix to check for
tokenNumUses, ok := data.GetOk("token_num_uses")
if ok {
pathSuffix := pathSuffixInt.(string)
switch {
case pathSuffix != "":
matched := pathSuffixSanitize.MatchString(pathSuffix)
if !matched {
return logical.ErrorResponse(fmt.Sprintf(
"given role path suffix contains invalid characters; must match %s",
pathSuffixSanitize.String())), nil
}
}
entry.PathSuffix = pathSuffix
} else if req.Operation == logical.CreateOperation {
entry.PathSuffix = data.Get("path_suffix").(string)
entry.TokenNumUses = tokenNumUses.(int)
}
if strings.Contains(entry.PathSuffix, "..") {
return logical.ErrorResponse(fmt.Sprintf("error registering path suffix: %s", consts.ErrPathContainsParentReferences)), nil
}
allowedPoliciesRaw, ok := data.GetOk("allowed_policies")
if ok {
entry.AllowedPolicies = policyutil.SanitizePolicies(allowedPoliciesRaw.([]string), policyutil.DoNotAddDefaultPolicy)
} else if req.Operation == logical.CreateOperation {
entry.AllowedPolicies = policyutil.SanitizePolicies(data.Get("allowed_policies").([]string), policyutil.DoNotAddDefaultPolicy)
}
disallowedPoliciesRaw, ok := data.GetOk("disallowed_policies")
if ok {
entry.DisallowedPolicies = strutil.RemoveDuplicates(disallowedPoliciesRaw.([]string), true)
} else if req.Operation == logical.CreateOperation {
entry.DisallowedPolicies = strutil.RemoveDuplicates(data.Get("disallowed_policies").([]string), true)
}
tokenType := entry.TokenType
if tokenType == logical.TokenTypeDefault {
tokenType = logical.TokenTypeDefaultService
}
tokenTypeRaw, ok := data.GetOk("token_type")
if ok {
tokenTypeStr := tokenTypeRaw.(string)
switch tokenTypeStr {
case "service":
tokenType = logical.TokenTypeService
case "batch":
tokenType = logical.TokenTypeBatch
case "default-service":
tokenType = logical.TokenTypeDefaultService
case "default-batch":
tokenType = logical.TokenTypeDefaultBatch
default:
return logical.ErrorResponse(fmt.Sprintf("invalid 'token_type' value %q", tokenTypeStr)), nil
}
} else if req.Operation == logical.CreateOperation {
tokenType = logical.TokenTypeDefaultService
}
entry.TokenType = tokenType
// Run validity checks on token type
if entry.TokenType == logical.TokenTypeBatch {
if !entry.Orphan {
return logical.ErrorResponse("'token_type' cannot be 'batch' when role is set to generate non-orphan tokens"), nil
}
if entry.Period != 0 {
if entry.Period != 0 || entry.TokenPeriod != 0 {
return logical.ErrorResponse("'token_type' cannot be 'batch' when role is set to generate periodic tokens"), nil
}
if entry.Renewable {
return logical.ErrorResponse("'token_type' cannot be 'batch' when role is set to generate renewable tokens"), nil
}
if entry.ExplicitMaxTTL != 0 {
if entry.ExplicitMaxTTL != 0 || entry.TokenExplicitMaxTTL != 0 {
return logical.ErrorResponse("'token_type' cannot be 'batch' when role is set to generate tokens with an explicit max TTL"), nil
}
}

View file

@ -21,6 +21,8 @@ import (
uuid "github.com/hashicorp/go-uuid"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/sdk/helper/locksutil"
"github.com/hashicorp/vault/sdk/helper/parseutil"
"github.com/hashicorp/vault/sdk/helper/tokenutil"
"github.com/hashicorp/vault/sdk/logical"
)
@ -2679,6 +2681,8 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
"allowed_policies": "test1,test2",
"path_suffix": "happenin",
"bound_cidrs": []string{"0.0.0.0/0"},
"explicit_max_ttl": "2h",
"token_num_uses": 123,
}
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
@ -2703,21 +2707,28 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
}
expected := map[string]interface{}{
"name": "test",
"orphan": true,
"period": int64(259200),
"allowed_policies": []string{"test1", "test2"},
"disallowed_policies": []string{},
"path_suffix": "happenin",
"explicit_max_ttl": int64(0),
"renewable": true,
"token_type": "default-service",
"name": "test",
"orphan": true,
"token_period": int64(259200),
"period": int64(259200),
"allowed_policies": []string{"test1", "test2"},
"disallowed_policies": []string{},
"path_suffix": "happenin",
"explicit_max_ttl": int64(7200),
"token_explicit_max_ttl": int64(7200),
"renewable": true,
"token_type": "default-service",
"token_num_uses": 123,
}
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
t.Fatal("unexpected bound cidrs")
}
delete(resp.Data, "bound_cidrs")
if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
t.Fatal("unexpected bound cidrs")
}
delete(resp.Data, "token_bound_cidrs")
if diff := deep.Equal(expected, resp.Data); diff != nil {
t.Fatal(diff)
@ -2731,6 +2742,8 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
"allowed_policies": "test3",
"path_suffix": "happenin",
"renewable": false,
"explicit_max_ttl": "80h",
"token_num_uses": 0,
}
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
@ -2754,21 +2767,27 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
}
expected = map[string]interface{}{
"name": "test",
"orphan": true,
"period": int64(284400),
"allowed_policies": []string{"test3"},
"disallowed_policies": []string{},
"path_suffix": "happenin",
"explicit_max_ttl": int64(0),
"renewable": false,
"token_type": "default-service",
"name": "test",
"orphan": true,
"period": int64(284400),
"token_period": int64(284400),
"allowed_policies": []string{"test3"},
"disallowed_policies": []string{},
"path_suffix": "happenin",
"token_explicit_max_ttl": int64(288000),
"explicit_max_ttl": int64(288000),
"renewable": false,
"token_type": "default-service",
}
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
t.Fatal("unexpected bound cidrs")
}
delete(resp.Data, "bound_cidrs")
if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
t.Fatal("unexpected bound cidrs")
}
delete(resp.Data, "token_bound_cidrs")
if diff := deep.Equal(expected, resp.Data); diff != nil {
t.Fatal(diff)
@ -2797,21 +2816,27 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
}
expected = map[string]interface{}{
"name": "test",
"orphan": true,
"explicit_max_ttl": int64(5),
"allowed_policies": []string{"test3"},
"disallowed_policies": []string{},
"path_suffix": "happenin",
"period": int64(0),
"renewable": false,
"token_type": "default-service",
"name": "test",
"orphan": true,
"explicit_max_ttl": int64(5),
"token_explicit_max_ttl": int64(5),
"allowed_policies": []string{"test3"},
"disallowed_policies": []string{},
"path_suffix": "happenin",
"period": int64(0),
"token_period": int64(0),
"renewable": false,
"token_type": "default-service",
}
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
t.Fatal("unexpected bound cidrs")
}
delete(resp.Data, "bound_cidrs")
if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
t.Fatal("unexpected bound cidrs")
}
delete(resp.Data, "token_bound_cidrs")
if diff := deep.Equal(expected, resp.Data); diff != nil {
t.Fatal(diff)
@ -2840,15 +2865,17 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
}
expected = map[string]interface{}{
"name": "test",
"orphan": true,
"explicit_max_ttl": int64(5),
"allowed_policies": []string{"test3"},
"disallowed_policies": []string{},
"path_suffix": "",
"period": int64(0),
"renewable": false,
"token_type": "default-service",
"name": "test",
"orphan": true,
"token_explicit_max_ttl": int64(5),
"explicit_max_ttl": int64(5),
"allowed_policies": []string{"test3"},
"disallowed_policies": []string{},
"path_suffix": "",
"period": int64(0),
"token_period": int64(0),
"renewable": false,
"token_type": "default-service",
}
if diff := deep.Equal(expected, resp.Data); diff != nil {
@ -3585,6 +3612,248 @@ func TestTokenStore_RoleExplicitMaxTTL(t *testing.T) {
}
}
func TestTokenStore_RoleTokenFields(t *testing.T) {
c, _, _ := TestCoreUnsealed(t)
//c, _, root := TestCoreUnsealed(t)
ts := c.tokenStore
rootContext := namespace.RootContext(context.Background())
boundCIDRs, err := parseutil.ParseAddrs([]string{"127.0.0.1/32"})
if err != nil {
t.Fatal(err)
}
// First test the upgrade case. Create a role with values and ensure they
// are reflected properly on read.
{
roleEntry := &tsRoleEntry{
Name: "test",
TokenParams: tokenutil.TokenParams{
TokenType: logical.TokenTypeBatch,
},
Period: time.Second,
ExplicitMaxTTL: time.Hour,
}
roleEntry.BoundCIDRs = boundCIDRs
ns := namespace.RootNamespace
jsonEntry, err := logical.StorageEntryJSON("test", roleEntry)
if err != nil {
t.Fatal(err)
}
if err := ts.rolesView(ns).Put(rootContext, jsonEntry); err != nil {
t.Fatal(err)
}
// Read it back
roleEntry, err = ts.tokenStoreRole(rootContext, "test")
if err != nil {
t.Fatal(err)
}
expRoleEntry := &tsRoleEntry{
Name: "test",
TokenParams: tokenutil.TokenParams{
TokenPeriod: time.Second,
TokenExplicitMaxTTL: time.Hour,
TokenBoundCIDRs: boundCIDRs,
TokenType: logical.TokenTypeBatch,
},
Period: time.Second,
ExplicitMaxTTL: time.Hour,
BoundCIDRs: boundCIDRs,
}
if diff := deep.Equal(expRoleEntry, roleEntry); diff != nil {
t.Fatal(diff)
}
}
// Now, read that back through the API and verify we see what we expect
{
req := logical.TestRequest(t, logical.ReadOperation, "roles/test")
resp, err := ts.HandleRequest(rootContext, req)
if err != nil {
t.Fatalf("err: %v", err)
}
expected := map[string]interface{}{
"name": "test",
"orphan": false,
"period": int64(1),
"token_period": int64(1),
"allowed_policies": []string(nil),
"disallowed_policies": []string(nil),
"path_suffix": "",
"token_explicit_max_ttl": int64(3600),
"explicit_max_ttl": int64(3600),
"renewable": false,
"token_type": "batch",
}
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
t.Fatalf("unexpected bound cidrs: %s", resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String())
}
delete(resp.Data, "bound_cidrs")
if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
t.Fatalf("unexpected token bound cidrs: %s", resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String())
}
delete(resp.Data, "token_bound_cidrs")
if diff := deep.Equal(expected, resp.Data); diff != nil {
t.Fatal(diff)
}
}
// Put values in just the old locations, but through the API
{
req := logical.TestRequest(t, logical.UpdateOperation, "roles/test")
req.Data = map[string]interface{}{
"explicit_max_ttl": 7200,
"token_type": "default-batch",
"period": 5,
"bound_cidrs": boundCIDRs[0].String(),
}
resp, err := ts.HandleRequest(rootContext, req)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err: %v\nresp: %#v", err, resp)
}
if resp != nil {
t.Fatalf("expected a nil response")
}
req = logical.TestRequest(t, logical.ReadOperation, "roles/test")
resp, err = ts.HandleRequest(rootContext, req)
if err != nil {
t.Fatalf("err: %v", err)
}
expected := map[string]interface{}{
"name": "test",
"orphan": false,
"period": int64(5),
"token_period": int64(5),
"allowed_policies": []string(nil),
"disallowed_policies": []string(nil),
"path_suffix": "",
"token_explicit_max_ttl": int64(7200),
"explicit_max_ttl": int64(7200),
"renewable": false,
"token_type": "default-batch",
}
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
t.Fatalf("unexpected bound cidrs: %s", resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String())
}
delete(resp.Data, "bound_cidrs")
if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
t.Fatalf("unexpected token bound cidrs: %s", resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String())
}
delete(resp.Data, "token_bound_cidrs")
if diff := deep.Equal(expected, resp.Data); diff != nil {
t.Fatal(diff)
}
}
// Same thing for just the new locations
{
req := logical.TestRequest(t, logical.UpdateOperation, "roles/test")
req.Data = map[string]interface{}{
"token_explicit_max_ttl": 5200,
"token_type": "default-service",
"token_period": 7,
"token_bound_cidrs": boundCIDRs[0].String(),
}
resp, err := ts.HandleRequest(rootContext, req)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err: %v\nresp: %#v", err, resp)
}
if resp != nil {
t.Fatalf("expected a nil response")
}
req = logical.TestRequest(t, logical.ReadOperation, "roles/test")
resp, err = ts.HandleRequest(rootContext, req)
if err != nil {
t.Fatalf("err: %v", err)
}
expected := map[string]interface{}{
"name": "test",
"orphan": false,
"period": int64(0),
"token_period": int64(7),
"allowed_policies": []string(nil),
"disallowed_policies": []string(nil),
"path_suffix": "",
"token_explicit_max_ttl": int64(5200),
"explicit_max_ttl": int64(0),
"renewable": false,
"token_type": "default-service",
}
if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
t.Fatalf("unexpected token bound cidrs: %s", resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String())
}
delete(resp.Data, "token_bound_cidrs")
if diff := deep.Equal(expected, resp.Data); diff != nil {
t.Fatal(diff)
}
}
// Put values in both locations
{
req := logical.TestRequest(t, logical.UpdateOperation, "roles/test")
req.Data = map[string]interface{}{
"token_explicit_max_ttl": 7200,
"explicit_max_ttl": 5200,
"token_type": "service",
"token_period": 5,
"period": 1,
"token_bound_cidrs": boundCIDRs[0].String(),
"bound_cidrs": boundCIDRs[0].String(),
}
resp, err := ts.HandleRequest(rootContext, req)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err: %v\nresp: %#v", err, resp)
}
if resp == nil {
t.Fatalf("expected a non-nil response")
}
if len(resp.Warnings) != 3 {
t.Fatalf("expected 3 warnings, got %#v", resp.Warnings)
}
req = logical.TestRequest(t, logical.ReadOperation, "roles/test")
resp, err = ts.HandleRequest(rootContext, req)
if err != nil {
t.Fatalf("err: %v", err)
}
expected := map[string]interface{}{
"name": "test",
"orphan": false,
"period": int64(0),
"token_period": int64(5),
"allowed_policies": []string(nil),
"disallowed_policies": []string(nil),
"path_suffix": "",
"token_explicit_max_ttl": int64(7200),
"explicit_max_ttl": int64(0),
"renewable": false,
"token_type": "service",
}
if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
t.Fatalf("unexpected token bound cidrs: %s", resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String())
}
delete(resp.Data, "token_bound_cidrs")
if diff := deep.Equal(expected, resp.Data); diff != nil {
t.Fatal(diff)
}
}
}
func TestTokenStore_Periodic(t *testing.T) {
core, _, root := TestCoreUnsealed(t)
@ -3726,6 +3995,120 @@ func TestTokenStore_Periodic(t *testing.T) {
}
}
func testTokenStore_NumUses_ErrorCheckHelper(t *testing.T, resp *logical.Response, err error) {
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("response was nil")
}
if resp.Auth == nil {
t.Fatalf(fmt.Sprintf("response auth was nil, resp is %#v", *resp))
}
if resp.Auth.ClientToken == "" {
t.Fatalf("bad: %#v", resp)
}
}
func testTokenStore_NumUses_SelfLookupHelper(t *testing.T, core *Core, clientToken string, expectedNumUses int) {
req := logical.TestRequest(t, logical.ReadOperation, "auth/token/lookup-self")
req.ClientToken = clientToken
resp, err := core.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Just used the token, this should decrement the num_uses counter
expectedNumUses = expectedNumUses - 1
actualNumUses := resp.Data["num_uses"].(int)
if actualNumUses != expectedNumUses {
t.Fatalf("num_uses mismatch (expected %d, got %d)", expectedNumUses, actualNumUses)
}
}
func TestTokenStore_NumUses(t *testing.T) {
core, _, root := TestCoreUnsealed(t)
roleNumUses := 10
lesserNumUses := 5
greaterNumUses := 15
// Create a test role with limited token_num_uses
req := logical.TestRequest(t, logical.UpdateOperation, "auth/token/roles/test-limited-uses")
req.ClientToken = root
req.Data = map[string]interface{}{
"token_num_uses": roleNumUses,
}
resp, err := core.HandleRequest(namespace.RootContext(nil), req)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err: %v\nresp: %#v", err, resp)
}
if resp != nil {
t.Fatalf("expected a nil response")
}
// Create a test role with unlimited token_num_uses
req.Path = "auth/token/roles/test-unlimited-uses"
req.Data = map[string]interface{}{}
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err: %v\nresp: %#v", err, resp)
}
if resp != nil {
t.Fatalf("expected a nil response")
}
// Generate some tokens from the test roles
req.Path = "auth/token/create/test-limited-uses"
// first token, num_uses is expected to come from the limited uses role
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
testTokenStore_NumUses_ErrorCheckHelper(t, resp, err)
noOverrideToken := resp.Auth.ClientToken
// second token, override num_uses with a lesser value, this should become the value
// applied to the token
req.Data = map[string]interface{}{
"num_uses": lesserNumUses,
}
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
testTokenStore_NumUses_ErrorCheckHelper(t, resp, err)
lesserOverrideToken := resp.Auth.ClientToken
// third token, override num_uses with a greater value, the value
// applied to the token should come from the limited uses role
req.Data = map[string]interface{}{
"num_uses": greaterNumUses,
}
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
testTokenStore_NumUses_ErrorCheckHelper(t, resp, err)
greaterOverrideToken := resp.Auth.ClientToken
// fourth token, override num_uses with a zero value, a num_uses value of zero
// has an internal meaning of unlimited so num_uses == 1 is actually less than
// num_uses == 0. In this case, the lesser value of the limited-uses role should be applied.
req.Data = map[string]interface{}{
"num_uses": 0,
}
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
testTokenStore_NumUses_ErrorCheckHelper(t, resp, err)
zeroOverrideToken := resp.Auth.ClientToken
// fifth token, override num_uses with a value from a role that has unlimited num_uses. num_uses
// should be the specified num_uses parameter at the create endpoint
req.Path = "auth/token/create/test-unlimited-uses"
req.Data = map[string]interface{}{
"num_uses": lesserNumUses,
}
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
testTokenStore_NumUses_ErrorCheckHelper(t, resp, err)
unlimitedRoleOverrideToken := resp.Auth.ClientToken
testTokenStore_NumUses_SelfLookupHelper(t, core, noOverrideToken, roleNumUses)
testTokenStore_NumUses_SelfLookupHelper(t, core, lesserOverrideToken, lesserNumUses)
testTokenStore_NumUses_SelfLookupHelper(t, core, greaterOverrideToken, roleNumUses)
testTokenStore_NumUses_SelfLookupHelper(t, core, zeroOverrideToken, roleNumUses)
testTokenStore_NumUses_SelfLookupHelper(t, core, unlimitedRoleOverrideToken, lesserNumUses)
}
func TestTokenStore_Periodic_ExplicitMax(t *testing.T) {
core, _, root := TestCoreUnsealed(t)

View file

@ -11,7 +11,7 @@ require (
github.com/hashicorp/go-retryablehttp v0.5.3
github.com/hashicorp/go-rootcerts v1.0.0
github.com/hashicorp/hcl v1.0.0
github.com/hashicorp/vault/sdk v0.1.8
github.com/hashicorp/vault/sdk v0.1.12-0.20190614165924-47d4e5b1f688
github.com/mitchellh/mapstructure v1.1.2
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4

View file

@ -234,7 +234,7 @@ func (c *Sys) RekeyRetrieveBackup() (*RekeyRetrieveResponse, error) {
}
func (c *Sys) RekeyRetrieveRecoveryBackup() (*RekeyRetrieveResponse, error) {
r := c.c.NewRequest("GET", "/v1/sys/rekey/recovery-backup")
r := c.c.NewRequest("GET", "/v1/sys/rekey/recovery-key-backup")
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
@ -275,7 +275,7 @@ func (c *Sys) RekeyDeleteBackup() error {
}
func (c *Sys) RekeyDeleteRecoveryBackup() error {
r := c.c.NewRequest("DELETE", "/v1/sys/rekey/recovery-backup")
r := c.c.NewRequest("DELETE", "/v1/sys/rekey/recovery-key-backup")
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()

View file

@ -0,0 +1,233 @@
package tokenutil
import (
"errors"
"fmt"
"time"
sockaddr "github.com/hashicorp/go-sockaddr"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/parseutil"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/hashicorp/vault/sdk/logical"
)
// TokenParams contains a set of common parameters that auth plugins can use
// for setting token behavior
type TokenParams struct {
// The set of CIDRs that tokens generated using this role will be bound to
TokenBoundCIDRs []*sockaddr.SockAddrMarshaler `json:"token_bound_cidrs"`
// If set, the token entry will have an explicit maximum TTL set, rather
// than deferring to role/mount values
TokenExplicitMaxTTL time.Duration `json:"token_explicit_max_ttl" mapstructure:"token_explicit_max_ttl"`
// The max TTL to use for the token
TokenMaxTTL time.Duration `json:"token_max_ttl" mapstructure:"token_max_ttl"`
// If set, core will not automatically add default to the policy list
TokenNoDefaultPolicy bool `json:"token_no_default_policy" mapstructure:"token_no_default_policy"`
// The maximum number of times a token issued from this role may be used.
TokenNumUses int `json:"token_num_uses" mapstructure:"token_num_uses"`
// If non-zero, tokens created using this role will be able to be renewed
// forever, but will have a fixed renewal period of this value
TokenPeriod time.Duration `json:"token_period" mapstructure:"token_period"`
// The policies to set
TokenPolicies []string `json:"token_policies" mapstructure:"token_policies"`
// The type of token this role should issue
TokenType logical.TokenType `json:"token_type" mapstructure:"token_type"`
// The TTL to user for the token
TokenTTL time.Duration `json:"token_ttl" mapstructure:"token_ttl"`
}
// AddTokenFields adds fields to an existing role. It panics if it would
// overwrite an existing field.
func AddTokenFields(m map[string]*framework.FieldSchema) {
AddTokenFieldsWithAllowList(m, nil)
}
// AddTokenFields adds fields to an existing role. It panics if it would
// overwrite an existing field. Allowed can be use to restrict the set, e.g. if
// there would be conflicts.
func AddTokenFieldsWithAllowList(m map[string]*framework.FieldSchema, allowed []string) {
r := TokenFields()
for k, v := range r {
if len(allowed) > 0 && !strutil.StrListContains(allowed, k) {
continue
}
if _, has := m[k]; has {
panic(fmt.Sprintf("adding role field %s would overwrite existing field", k))
}
m[k] = v
}
}
// TokenFields provides a set of field schemas for the parameters
func TokenFields() map[string]*framework.FieldSchema {
return map[string]*framework.FieldSchema{
"token_bound_cidrs": &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: `Comma separated string or JSON list of CIDR blocks. If set, specifies the blocks of IP addresses which are allowed to use the generated token.`,
},
"token_explicit_max_ttl": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Description: tokenExplicitMaxTTLHelp,
},
"token_max_ttl": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Description: "The maximum lifetime of the generated token",
},
"token_no_default_policy": &framework.FieldSchema{
Type: framework.TypeBool,
Description: "If true, the 'default' policy will not automatically be added to generated tokens",
},
"token_period": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Description: tokenPeriodHelp,
},
"token_policies": &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: "Comma-separated list of policies",
},
"token_type": &framework.FieldSchema{
Type: framework.TypeString,
Default: "default-service",
Description: "The type of token to generate, service or batch",
},
"token_ttl": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Description: "The initial ttl of the token to generate",
},
"token_num_uses": &framework.FieldSchema{
Type: framework.TypeInt,
Description: "The maximum number of times a token may be used, a value of zero means unlimited",
},
}
}
// ParseTokenFields provides common field parsing functionality into a TokenFields struct
func (t *TokenParams) ParseTokenFields(req *logical.Request, d *framework.FieldData) error {
if boundCIDRsRaw, ok := d.GetOk("token_bound_cidrs"); ok {
boundCIDRs, err := parseutil.ParseAddrs(boundCIDRsRaw.([]string))
if err != nil {
return err
}
t.TokenBoundCIDRs = boundCIDRs
}
if explicitMaxTTLRaw, ok := d.GetOk("token_explicit_max_ttl"); ok {
t.TokenExplicitMaxTTL = time.Duration(explicitMaxTTLRaw.(int)) * time.Second
}
if maxTTLRaw, ok := d.GetOk("token_max_ttl"); ok {
t.TokenMaxTTL = time.Duration(maxTTLRaw.(int)) * time.Second
}
if t.TokenMaxTTL < 0 {
return errors.New("'token_max_ttl' cannot be negative")
}
if noDefaultRaw, ok := d.GetOk("token_no_default_policy"); ok {
t.TokenNoDefaultPolicy = noDefaultRaw.(bool)
}
if periodRaw, ok := d.GetOk("token_period"); ok {
t.TokenPeriod = time.Duration(periodRaw.(int)) * time.Second
}
if t.TokenPeriod < 0 {
return errors.New("'token_period' cannot be negative")
}
if policiesRaw, ok := d.GetOk("token_policies"); ok {
t.TokenPolicies = policiesRaw.([]string)
}
if tokenTypeRaw, ok := d.GetOk("token_type"); ok {
var tokenType logical.TokenType
tokenTypeStr := tokenTypeRaw.(string)
switch tokenTypeStr {
case "service":
tokenType = logical.TokenTypeService
case "batch":
tokenType = logical.TokenTypeBatch
case "", "default", "default-service":
tokenType = logical.TokenTypeDefaultService
case "default-batch":
tokenType = logical.TokenTypeDefaultBatch
default:
return fmt.Errorf("invalid 'token_type' value %q", tokenTypeStr)
}
t.TokenType = tokenType
}
if ttlRaw, ok := d.GetOk("token_ttl"); ok {
t.TokenTTL = time.Duration(ttlRaw.(int)) * time.Second
}
if t.TokenTTL < 0 {
return errors.New("'token_ttl' cannot be negative")
}
if t.TokenTTL > 0 && t.TokenMaxTTL > 0 && t.TokenTTL > t.TokenMaxTTL {
return errors.New("'token_ttl' cannot be greater than 'token_max_ttl'")
}
if tokenNumUses, ok := d.GetOk("token_num_uses"); ok {
t.TokenNumUses = tokenNumUses.(int)
}
if t.TokenNumUses < 0 {
return errors.New("'token_num_uses' cannot be negative")
}
return nil
}
// PopulateTokenData adds information from TokenParams into the map
func (t *TokenParams) PopulateTokenData(m map[string]interface{}) {
m["token_bound_cidrs"] = t.TokenBoundCIDRs
m["token_explicit_max_ttl"] = t.TokenExplicitMaxTTL.Seconds()
m["token_max_ttl"] = t.TokenMaxTTL.Seconds()
m["token_no_default_policy"] = t.TokenNoDefaultPolicy
m["token_period"] = t.TokenPeriod.Seconds()
m["token_policies"] = t.TokenPolicies
m["token_type"] = t.TokenType.String()
m["token_ttl"] = t.TokenTTL.Seconds()
m["token_num_uses"] = t.TokenNumUses
}
// PopulateTokenAuth populates Auth with parameters
func (t *TokenParams) PopulateTokenAuth(auth *logical.Auth) {
auth.BoundCIDRs = t.TokenBoundCIDRs
auth.ExplicitMaxTTL = t.TokenExplicitMaxTTL
auth.MaxTTL = t.TokenMaxTTL
auth.NoDefaultPolicy = t.TokenNoDefaultPolicy
auth.Period = t.TokenPeriod
auth.Policies = t.TokenPolicies
auth.TokenType = t.TokenType
auth.TTL = t.TokenTTL
auth.NumUses = t.TokenNumUses
}
const (
tokenPeriodHelp = `If set, tokens created via this role
will have no max lifetime; instead, their
renewal period will be fixed to this value.
This takes an integer number of seconds,
or a string duration (e.g. "24h").`
tokenExplicitMaxTTLHelp = `If set, tokens created via this role
carry an explicit maximum TTL. During renewal,
the current maximum TTL values of the role
and the mount are not checked for changes,
and any updates to these values will have
no effect on the token being renewed.`
)

View file

@ -38,6 +38,11 @@ type Auth struct {
// different namespaces indexed by respective namespace identifiers
ExternalNamespacePolicies map[string][]string `json:"external_namespace_policies" mapstructure:"external_namespace_policies" structs:"external_namespace_policies"`
// Indicates that the default policy should not be added by core when
// creating a token. The default policy will still be added if it's
// explicitly defined.
NoDefaultPolicy bool `json:"no_default_policy" mapstructure:"no_default_policy" structs:"no_default_policy"`
// Metadata is used to attach arbitrary string-type metadata to
// an authenticated user. This metadata will be outputted into the
// audit log.

View file

@ -72,6 +72,7 @@ type SystemView interface {
type ExtendedSystemView interface {
Auditor() Auditor
ForwardGenericRequest(context.Context, *Request) (*Response, error)
}
type StaticSystemView struct {
@ -104,6 +105,10 @@ func (d StaticSystemView) Auditor() Auditor {
return noopAuditor{}
}
func (d StaticSystemView) ForwardGenericRequest(ctx context.Context, req *Request) (*Response, error) {
return nil, errors.New("ForwardGenericRequest is not implemented in StaticSystemView")
}
func (d StaticSystemView) DefaultLeaseTTL() time.Duration {
return d.DefaultLeaseTTLVal
}

View file

@ -526,7 +526,9 @@ type Auth struct {
// TTL is a hard limit and cannot be exceeded, also counts for periodic tokens.
ExplicitMaxTTL int64 `sentinel:"" protobuf:"varint,16,opt,name=explicit_max_ttl,json=explicitMaxTtl,proto3" json:"explicit_max_ttl,omitempty"`
// TokenType is the type of token being requested
TokenType uint32 `sentinel:"" protobuf:"varint,17,opt,name=token_type,json=tokenType,proto3" json:"token_type,omitempty"`
TokenType uint32 `sentinel:"" protobuf:"varint,17,opt,name=token_type,json=tokenType,proto3" json:"token_type,omitempty"`
// Whether the default policy should be added automatically by core
NoDefaultPolicy bool `sentinel:"" protobuf:"varint,18,opt,name=no_default_policy,json=noDefaultPolicy,proto3" json:"no_default_policy,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -676,6 +678,13 @@ func (m *Auth) GetTokenType() uint32 {
return 0
}
func (m *Auth) GetNoDefaultPolicy() bool {
if m != nil {
return m.NoDefaultPolicy
}
return false
}
type TokenEntry struct {
ID string `sentinel:"" protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Accessor string `sentinel:"" protobuf:"bytes,2,opt,name=accessor,proto3" json:"accessor,omitempty"`
@ -2713,164 +2722,165 @@ func init() {
func init() { proto.RegisterFile("sdk/plugin/pb/backend.proto", fileDescriptor_4dbf1dfe0c11846b) }
var fileDescriptor_4dbf1dfe0c11846b = []byte{
// 2499 bytes of a gzipped FileDescriptorProto
// 2519 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0xdb, 0x72, 0x1b, 0xc7,
0xd1, 0x2e, 0x00, 0xc4, 0xa9, 0x71, 0x22, 0x46, 0xb4, 0xfe, 0x15, 0x24, 0xff, 0x82, 0xd7, 0x91,
0x0c, 0x2b, 0x36, 0x68, 0x51, 0x71, 0x2c, 0x27, 0x65, 0xa7, 0x68, 0x8a, 0x96, 0x19, 0x93, 0x36,
0x6b, 0x09, 0xc5, 0x39, 0x55, 0xc1, 0x83, 0xdd, 0x21, 0xb8, 0xc5, 0xc5, 0xee, 0x66, 0x76, 0x96,
0x22, 0xae, 0xf2, 0x16, 0x79, 0x8d, 0xdc, 0xa6, 0x72, 0x93, 0xbb, 0x94, 0x2b, 0xf7, 0x79, 0x8d,
0x3c, 0x43, 0x6a, 0x7a, 0x66, 0x4f, 0x00, 0x68, 0xc9, 0x55, 0xce, 0xdd, 0x4c, 0x77, 0xcf, 0xa9,
0xe7, 0xeb, 0xaf, 0x7b, 0x76, 0xe1, 0x6e, 0xe4, 0x5c, 0xee, 0x86, 0x5e, 0x3c, 0x77, 0xfd, 0xdd,
0x70, 0xb6, 0x3b, 0xa3, 0xf6, 0x25, 0xf3, 0x9d, 0x71, 0xc8, 0x03, 0x11, 0x90, 0x72, 0x38, 0x1b,
0xdc, 0x9f, 0x07, 0xc1, 0xdc, 0x63, 0xbb, 0x28, 0x99, 0xc5, 0xe7, 0xbb, 0xc2, 0x5d, 0xb0, 0x48,
0xd0, 0x45, 0xa8, 0x8c, 0x06, 0x03, 0x39, 0x83, 0x17, 0xcc, 0x5d, 0x9b, 0x7a, 0xbb, 0xae, 0xc3,
0x7c, 0xe1, 0x8a, 0xa5, 0xd6, 0x19, 0x79, 0x9d, 0x5a, 0x45, 0x69, 0xcc, 0x3a, 0x54, 0x0f, 0x17,
0xa1, 0x58, 0x9a, 0x43, 0xa8, 0x7d, 0xc1, 0xa8, 0xc3, 0x38, 0xb9, 0x0d, 0xb5, 0x0b, 0x6c, 0x19,
0xa5, 0x61, 0x65, 0xd4, 0xb4, 0x74, 0xcf, 0xfc, 0x03, 0xc0, 0xa9, 0x1c, 0x73, 0xc8, 0x79, 0xc0,
0xc9, 0x1d, 0x68, 0x30, 0xce, 0xa7, 0x62, 0x19, 0x32, 0xa3, 0x34, 0x2c, 0x8d, 0x3a, 0x56, 0x9d,
0x71, 0x3e, 0x59, 0x86, 0x8c, 0xfc, 0x1f, 0xc8, 0xe6, 0x74, 0x11, 0xcd, 0x8d, 0xf2, 0xb0, 0x24,
0x67, 0x60, 0x9c, 0x9f, 0x44, 0xf3, 0x64, 0x8c, 0x1d, 0x38, 0xcc, 0xa8, 0x0c, 0x4b, 0xa3, 0x0a,
0x8e, 0x39, 0x08, 0x1c, 0x66, 0xfe, 0xa5, 0x04, 0xd5, 0x53, 0x2a, 0x2e, 0x22, 0x42, 0x60, 0x8b,
0x07, 0x81, 0xd0, 0x8b, 0x63, 0x9b, 0x8c, 0xa0, 0x17, 0xfb, 0x34, 0x16, 0x17, 0xf2, 0x54, 0x36,
0x15, 0xcc, 0x31, 0xca, 0xa8, 0x5e, 0x15, 0x93, 0xb7, 0xa1, 0xe3, 0x05, 0x36, 0xf5, 0xa6, 0x91,
0x08, 0x38, 0x9d, 0xcb, 0x75, 0xa4, 0x5d, 0x1b, 0x85, 0x67, 0x4a, 0x46, 0x1e, 0x41, 0x3f, 0x62,
0xd4, 0x9b, 0xbe, 0xe4, 0x34, 0x4c, 0x0d, 0xb7, 0xd4, 0x84, 0x52, 0xf1, 0x0d, 0xa7, 0xa1, 0xb6,
0x35, 0xff, 0x51, 0x83, 0xba, 0xc5, 0xfe, 0x14, 0xb3, 0x48, 0x90, 0x2e, 0x94, 0x5d, 0x07, 0x4f,
0xdb, 0xb4, 0xca, 0xae, 0x43, 0xc6, 0x40, 0x2c, 0x16, 0x7a, 0x72, 0x69, 0x37, 0xf0, 0x0f, 0xbc,
0x38, 0x12, 0x8c, 0xeb, 0x33, 0x6f, 0xd0, 0x90, 0x7b, 0xd0, 0x0c, 0x42, 0xc6, 0x51, 0x86, 0x0e,
0x68, 0x5a, 0x99, 0x40, 0x1e, 0x3c, 0xa4, 0xe2, 0xc2, 0xd8, 0x42, 0x05, 0xb6, 0xa5, 0xcc, 0xa1,
0x82, 0x1a, 0x55, 0x25, 0x93, 0x6d, 0x62, 0x42, 0x2d, 0x62, 0x36, 0x67, 0xc2, 0xa8, 0x0d, 0x4b,
0xa3, 0xd6, 0x1e, 0x8c, 0xc3, 0xd9, 0xf8, 0x0c, 0x25, 0x96, 0xd6, 0x90, 0x7b, 0xb0, 0x25, 0xfd,
0x62, 0xd4, 0xd1, 0xa2, 0x21, 0x2d, 0xf6, 0x63, 0x71, 0x61, 0xa1, 0x94, 0xec, 0x41, 0x5d, 0xdd,
0x69, 0x64, 0x34, 0x86, 0x95, 0x51, 0x6b, 0xcf, 0x90, 0x06, 0xfa, 0x94, 0x63, 0x05, 0x83, 0xe8,
0xd0, 0x17, 0x7c, 0x69, 0x25, 0x86, 0xe4, 0x2d, 0x68, 0xdb, 0x9e, 0xcb, 0x7c, 0x31, 0x15, 0xc1,
0x25, 0xf3, 0x8d, 0x26, 0xee, 0xa8, 0xa5, 0x64, 0x13, 0x29, 0x22, 0x7b, 0xf0, 0x46, 0xde, 0x64,
0x4a, 0x6d, 0x9b, 0x45, 0x51, 0xc0, 0x0d, 0x40, 0xdb, 0x5b, 0x39, 0xdb, 0x7d, 0xad, 0x92, 0xd3,
0x3a, 0x6e, 0x14, 0x7a, 0x74, 0x39, 0xf5, 0xe9, 0x82, 0x19, 0x2d, 0x35, 0xad, 0x96, 0x7d, 0x45,
0x17, 0x8c, 0xdc, 0x87, 0xd6, 0x22, 0x88, 0x7d, 0x31, 0x0d, 0x03, 0xd7, 0x17, 0x46, 0x1b, 0x2d,
0x00, 0x45, 0xa7, 0x52, 0x42, 0xde, 0x04, 0xd5, 0x53, 0x60, 0xec, 0x28, 0xbf, 0xa2, 0x04, 0xe1,
0xf8, 0x00, 0xba, 0x4a, 0x9d, 0xee, 0xa7, 0x8b, 0x26, 0x1d, 0x94, 0xa6, 0x3b, 0xf9, 0x00, 0x9a,
0x88, 0x07, 0xd7, 0x3f, 0x0f, 0x8c, 0x1e, 0xfa, 0xed, 0x56, 0xce, 0x2d, 0x12, 0x13, 0x47, 0xfe,
0x79, 0x60, 0x35, 0x5e, 0xea, 0x16, 0xf9, 0x04, 0xee, 0x16, 0xce, 0xcb, 0xd9, 0x82, 0xba, 0xbe,
0xeb, 0xcf, 0xa7, 0x71, 0xc4, 0x22, 0x63, 0x1b, 0x11, 0x6e, 0xe4, 0x4e, 0x6d, 0x25, 0x06, 0x2f,
0x22, 0x16, 0x91, 0xbb, 0xd0, 0x54, 0x41, 0x3a, 0x75, 0x1d, 0xa3, 0x8f, 0x5b, 0x6a, 0x28, 0xc1,
0x91, 0x43, 0xde, 0x81, 0x5e, 0x18, 0x78, 0xae, 0xbd, 0x9c, 0x06, 0x57, 0x8c, 0x73, 0xd7, 0x61,
0x06, 0x19, 0x96, 0x46, 0x0d, 0xab, 0xab, 0xc4, 0x5f, 0x6b, 0xe9, 0xa6, 0xd0, 0xb8, 0x85, 0x86,
0x6b, 0xa1, 0x31, 0x06, 0xb0, 0x03, 0xdf, 0x67, 0x36, 0xc2, 0x6f, 0x07, 0x4f, 0xd8, 0x95, 0x27,
0x3c, 0x48, 0xa5, 0x56, 0xce, 0x62, 0xf0, 0x39, 0xb4, 0xf3, 0x50, 0x20, 0xdb, 0x50, 0xb9, 0x64,
0x4b, 0x0d, 0x7f, 0xd9, 0x24, 0x43, 0xa8, 0x5e, 0x51, 0x2f, 0x66, 0x08, 0x79, 0x0d, 0x44, 0x35,
0xc4, 0x52, 0x8a, 0x5f, 0x94, 0x9f, 0x96, 0xcc, 0xbf, 0x57, 0x61, 0x4b, 0x82, 0x8f, 0x7c, 0x08,
0x1d, 0x8f, 0xd1, 0x88, 0x4d, 0x83, 0x50, 0x2e, 0x10, 0xe1, 0x54, 0xad, 0xbd, 0x6d, 0x39, 0xec,
0x58, 0x2a, 0xbe, 0x56, 0x72, 0xab, 0xed, 0xe5, 0x7a, 0x32, 0xa4, 0x5d, 0x5f, 0x30, 0xee, 0x53,
0x6f, 0x8a, 0xc1, 0xa0, 0x02, 0xac, 0x9d, 0x08, 0x9f, 0xc9, 0xa0, 0x58, 0xc5, 0x51, 0x65, 0x1d,
0x47, 0x03, 0x68, 0xa0, 0xef, 0x5c, 0x16, 0xe9, 0x60, 0x4f, 0xfb, 0x64, 0x0f, 0x1a, 0x0b, 0x26,
0xa8, 0x8e, 0x35, 0x19, 0x12, 0xb7, 0x93, 0x98, 0x19, 0x9f, 0x68, 0x85, 0x0a, 0x88, 0xd4, 0x6e,
0x2d, 0x22, 0x6a, 0xeb, 0x11, 0x31, 0x80, 0x46, 0x0a, 0xba, 0xba, 0xba, 0xe1, 0xa4, 0x2f, 0x69,
0x36, 0x64, 0xdc, 0x0d, 0x1c, 0xa3, 0x81, 0x40, 0xd1, 0x3d, 0x49, 0x92, 0x7e, 0xbc, 0x50, 0x10,
0x6a, 0x2a, 0x92, 0xf4, 0xe3, 0xc5, 0x3a, 0x62, 0x60, 0x05, 0x31, 0x3f, 0x81, 0x2a, 0xf5, 0x5c,
0x1a, 0x61, 0x08, 0xc9, 0x9b, 0xd5, 0x7c, 0x3f, 0xde, 0x97, 0x52, 0x4b, 0x29, 0xc9, 0x13, 0xe8,
0xcc, 0x79, 0x10, 0x87, 0x53, 0xec, 0xb2, 0xc8, 0x68, 0xe3, 0x69, 0x57, 0xad, 0xdb, 0x68, 0xb4,
0xaf, 0x6c, 0x64, 0x04, 0xce, 0x82, 0xd8, 0x77, 0xa6, 0xb6, 0xeb, 0xf0, 0xc8, 0xe8, 0xa0, 0xf3,
0x00, 0x45, 0x07, 0x52, 0x22, 0x43, 0x4c, 0x85, 0x40, 0xea, 0xe0, 0x2e, 0xda, 0x74, 0x50, 0x7a,
0x9a, 0x78, 0xf9, 0xa7, 0xd0, 0x4f, 0x12, 0x53, 0x66, 0xd9, 0x43, 0xcb, 0xed, 0x44, 0x91, 0x1a,
0x8f, 0x60, 0x9b, 0x5d, 0x4b, 0x0a, 0x75, 0xc5, 0x74, 0x41, 0xaf, 0xa7, 0x42, 0x78, 0x3a, 0xa4,
0xba, 0x89, 0xfc, 0x84, 0x5e, 0x4f, 0x84, 0x27, 0xe3, 0x5f, 0xad, 0x8e, 0xf1, 0xdf, 0xc7, 0x64,
0xd4, 0x44, 0x89, 0x8c, 0xff, 0xc1, 0x2f, 0xa1, 0x53, 0xb8, 0xc2, 0x0d, 0x40, 0xde, 0xc9, 0x03,
0xb9, 0x99, 0x07, 0xef, 0xbf, 0xb6, 0x00, 0xf0, 0x2e, 0xd5, 0xd0, 0xd5, 0x0c, 0x90, 0xbf, 0xe0,
0xf2, 0x86, 0x0b, 0xa6, 0x9c, 0xf9, 0x42, 0x83, 0x51, 0xf7, 0xbe, 0x17, 0x87, 0x49, 0x0e, 0xa8,
0xe6, 0x72, 0xc0, 0x7b, 0xb0, 0x25, 0x31, 0x67, 0xd4, 0x32, 0xaa, 0xce, 0x76, 0x84, 0xe8, 0x54,
0xc8, 0x44, 0xab, 0xb5, 0x40, 0xa8, 0xaf, 0x07, 0x42, 0x1e, 0x61, 0x8d, 0x22, 0xc2, 0xde, 0x86,
0x8e, 0xcd, 0x19, 0xe6, 0xa3, 0xa9, 0x2c, 0x30, 0x34, 0x02, 0xdb, 0x89, 0x70, 0xe2, 0x2e, 0x98,
0xf4, 0x9f, 0xbc, 0x0c, 0x40, 0x95, 0x6c, 0x6e, 0xbc, 0xab, 0xd6, 0xc6, 0xbb, 0xc2, 0xec, 0xee,
0x31, 0xcd, 0xe2, 0xd8, 0xce, 0x45, 0x42, 0xa7, 0x10, 0x09, 0x05, 0xb8, 0x77, 0x57, 0xe0, 0xbe,
0x82, 0xc9, 0xde, 0x1a, 0x26, 0xdf, 0x82, 0xb6, 0x74, 0x40, 0x14, 0x52, 0x9b, 0xc9, 0x09, 0xb6,
0x95, 0x23, 0x52, 0xd9, 0x91, 0x83, 0x11, 0x1c, 0xcf, 0x66, 0xcb, 0x8b, 0xc0, 0x63, 0x19, 0x09,
0xb7, 0x52, 0xd9, 0x91, 0x23, 0xf7, 0x8b, 0xa8, 0x22, 0x88, 0x2a, 0x6c, 0x0f, 0x3e, 0x82, 0x66,
0xea, 0xf5, 0x1f, 0x04, 0xa6, 0xbf, 0x96, 0xa0, 0x9d, 0x27, 0x3a, 0x39, 0x78, 0x32, 0x39, 0xc6,
0xc1, 0x15, 0x4b, 0x36, 0x65, 0x89, 0xc0, 0x99, 0xcf, 0x5e, 0xd2, 0x99, 0xa7, 0x26, 0x68, 0x58,
0x99, 0x40, 0x6a, 0x5d, 0xdf, 0xe6, 0x6c, 0x91, 0xa0, 0xaa, 0x62, 0x65, 0x02, 0xf2, 0x31, 0x80,
0x1b, 0x45, 0x31, 0x53, 0x37, 0xb7, 0x85, 0x34, 0x30, 0x18, 0xab, 0xba, 0x71, 0x9c, 0xd4, 0x8d,
0xe3, 0x49, 0x52, 0x37, 0x5a, 0x4d, 0xb4, 0xc6, 0x2b, 0xbd, 0x0d, 0x35, 0x79, 0x41, 0x93, 0x63,
0x44, 0x5e, 0xc5, 0xd2, 0x3d, 0xf3, 0xcf, 0x50, 0x53, 0x95, 0xc5, 0xff, 0x94, 0xbc, 0xef, 0x40,
0x43, 0xcd, 0xed, 0x3a, 0x3a, 0x56, 0xea, 0xd8, 0x3f, 0x72, 0xcc, 0xef, 0xca, 0xd0, 0xb0, 0x58,
0x14, 0x06, 0x7e, 0xc4, 0x72, 0x95, 0x4f, 0xe9, 0x95, 0x95, 0x4f, 0x79, 0x63, 0xe5, 0x93, 0xd4,
0x53, 0x95, 0x5c, 0x3d, 0x35, 0x80, 0x06, 0x67, 0x8e, 0xcb, 0x99, 0x2d, 0x74, 0xed, 0x95, 0xf6,
0xa5, 0xee, 0x25, 0xe5, 0x32, 0x65, 0x47, 0x98, 0x17, 0x9a, 0x56, 0xda, 0x27, 0x8f, 0xf3, 0x05,
0x83, 0x2a, 0xc5, 0x76, 0x54, 0xc1, 0xa0, 0xb6, 0xbb, 0xa1, 0x62, 0x78, 0x92, 0x15, 0x5e, 0x75,
0x8c, 0xe6, 0x3b, 0xf9, 0x01, 0x9b, 0x2b, 0xaf, 0x1f, 0x2d, 0x0f, 0x7f, 0x57, 0x86, 0xed, 0xd5,
0xbd, 0x6d, 0x40, 0xe0, 0x0e, 0x54, 0x55, 0x3e, 0xd3, 0xf0, 0x15, 0x6b, 0x99, 0xac, 0xb2, 0x42,
0x74, 0xbf, 0x5a, 0x25, 0x8d, 0x57, 0x43, 0xaf, 0x48, 0x28, 0xef, 0xc2, 0xb6, 0x74, 0x51, 0xc8,
0x9c, 0xac, 0x46, 0x53, 0x0c, 0xd8, 0xd3, 0xf2, 0xb4, 0x4a, 0x7b, 0x04, 0xfd, 0xc4, 0x34, 0xe3,
0x86, 0x5a, 0xc1, 0xf6, 0x30, 0xa1, 0x88, 0xdb, 0x50, 0x3b, 0x0f, 0xf8, 0x82, 0x0a, 0x4d, 0x82,
0xba, 0x57, 0x20, 0x39, 0x64, 0xdb, 0x86, 0xc2, 0x64, 0x22, 0x94, 0xef, 0x10, 0x49, 0x3e, 0xe9,
0x1b, 0x01, 0x59, 0xb0, 0x61, 0x35, 0x92, 0xb7, 0x81, 0xf9, 0x5b, 0xe8, 0xad, 0x94, 0x85, 0x1b,
0x1c, 0x99, 0x2d, 0x5f, 0x2e, 0x2c, 0x5f, 0x98, 0xb9, 0xb2, 0x32, 0xf3, 0xef, 0xa0, 0xff, 0x05,
0xf5, 0x1d, 0x8f, 0xe9, 0xf9, 0xf7, 0xf9, 0x3c, 0x92, 0x09, 0x4e, 0xbf, 0x52, 0xa6, 0x3a, 0xfb,
0x74, 0xac, 0xa6, 0x96, 0x1c, 0x39, 0xe4, 0x01, 0xd4, 0xb9, 0xb2, 0xd6, 0x00, 0x68, 0xe5, 0xea,
0x56, 0x2b, 0xd1, 0x99, 0xdf, 0x02, 0x29, 0x4c, 0x2d, 0x1f, 0x28, 0x4b, 0x32, 0x92, 0xe8, 0x57,
0xa0, 0xd0, 0x51, 0xd5, 0xce, 0x63, 0xd2, 0x4a, 0xb5, 0x64, 0x08, 0x15, 0xc6, 0xb9, 0x5e, 0x02,
0x0b, 0xc7, 0xec, 0x39, 0x68, 0x49, 0x95, 0xf9, 0x33, 0xe8, 0x9f, 0x85, 0xcc, 0x76, 0xa9, 0x87,
0x4f, 0x39, 0xb5, 0xc0, 0x7d, 0xa8, 0x4a, 0x27, 0x27, 0x84, 0xd1, 0xc4, 0x81, 0xa8, 0x56, 0x72,
0xf3, 0x5b, 0x30, 0xd4, 0xbe, 0x0e, 0xaf, 0xdd, 0x48, 0x30, 0xdf, 0x66, 0x07, 0x17, 0xcc, 0xbe,
0xfc, 0x11, 0x4f, 0x7e, 0x05, 0x77, 0x36, 0xad, 0x90, 0xec, 0xaf, 0x65, 0xcb, 0xde, 0xf4, 0x5c,
0xe6, 0x0e, 0x5c, 0xa3, 0x61, 0x01, 0x8a, 0x3e, 0x97, 0x12, 0x79, 0x8f, 0x4c, 0x8e, 0x8b, 0x34,
0x1f, 0xeb, 0x5e, 0xe2, 0x8f, 0xca, 0xcd, 0xfe, 0xf8, 0x5b, 0x09, 0x9a, 0x67, 0x4c, 0xc4, 0x21,
0x9e, 0xe5, 0x2e, 0x34, 0x67, 0x3c, 0xb8, 0x64, 0x3c, 0x3b, 0x4a, 0x43, 0x09, 0x8e, 0x1c, 0xf2,
0x18, 0x6a, 0x07, 0x81, 0x7f, 0xee, 0xce, 0xf1, 0x61, 0xab, 0x89, 0x21, 0x1d, 0x3b, 0x56, 0x3a,
0x45, 0x0c, 0xda, 0x90, 0x0c, 0xa1, 0xa5, 0x3f, 0x13, 0xbc, 0x78, 0x71, 0xf4, 0x2c, 0xa9, 0x78,
0x73, 0xa2, 0xc1, 0xc7, 0xd0, 0xca, 0x0d, 0xfc, 0x41, 0xa9, 0xea, 0xff, 0x01, 0x70, 0x75, 0xe5,
0xa3, 0x6d, 0x75, 0x54, 0x3d, 0x52, 0x1e, 0xed, 0x3e, 0x34, 0x65, 0x71, 0xa5, 0xd4, 0x49, 0x92,
0x2c, 0x65, 0x49, 0xd2, 0x7c, 0x00, 0xfd, 0x23, 0xff, 0x8a, 0x7a, 0xae, 0x43, 0x05, 0xfb, 0x92,
0x2d, 0xd1, 0x05, 0x6b, 0x3b, 0x30, 0xcf, 0xa0, 0xad, 0x5f, 0xda, 0xaf, 0xb5, 0xc7, 0xb6, 0xde,
0xe3, 0xf7, 0x07, 0xd1, 0xbb, 0xd0, 0xd3, 0x93, 0x1e, 0xbb, 0x3a, 0x84, 0x64, 0x8d, 0xc1, 0xd9,
0xb9, 0x7b, 0xad, 0xa7, 0xd6, 0x3d, 0xf3, 0x29, 0x6c, 0xe7, 0x4c, 0xd3, 0xe3, 0x5c, 0xb2, 0x65,
0x94, 0x7c, 0x81, 0x90, 0xed, 0xc4, 0x03, 0xe5, 0xcc, 0x03, 0x26, 0x74, 0xf5, 0xc8, 0xe7, 0x4c,
0xdc, 0x70, 0xba, 0x2f, 0xd3, 0x8d, 0x3c, 0x67, 0x7a, 0xf2, 0x87, 0x50, 0x65, 0xf2, 0xa4, 0xf9,
0xfc, 0x99, 0xf7, 0x80, 0xa5, 0xd4, 0x1b, 0x16, 0x7c, 0x9a, 0x2e, 0x78, 0x1a, 0xab, 0x05, 0x5f,
0x73, 0x2e, 0xf3, 0xed, 0x74, 0x1b, 0xa7, 0xb1, 0xb8, 0xe9, 0x46, 0x1f, 0x40, 0x5f, 0x1b, 0x3d,
0x63, 0x1e, 0x13, 0xec, 0x86, 0x23, 0x3d, 0x04, 0x52, 0x30, 0xbb, 0x69, 0xba, 0x7b, 0xd0, 0x98,
0x4c, 0x8e, 0x53, 0x6d, 0x91, 0x1b, 0xcd, 0x4f, 0xa0, 0x7f, 0x16, 0x3b, 0xc1, 0x29, 0x77, 0xaf,
0x5c, 0x8f, 0xcd, 0xd5, 0x62, 0x49, 0xf1, 0x5b, 0xca, 0x15, 0xbf, 0x1b, 0xb3, 0x91, 0x39, 0x02,
0x52, 0x18, 0x9e, 0xde, 0x5b, 0x14, 0x3b, 0x81, 0x0e, 0x61, 0x6c, 0x9b, 0x23, 0x68, 0x4f, 0xa8,
0x2c, 0x36, 0x1c, 0x65, 0x63, 0x40, 0x5d, 0xa8, 0xbe, 0x36, 0x4b, 0xba, 0xe6, 0x1e, 0xec, 0x1c,
0x50, 0xfb, 0xc2, 0xf5, 0xe7, 0xcf, 0xdc, 0x48, 0x56, 0x5b, 0x7a, 0xc4, 0x00, 0x1a, 0x8e, 0x16,
0xe8, 0x21, 0x69, 0xdf, 0x7c, 0x1f, 0xde, 0xc8, 0x7d, 0xe6, 0x39, 0x13, 0x34, 0xf1, 0xc7, 0x0e,
0x54, 0x23, 0xd9, 0xc3, 0x11, 0x55, 0x4b, 0x75, 0xcc, 0xaf, 0x60, 0x27, 0x9f, 0x80, 0x65, 0xed,
0x93, 0x1c, 0x1c, 0xab, 0x92, 0x52, 0xae, 0x2a, 0xd1, 0x3e, 0x2b, 0x67, 0xf9, 0x64, 0x1b, 0x2a,
0xbf, 0xfe, 0x66, 0xa2, 0xc1, 0x2e, 0x9b, 0xe6, 0x1f, 0xe5, 0xf2, 0xc5, 0xf9, 0xd4, 0xf2, 0x85,
0xd2, 0xa4, 0xf4, 0x5a, 0xa5, 0xc9, 0x3a, 0xde, 0xde, 0x87, 0xfe, 0x89, 0x17, 0xd8, 0x97, 0x87,
0x7e, 0xce, 0x1b, 0x06, 0xd4, 0x99, 0x9f, 0x77, 0x46, 0xd2, 0x35, 0xdf, 0x81, 0xde, 0x71, 0x60,
0x53, 0xef, 0x24, 0x88, 0x7d, 0x91, 0x7a, 0x01, 0xbf, 0xbb, 0x69, 0x53, 0xd5, 0x31, 0xdf, 0x87,
0xae, 0x4e, 0xd1, 0xfe, 0x79, 0x90, 0x30, 0x63, 0x96, 0xcc, 0x4b, 0xc5, 0x42, 0xdf, 0x3c, 0x86,
0x5e, 0x66, 0xae, 0xe6, 0x7d, 0x07, 0x6a, 0x4a, 0xad, 0xcf, 0xd6, 0x4b, 0x5f, 0xaf, 0xca, 0xd2,
0xd2, 0xea, 0x0d, 0x87, 0x5a, 0x40, 0xf7, 0x14, 0xbf, 0x7f, 0x1e, 0xfa, 0x57, 0x6a, 0xb2, 0x23,
0x20, 0xea, 0x8b, 0xe8, 0x94, 0xf9, 0x57, 0x2e, 0x0f, 0x7c, 0x2c, 0xae, 0x4b, 0xba, 0x84, 0x49,
0x26, 0x4e, 0x07, 0x25, 0x16, 0x56, 0x3f, 0x5c, 0x15, 0x6d, 0xf4, 0x21, 0x64, 0x5f, 0x57, 0x64,
0xaa, 0xe1, 0x6c, 0x11, 0x08, 0x36, 0xa5, 0x8e, 0x93, 0x44, 0x0b, 0x28, 0xd1, 0xbe, 0xe3, 0xf0,
0xbd, 0xff, 0x94, 0xa1, 0xfe, 0x99, 0x22, 0x70, 0xf2, 0x29, 0x74, 0x0a, 0xe9, 0x9a, 0xbc, 0x81,
0x65, 0xdd, 0x6a, 0x71, 0x30, 0xb8, 0xbd, 0x26, 0x56, 0xe7, 0xfa, 0x00, 0xda, 0xf9, 0x64, 0x4c,
0x30, 0xf1, 0xe2, 0xb7, 0xde, 0x01, 0xce, 0xb4, 0x9e, 0xa9, 0xcf, 0x60, 0x67, 0x53, 0x9a, 0x24,
0xf7, 0xb2, 0x15, 0xd6, 0x53, 0xf4, 0xe0, 0xcd, 0x9b, 0xb4, 0x49, 0x7a, 0xad, 0x1f, 0x78, 0x8c,
0xfa, 0x71, 0x98, 0xdf, 0x41, 0xd6, 0x24, 0x8f, 0xa1, 0x53, 0x48, 0x14, 0xea, 0x9c, 0x6b, 0xb9,
0x23, 0x3f, 0xe4, 0x21, 0x54, 0x31, 0x39, 0x91, 0x4e, 0x21, 0x4b, 0x0e, 0xba, 0x69, 0x57, 0xad,
0x3d, 0x84, 0x2d, 0xfc, 0x02, 0x98, 0x5b, 0x18, 0x47, 0xa4, 0x99, 0x6b, 0xef, 0xdf, 0x25, 0xa8,
0x27, 0x5f, 0x85, 0x1f, 0xc3, 0x96, 0xcc, 0x01, 0xe4, 0x56, 0x8e, 0x46, 0x93, 0xfc, 0x31, 0xd8,
0x59, 0x11, 0xaa, 0x05, 0xc6, 0x50, 0x79, 0xce, 0x04, 0x21, 0x39, 0xa5, 0x4e, 0x06, 0x83, 0x5b,
0x45, 0x59, 0x6a, 0x7f, 0x1a, 0x17, 0xed, 0x35, 0x97, 0x17, 0xec, 0x53, 0x96, 0xfe, 0x08, 0x6a,
0x8a, 0x65, 0x95, 0x53, 0xd6, 0xf8, 0x59, 0x5d, 0xfe, 0x3a, 0x1f, 0xef, 0xfd, 0x73, 0x0b, 0xe0,
0x6c, 0x19, 0x09, 0xb6, 0xf8, 0x8d, 0xcb, 0x5e, 0x92, 0x47, 0xd0, 0x7b, 0xc6, 0xce, 0x69, 0xec,
0x09, 0x7c, 0xaa, 0x49, 0x36, 0xc9, 0xf9, 0x04, 0x0b, 0xbe, 0x94, 0xac, 0x1f, 0x42, 0xeb, 0x84,
0x5e, 0xbf, 0xda, 0xee, 0x53, 0xe8, 0x14, 0x38, 0x58, 0x6f, 0x71, 0x95, 0xd5, 0xf5, 0x16, 0xd7,
0xd9, 0xfa, 0x21, 0xd4, 0x35, 0x33, 0xe7, 0xd7, 0xc0, 0x1c, 0x56, 0x60, 0xec, 0x9f, 0x43, 0x6f,
0x85, 0x97, 0xf3, 0xf6, 0xf8, 0x39, 0x64, 0x23, 0x6f, 0x3f, 0x95, 0xaf, 0x9d, 0x22, 0x37, 0xe7,
0x07, 0xea, 0x97, 0xd7, 0x26, 0xf2, 0x7e, 0x5e, 0x7c, 0x27, 0xe1, 0x13, 0xd5, 0x58, 0xa5, 0xcf,
0x84, 0xbc, 0x07, 0x77, 0x36, 0x69, 0xd2, 0x10, 0xcc, 0x33, 0xe8, 0x5a, 0x08, 0xae, 0xd3, 0xeb,
0x7b, 0x00, 0x19, 0x89, 0xe6, 0xed, 0x11, 0x1e, 0xab, 0xfc, 0xfa, 0x21, 0x40, 0x46, 0x8d, 0x0a,
0x55, 0x45, 0x66, 0x55, 0xc3, 0x56, 0xe9, 0xf3, 0x11, 0x34, 0x53, 0x3a, 0xcb, 0xaf, 0x81, 0x13,
0x14, 0xd9, 0xf1, 0xb3, 0x47, 0xbf, 0x1f, 0xcd, 0x5d, 0x71, 0x11, 0xcf, 0xc6, 0x76, 0xb0, 0xd8,
0xbd, 0xa0, 0xd1, 0x85, 0x6b, 0x07, 0x3c, 0xdc, 0xbd, 0x92, 0x60, 0xda, 0x2d, 0xfc, 0xb4, 0x9a,
0xd5, 0xf0, 0xa1, 0xf7, 0xe4, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x5b, 0x0c, 0x01, 0xf3, 0xcc,
0x1a, 0x00, 0x00,
0x0c, 0x33, 0x36, 0x68, 0xd1, 0x71, 0x2c, 0x27, 0x65, 0xa7, 0x68, 0x8a, 0x96, 0x19, 0x93, 0x36,
0x6b, 0x09, 0xc7, 0x39, 0x55, 0xc1, 0x83, 0xdd, 0x21, 0xb8, 0xc5, 0xc5, 0xee, 0x66, 0x76, 0x96,
0x22, 0xae, 0xf2, 0x16, 0x79, 0x8d, 0xdc, 0xe6, 0x2e, 0x77, 0x29, 0x57, 0xee, 0xf3, 0x0a, 0xb9,
0xcc, 0x33, 0xa4, 0xa6, 0x67, 0xf6, 0x04, 0x80, 0x96, 0x5c, 0xe5, 0xdc, 0xcd, 0x74, 0xf7, 0x9c,
0x7a, 0xbe, 0xfe, 0xba, 0x67, 0x17, 0xee, 0x47, 0xce, 0xd5, 0x5e, 0xe8, 0xc5, 0x73, 0xd7, 0xdf,
0x0b, 0x67, 0x7b, 0x33, 0x6a, 0x5f, 0x31, 0xdf, 0x19, 0x87, 0x3c, 0x10, 0x01, 0x29, 0x87, 0xb3,
0xc1, 0xc3, 0x79, 0x10, 0xcc, 0x3d, 0xb6, 0x87, 0x92, 0x59, 0x7c, 0xb1, 0x27, 0xdc, 0x05, 0x8b,
0x04, 0x5d, 0x84, 0xca, 0x68, 0x30, 0x90, 0x33, 0x78, 0xc1, 0xdc, 0xb5, 0xa9, 0xb7, 0xe7, 0x3a,
0xcc, 0x17, 0xae, 0x58, 0x6a, 0x9d, 0x91, 0xd7, 0xa9, 0x55, 0x94, 0xc6, 0xac, 0x43, 0xf5, 0x68,
0x11, 0x8a, 0xa5, 0x39, 0x84, 0xda, 0xe7, 0x8c, 0x3a, 0x8c, 0x93, 0xbb, 0x50, 0xbb, 0xc4, 0x96,
0x51, 0x1a, 0x56, 0x46, 0x4d, 0x4b, 0xf7, 0xcc, 0x3f, 0x00, 0x9c, 0xc9, 0x31, 0x47, 0x9c, 0x07,
0x9c, 0xdc, 0x83, 0x06, 0xe3, 0x7c, 0x2a, 0x96, 0x21, 0x33, 0x4a, 0xc3, 0xd2, 0xa8, 0x63, 0xd5,
0x19, 0xe7, 0x93, 0x65, 0xc8, 0xc8, 0xff, 0x81, 0x6c, 0x4e, 0x17, 0xd1, 0xdc, 0x28, 0x0f, 0x4b,
0x72, 0x06, 0xc6, 0xf9, 0x69, 0x34, 0x4f, 0xc6, 0xd8, 0x81, 0xc3, 0x8c, 0xca, 0xb0, 0x34, 0xaa,
0xe0, 0x98, 0xc3, 0xc0, 0x61, 0xe6, 0x5f, 0x4a, 0x50, 0x3d, 0xa3, 0xe2, 0x32, 0x22, 0x04, 0xb6,
0x78, 0x10, 0x08, 0xbd, 0x38, 0xb6, 0xc9, 0x08, 0x7a, 0xb1, 0x4f, 0x63, 0x71, 0x29, 0x4f, 0x65,
0x53, 0xc1, 0x1c, 0xa3, 0x8c, 0xea, 0x55, 0x31, 0x79, 0x13, 0x3a, 0x5e, 0x60, 0x53, 0x6f, 0x1a,
0x89, 0x80, 0xd3, 0xb9, 0x5c, 0x47, 0xda, 0xb5, 0x51, 0x78, 0xae, 0x64, 0x64, 0x17, 0xfa, 0x11,
0xa3, 0xde, 0xf4, 0x05, 0xa7, 0x61, 0x6a, 0xb8, 0xa5, 0x26, 0x94, 0x8a, 0x6f, 0x38, 0x0d, 0xb5,
0xad, 0xf9, 0xf7, 0x1a, 0xd4, 0x2d, 0xf6, 0xa7, 0x98, 0x45, 0x82, 0x74, 0xa1, 0xec, 0x3a, 0x78,
0xda, 0xa6, 0x55, 0x76, 0x1d, 0x32, 0x06, 0x62, 0xb1, 0xd0, 0x93, 0x4b, 0xbb, 0x81, 0x7f, 0xe8,
0xc5, 0x91, 0x60, 0x5c, 0x9f, 0x79, 0x83, 0x86, 0x3c, 0x80, 0x66, 0x10, 0x32, 0x8e, 0x32, 0x74,
0x40, 0xd3, 0xca, 0x04, 0xf2, 0xe0, 0x21, 0x15, 0x97, 0xc6, 0x16, 0x2a, 0xb0, 0x2d, 0x65, 0x0e,
0x15, 0xd4, 0xa8, 0x2a, 0x99, 0x6c, 0x13, 0x13, 0x6a, 0x11, 0xb3, 0x39, 0x13, 0x46, 0x6d, 0x58,
0x1a, 0xb5, 0xf6, 0x61, 0x1c, 0xce, 0xc6, 0xe7, 0x28, 0xb1, 0xb4, 0x86, 0x3c, 0x80, 0x2d, 0xe9,
0x17, 0xa3, 0x8e, 0x16, 0x0d, 0x69, 0x71, 0x10, 0x8b, 0x4b, 0x0b, 0xa5, 0x64, 0x1f, 0xea, 0xea,
0x4e, 0x23, 0xa3, 0x31, 0xac, 0x8c, 0x5a, 0xfb, 0x86, 0x34, 0xd0, 0xa7, 0x1c, 0x2b, 0x18, 0x44,
0x47, 0xbe, 0xe0, 0x4b, 0x2b, 0x31, 0x24, 0x6f, 0x40, 0xdb, 0xf6, 0x5c, 0xe6, 0x8b, 0xa9, 0x08,
0xae, 0x98, 0x6f, 0x34, 0x71, 0x47, 0x2d, 0x25, 0x9b, 0x48, 0x11, 0xd9, 0x87, 0xd7, 0xf2, 0x26,
0x53, 0x6a, 0xdb, 0x2c, 0x8a, 0x02, 0x6e, 0x00, 0xda, 0xde, 0xc9, 0xd9, 0x1e, 0x68, 0x95, 0x9c,
0xd6, 0x71, 0xa3, 0xd0, 0xa3, 0xcb, 0xa9, 0x4f, 0x17, 0xcc, 0x68, 0xa9, 0x69, 0xb5, 0xec, 0x4b,
0xba, 0x60, 0xe4, 0x21, 0xb4, 0x16, 0x41, 0xec, 0x8b, 0x69, 0x18, 0xb8, 0xbe, 0x30, 0xda, 0x68,
0x01, 0x28, 0x3a, 0x93, 0x12, 0xf2, 0x3a, 0xa8, 0x9e, 0x02, 0x63, 0x47, 0xf9, 0x15, 0x25, 0x08,
0xc7, 0x47, 0xd0, 0x55, 0xea, 0x74, 0x3f, 0x5d, 0x34, 0xe9, 0xa0, 0x34, 0xdd, 0xc9, 0x7b, 0xd0,
0x44, 0x3c, 0xb8, 0xfe, 0x45, 0x60, 0xf4, 0xd0, 0x6f, 0x77, 0x72, 0x6e, 0x91, 0x98, 0x38, 0xf6,
0x2f, 0x02, 0xab, 0xf1, 0x42, 0xb7, 0xc8, 0xc7, 0x70, 0xbf, 0x70, 0x5e, 0xce, 0x16, 0xd4, 0xf5,
0x5d, 0x7f, 0x3e, 0x8d, 0x23, 0x16, 0x19, 0xdb, 0x88, 0x70, 0x23, 0x77, 0x6a, 0x2b, 0x31, 0xf8,
0x3a, 0x62, 0x11, 0xb9, 0x0f, 0x4d, 0x15, 0xa4, 0x53, 0xd7, 0x31, 0xfa, 0xb8, 0xa5, 0x86, 0x12,
0x1c, 0x3b, 0xe4, 0x2d, 0xe8, 0x85, 0x81, 0xe7, 0xda, 0xcb, 0x69, 0x70, 0xcd, 0x38, 0x77, 0x1d,
0x66, 0x90, 0x61, 0x69, 0xd4, 0xb0, 0xba, 0x4a, 0xfc, 0x95, 0x96, 0x6e, 0x0a, 0x8d, 0x3b, 0x68,
0xb8, 0x16, 0x1a, 0x63, 0x00, 0x3b, 0xf0, 0x7d, 0x66, 0x23, 0xfc, 0x76, 0xf0, 0x84, 0x5d, 0x79,
0xc2, 0xc3, 0x54, 0x6a, 0xe5, 0x2c, 0x06, 0x9f, 0x41, 0x3b, 0x0f, 0x05, 0xb2, 0x0d, 0x95, 0x2b,
0xb6, 0xd4, 0xf0, 0x97, 0x4d, 0x32, 0x84, 0xea, 0x35, 0xf5, 0x62, 0x86, 0x90, 0xd7, 0x40, 0x54,
0x43, 0x2c, 0xa5, 0xf8, 0x45, 0xf9, 0x69, 0xc9, 0xfc, 0x77, 0x15, 0xb6, 0x24, 0xf8, 0xc8, 0x07,
0xd0, 0xf1, 0x18, 0x8d, 0xd8, 0x34, 0x08, 0xe5, 0x02, 0x11, 0x4e, 0xd5, 0xda, 0xdf, 0x96, 0xc3,
0x4e, 0xa4, 0xe2, 0x2b, 0x25, 0xb7, 0xda, 0x5e, 0xae, 0x27, 0x43, 0xda, 0xf5, 0x05, 0xe3, 0x3e,
0xf5, 0xa6, 0x18, 0x0c, 0x2a, 0xc0, 0xda, 0x89, 0xf0, 0x99, 0x0c, 0x8a, 0x55, 0x1c, 0x55, 0xd6,
0x71, 0x34, 0x80, 0x06, 0xfa, 0xce, 0x65, 0x91, 0x0e, 0xf6, 0xb4, 0x4f, 0xf6, 0xa1, 0xb1, 0x60,
0x82, 0xea, 0x58, 0x93, 0x21, 0x71, 0x37, 0x89, 0x99, 0xf1, 0xa9, 0x56, 0xa8, 0x80, 0x48, 0xed,
0xd6, 0x22, 0xa2, 0xb6, 0x1e, 0x11, 0x03, 0x68, 0xa4, 0xa0, 0xab, 0xab, 0x1b, 0x4e, 0xfa, 0x92,
0x66, 0x43, 0xc6, 0xdd, 0xc0, 0x31, 0x1a, 0x08, 0x14, 0xdd, 0x93, 0x24, 0xe9, 0xc7, 0x0b, 0x05,
0xa1, 0xa6, 0x22, 0x49, 0x3f, 0x5e, 0xac, 0x23, 0x06, 0x56, 0x10, 0xf3, 0x13, 0xa8, 0x52, 0xcf,
0xa5, 0x11, 0x86, 0x90, 0xbc, 0x59, 0xcd, 0xf7, 0xe3, 0x03, 0x29, 0xb5, 0x94, 0x92, 0xbc, 0x0f,
0x9d, 0x39, 0x0f, 0xe2, 0x70, 0x8a, 0x5d, 0x16, 0x19, 0x6d, 0x3c, 0xed, 0xaa, 0x75, 0x1b, 0x8d,
0x0e, 0x94, 0x8d, 0x8c, 0xc0, 0x59, 0x10, 0xfb, 0xce, 0xd4, 0x76, 0x1d, 0x1e, 0x19, 0x1d, 0x74,
0x1e, 0xa0, 0xe8, 0x50, 0x4a, 0x64, 0x88, 0xa9, 0x10, 0x48, 0x1d, 0xdc, 0x45, 0x9b, 0x0e, 0x4a,
0xcf, 0x12, 0x2f, 0xff, 0x14, 0xfa, 0x49, 0x62, 0xca, 0x2c, 0x7b, 0x68, 0xb9, 0x9d, 0x28, 0x52,
0xe3, 0x11, 0x6c, 0xb3, 0x1b, 0x49, 0xa1, 0xae, 0x98, 0x2e, 0xe8, 0xcd, 0x54, 0x08, 0x4f, 0x87,
0x54, 0x37, 0x91, 0x9f, 0xd2, 0x9b, 0x89, 0xf0, 0x64, 0xfc, 0xab, 0xd5, 0x31, 0xfe, 0xfb, 0x98,
0x8c, 0x9a, 0x28, 0xc1, 0xf8, 0xdf, 0x85, 0xbe, 0x1f, 0x4c, 0x1d, 0x76, 0x41, 0x63, 0x4f, 0xa8,
0x75, 0x97, 0x3a, 0x98, 0x7a, 0x7e, 0xf0, 0x4c, 0xc9, 0x71, 0xd9, 0xe5, 0xe0, 0x97, 0xd0, 0x29,
0x5c, 0xf7, 0x06, 0xd0, 0xef, 0xe4, 0x41, 0xdf, 0xcc, 0x03, 0xfd, 0x9f, 0x5b, 0x00, 0x78, 0xef,
0x6a, 0xe8, 0x6a, 0xb6, 0xc8, 0x83, 0xa1, 0xbc, 0x01, 0x0c, 0x94, 0x33, 0x5f, 0x68, 0xe0, 0xea,
0xde, 0xf7, 0x62, 0x36, 0xc9, 0x17, 0xd5, 0x5c, 0xbe, 0x78, 0x07, 0xb6, 0x24, 0x3e, 0x8d, 0x5a,
0x46, 0xeb, 0xd9, 0x8e, 0x10, 0xc9, 0x0a, 0xc5, 0x68, 0xb5, 0x16, 0x34, 0xf5, 0xf5, 0xa0, 0xc9,
0xa3, 0xb1, 0x51, 0x44, 0xe3, 0x9b, 0xd0, 0xb1, 0x39, 0xc3, 0xdc, 0x35, 0x95, 0xc5, 0x88, 0x46,
0x6b, 0x3b, 0x11, 0x4e, 0xdc, 0x05, 0x93, 0xfe, 0x93, 0x17, 0x07, 0xa8, 0x92, 0xcd, 0x8d, 0xf7,
0xda, 0xda, 0x78, 0xaf, 0x58, 0x09, 0x78, 0x4c, 0x33, 0x3e, 0xb6, 0x73, 0x51, 0xd3, 0x29, 0x44,
0x4d, 0x21, 0x34, 0xba, 0x2b, 0xa1, 0xb1, 0x82, 0xdf, 0xde, 0x1a, 0x7e, 0xdf, 0x80, 0xb6, 0x74,
0x40, 0x14, 0x52, 0x9b, 0xc9, 0x09, 0xb6, 0x95, 0x23, 0x52, 0xd9, 0xb1, 0x83, 0xd1, 0x1e, 0xcf,
0x66, 0xcb, 0xcb, 0xc0, 0x63, 0x19, 0x61, 0xb7, 0x52, 0xd9, 0xb1, 0x23, 0xf7, 0x8b, 0x08, 0x24,
0x88, 0x40, 0x6c, 0x0f, 0x3e, 0x84, 0x66, 0xea, 0xf5, 0x1f, 0x04, 0xa6, 0xbf, 0x96, 0xa0, 0x9d,
0x27, 0x45, 0x39, 0x78, 0x32, 0x39, 0xc1, 0xc1, 0x15, 0x4b, 0x36, 0x65, 0x39, 0xc1, 0x99, 0xcf,
0x5e, 0xd0, 0x99, 0xa7, 0x26, 0x68, 0x58, 0x99, 0x40, 0x6a, 0x5d, 0xdf, 0xe6, 0x6c, 0x91, 0xa0,
0xaa, 0x62, 0x65, 0x02, 0xf2, 0x11, 0x80, 0x1b, 0x45, 0x31, 0x53, 0x37, 0xb7, 0x85, 0x94, 0x31,
0x18, 0xab, 0x1a, 0x73, 0x9c, 0xd4, 0x98, 0xe3, 0x49, 0x52, 0x63, 0x5a, 0x4d, 0xb4, 0xc6, 0x2b,
0xbd, 0x0b, 0x35, 0x79, 0x41, 0x93, 0x13, 0x44, 0x5e, 0xc5, 0xd2, 0x3d, 0xf3, 0xcf, 0x50, 0x53,
0x55, 0xc8, 0xff, 0x94, 0xe8, 0xef, 0x41, 0x43, 0xcd, 0xed, 0x3a, 0x3a, 0x56, 0xea, 0xd8, 0x3f,
0x76, 0xcc, 0xef, 0xca, 0xd0, 0xb0, 0x58, 0x14, 0x06, 0x7e, 0xc4, 0x72, 0x55, 0x52, 0xe9, 0xa5,
0x55, 0x52, 0x79, 0x63, 0x95, 0x94, 0xd4, 0x5e, 0x95, 0x5c, 0xed, 0x35, 0x80, 0x06, 0x67, 0x8e,
0xcb, 0x99, 0x2d, 0x74, 0x9d, 0x96, 0xf6, 0xa5, 0xee, 0x05, 0xe5, 0x32, 0xbd, 0x47, 0x98, 0x43,
0x9a, 0x56, 0xda, 0x27, 0x4f, 0xf2, 0xc5, 0x85, 0x2a, 0xdb, 0x76, 0x54, 0x71, 0xa1, 0xb6, 0xbb,
0xa1, 0xba, 0x78, 0x3f, 0x2b, 0xd2, 0xea, 0x18, 0xcd, 0xf7, 0xf2, 0x03, 0x36, 0x57, 0x69, 0x3f,
0x5a, 0xce, 0xfe, 0xae, 0x0c, 0xdb, 0xab, 0x7b, 0xdb, 0x80, 0xc0, 0x1d, 0xa8, 0xaa, 0xdc, 0xa7,
0xe1, 0x2b, 0xd6, 0xb2, 0x5e, 0x65, 0x85, 0xe8, 0x7e, 0xb5, 0x4a, 0x1a, 0x2f, 0x87, 0x5e, 0x91,
0x50, 0xde, 0x86, 0x6d, 0xe9, 0xa2, 0x90, 0x39, 0x59, 0x3d, 0xa7, 0x18, 0xb0, 0xa7, 0xe5, 0x69,
0x45, 0xb7, 0x0b, 0xfd, 0xc4, 0x34, 0xe3, 0x86, 0x5a, 0xc1, 0xf6, 0x28, 0xa1, 0x88, 0xbb, 0x50,
0xbb, 0x08, 0xf8, 0x82, 0x0a, 0x4d, 0x82, 0xba, 0x57, 0x20, 0x39, 0x64, 0xdb, 0x86, 0xc2, 0x64,
0x22, 0x94, 0x6f, 0x16, 0x49, 0x3e, 0xe9, 0x7b, 0x02, 0x59, 0xb0, 0x61, 0x35, 0x92, 0x77, 0x84,
0xf9, 0x5b, 0xe8, 0xad, 0x94, 0x90, 0x1b, 0x1c, 0x99, 0x2d, 0x5f, 0x2e, 0x2c, 0x5f, 0x98, 0xb9,
0xb2, 0x32, 0xf3, 0xef, 0xa0, 0xff, 0x39, 0xf5, 0x1d, 0x8f, 0xe9, 0xf9, 0x0f, 0xf8, 0x3c, 0x92,
0xc9, 0x50, 0xbf, 0x68, 0xa6, 0x3a, 0xfb, 0x74, 0xac, 0xa6, 0x96, 0x1c, 0x3b, 0xe4, 0x11, 0xd4,
0xb9, 0xb2, 0xd6, 0x00, 0x68, 0xe5, 0x6a, 0x5c, 0x2b, 0xd1, 0x99, 0xdf, 0x02, 0x29, 0x4c, 0x2d,
0x1f, 0x33, 0x4b, 0x32, 0x92, 0xe8, 0x57, 0xa0, 0xd0, 0x51, 0xd5, 0xce, 0x63, 0xd2, 0x4a, 0xb5,
0x64, 0x08, 0x15, 0xc6, 0xb9, 0x5e, 0x02, 0x8b, 0xcc, 0xec, 0xe9, 0x68, 0x49, 0x95, 0xf9, 0x33,
0xe8, 0x9f, 0x87, 0xcc, 0x76, 0xa9, 0x87, 0xcf, 0x3e, 0xb5, 0xc0, 0x43, 0xa8, 0x4a, 0x27, 0x27,
0x84, 0xd1, 0xc4, 0x81, 0xa8, 0x56, 0x72, 0xf3, 0x5b, 0x30, 0xd4, 0xbe, 0x8e, 0x6e, 0xdc, 0x48,
0x30, 0xdf, 0x66, 0x87, 0x97, 0xcc, 0xbe, 0xfa, 0x11, 0x4f, 0x7e, 0x0d, 0xf7, 0x36, 0xad, 0x90,
0xec, 0xaf, 0x65, 0xcb, 0xde, 0xf4, 0x42, 0xe6, 0x0e, 0x5c, 0xa3, 0x61, 0x01, 0x8a, 0x3e, 0x93,
0x12, 0x79, 0x8f, 0x4c, 0x8e, 0x8b, 0x34, 0x1f, 0xeb, 0x5e, 0xe2, 0x8f, 0xca, 0xed, 0xfe, 0xf8,
0x5b, 0x09, 0x9a, 0xe7, 0x4c, 0xc4, 0x21, 0x9e, 0xe5, 0x3e, 0x34, 0x67, 0x3c, 0xb8, 0x62, 0x3c,
0x3b, 0x4a, 0x43, 0x09, 0x8e, 0x1d, 0xf2, 0x04, 0x6a, 0x87, 0x81, 0x7f, 0xe1, 0xce, 0xf1, 0x11,
0xac, 0x89, 0x21, 0x1d, 0x3b, 0x56, 0x3a, 0x45, 0x0c, 0xda, 0x90, 0x0c, 0xa1, 0xa5, 0x3f, 0x29,
0x7c, 0xfd, 0xf5, 0xf1, 0xb3, 0xa4, 0x3a, 0xce, 0x89, 0x06, 0x1f, 0x41, 0x2b, 0x37, 0xf0, 0x07,
0xa5, 0xaa, 0xff, 0x07, 0xc0, 0xd5, 0x95, 0x8f, 0xb6, 0xd5, 0x51, 0xf5, 0x48, 0x79, 0xb4, 0x87,
0xd0, 0x94, 0x85, 0x98, 0x52, 0x27, 0x49, 0xb2, 0x94, 0x25, 0x49, 0xf3, 0x11, 0xf4, 0x8f, 0xfd,
0x6b, 0xea, 0xb9, 0x0e, 0x15, 0xec, 0x0b, 0xb6, 0x44, 0x17, 0xac, 0xed, 0xc0, 0x3c, 0x87, 0xb6,
0x7e, 0x95, 0xbf, 0xd2, 0x1e, 0xdb, 0x7a, 0x8f, 0xdf, 0x1f, 0x44, 0x6f, 0x43, 0x4f, 0x4f, 0x7a,
0xe2, 0xea, 0x10, 0x92, 0x35, 0x06, 0x67, 0x17, 0xee, 0x8d, 0x9e, 0x5a, 0xf7, 0xcc, 0xa7, 0xb0,
0x9d, 0x33, 0x4d, 0x8f, 0x73, 0xc5, 0x96, 0x51, 0xf2, 0xb5, 0x42, 0xb6, 0x13, 0x0f, 0x94, 0x33,
0x0f, 0x98, 0xd0, 0xd5, 0x23, 0x9f, 0x33, 0x71, 0xcb, 0xe9, 0xbe, 0x48, 0x37, 0xf2, 0x9c, 0xe9,
0xc9, 0x1f, 0x43, 0x95, 0xc9, 0x93, 0xe6, 0xf3, 0x67, 0xde, 0x03, 0x96, 0x52, 0x6f, 0x58, 0xf0,
0x69, 0xba, 0xe0, 0x59, 0xac, 0x16, 0x7c, 0xc5, 0xb9, 0xcc, 0x37, 0xd3, 0x6d, 0x9c, 0xc5, 0xe2,
0xb6, 0x1b, 0x7d, 0x04, 0x7d, 0x6d, 0xf4, 0x8c, 0x79, 0x4c, 0xb0, 0x5b, 0x8e, 0xf4, 0x18, 0x48,
0xc1, 0xec, 0xb6, 0xe9, 0x1e, 0x40, 0x63, 0x32, 0x39, 0x49, 0xb5, 0x45, 0x6e, 0x34, 0x3f, 0x86,
0xfe, 0x79, 0xec, 0x04, 0x67, 0xdc, 0xbd, 0x76, 0x3d, 0x36, 0x57, 0x8b, 0x25, 0xc5, 0x6f, 0x29,
0x57, 0xfc, 0x6e, 0xcc, 0x46, 0xe6, 0x08, 0x48, 0x61, 0x78, 0x7a, 0x6f, 0x51, 0xec, 0x04, 0x3a,
0x84, 0xb1, 0x6d, 0x8e, 0xa0, 0x3d, 0xa1, 0xb2, 0xd8, 0x70, 0x94, 0x8d, 0x01, 0x75, 0xa1, 0xfa,
0xda, 0x2c, 0xe9, 0x9a, 0xfb, 0xb0, 0x73, 0x48, 0xed, 0x4b, 0xd7, 0x9f, 0x3f, 0x73, 0x23, 0x59,
0x6d, 0xe9, 0x11, 0x03, 0x68, 0x38, 0x5a, 0xa0, 0x87, 0xa4, 0x7d, 0xf3, 0x5d, 0x78, 0x2d, 0xf7,
0x49, 0xe8, 0x5c, 0xd0, 0xc4, 0x1f, 0x3b, 0x50, 0x8d, 0x64, 0x0f, 0x47, 0x54, 0x2d, 0xd5, 0x31,
0xbf, 0x84, 0x9d, 0x7c, 0x02, 0x96, 0xb5, 0x4f, 0x72, 0x70, 0xac, 0x4a, 0x4a, 0xb9, 0xaa, 0x44,
0xfb, 0xac, 0x9c, 0xe5, 0x93, 0x6d, 0xa8, 0xfc, 0xfa, 0x9b, 0x89, 0x06, 0xbb, 0x6c, 0x9a, 0x7f,
0x94, 0xcb, 0x17, 0xe7, 0x53, 0xcb, 0x17, 0x4a, 0x93, 0xd2, 0x2b, 0x95, 0x26, 0xeb, 0x78, 0x7b,
0x17, 0xfa, 0xa7, 0x5e, 0x60, 0x5f, 0x1d, 0xf9, 0x39, 0x6f, 0x18, 0x50, 0x67, 0x7e, 0xde, 0x19,
0x49, 0xd7, 0x7c, 0x0b, 0x7a, 0x27, 0x81, 0x4d, 0xbd, 0xd3, 0x20, 0xf6, 0x45, 0xea, 0x05, 0xfc,
0x46, 0xa7, 0x4d, 0x55, 0xc7, 0x7c, 0x17, 0xba, 0x3a, 0x45, 0xfb, 0x17, 0x41, 0xc2, 0x8c, 0x59,
0x32, 0x2f, 0x15, 0x0b, 0x7d, 0xf3, 0x04, 0x7a, 0x99, 0xb9, 0x9a, 0xf7, 0x2d, 0xa8, 0x29, 0xb5,
0x3e, 0x5b, 0x2f, 0x7d, 0xe9, 0x2a, 0x4b, 0x4b, 0xab, 0x37, 0x1c, 0x6a, 0x01, 0xdd, 0x33, 0xfc,
0x56, 0x7a, 0xe4, 0x5f, 0xab, 0xc9, 0x8e, 0x81, 0xa8, 0xaf, 0xa7, 0x53, 0xe6, 0x5f, 0xbb, 0x3c,
0xf0, 0xb1, 0xb8, 0x2e, 0xe9, 0x12, 0x26, 0x99, 0x38, 0x1d, 0x94, 0x58, 0x58, 0xfd, 0x70, 0x55,
0xb4, 0xd1, 0x87, 0x90, 0x7d, 0x89, 0x91, 0xa9, 0x86, 0xb3, 0x45, 0x20, 0xd8, 0x94, 0x3a, 0x4e,
0x12, 0x2d, 0xa0, 0x44, 0x07, 0x8e, 0xc3, 0xf7, 0xff, 0x53, 0x86, 0xfa, 0xa7, 0x8a, 0xc0, 0xc9,
0x27, 0xd0, 0x29, 0xa4, 0x6b, 0xf2, 0x1a, 0x96, 0x75, 0xab, 0xc5, 0xc1, 0xe0, 0xee, 0x9a, 0x58,
0x9d, 0xeb, 0x3d, 0x68, 0xe7, 0x93, 0x31, 0xc1, 0xc4, 0x8b, 0xdf, 0x85, 0x07, 0x38, 0xd3, 0x7a,
0xa6, 0x3e, 0x87, 0x9d, 0x4d, 0x69, 0x92, 0x3c, 0xc8, 0x56, 0x58, 0x4f, 0xd1, 0x83, 0xd7, 0x6f,
0xd3, 0x26, 0xe9, 0xb5, 0x7e, 0xe8, 0x31, 0xea, 0xc7, 0x61, 0x7e, 0x07, 0x59, 0x93, 0x3c, 0x81,
0x4e, 0x21, 0x51, 0xa8, 0x73, 0xae, 0xe5, 0x8e, 0xfc, 0x90, 0xc7, 0x50, 0xc5, 0xe4, 0x44, 0x3a,
0x85, 0x2c, 0x39, 0xe8, 0xa6, 0x5d, 0xb5, 0xf6, 0x10, 0xb6, 0xf0, 0x6b, 0x41, 0x6e, 0x61, 0x1c,
0x91, 0x66, 0xae, 0xfd, 0x7f, 0x95, 0xa0, 0x9e, 0x7c, 0x41, 0x7e, 0x02, 0x5b, 0x32, 0x07, 0x90,
0x3b, 0x39, 0x1a, 0x4d, 0xf2, 0xc7, 0x60, 0x67, 0x45, 0xa8, 0x16, 0x18, 0x43, 0xe5, 0x39, 0x13,
0x84, 0xe4, 0x94, 0x3a, 0x19, 0x0c, 0xee, 0x14, 0x65, 0xa9, 0xfd, 0x59, 0x5c, 0xb4, 0xd7, 0x5c,
0x5e, 0xb0, 0x4f, 0x59, 0xfa, 0x43, 0xa8, 0x29, 0x96, 0x55, 0x4e, 0x59, 0xe3, 0x67, 0x75, 0xf9,
0xeb, 0x7c, 0xbc, 0xff, 0x8f, 0x2d, 0x80, 0xf3, 0x65, 0x24, 0xd8, 0xe2, 0x37, 0x2e, 0x7b, 0x41,
0x76, 0xa1, 0xa7, 0xbf, 0x89, 0xe0, 0x53, 0x4d, 0xb2, 0x49, 0xce, 0x27, 0x58, 0xf0, 0xa5, 0x64,
0xfd, 0x18, 0x5a, 0xa7, 0xf4, 0xe6, 0xe5, 0x76, 0x9f, 0x40, 0xa7, 0xc0, 0xc1, 0x7a, 0x8b, 0xab,
0xac, 0xae, 0xb7, 0xb8, 0xce, 0xd6, 0x8f, 0xa1, 0xae, 0x99, 0x39, 0xbf, 0x06, 0xe6, 0xb0, 0x02,
0x63, 0xff, 0x1c, 0x7a, 0x2b, 0xbc, 0x9c, 0xb7, 0xc7, 0xcf, 0x21, 0x1b, 0x79, 0xfb, 0xa9, 0x7c,
0xed, 0x14, 0xb9, 0x39, 0x3f, 0x50, 0xbf, 0xbc, 0x36, 0x91, 0xf7, 0xf3, 0xe2, 0x3b, 0x09, 0x9f,
0xa8, 0xc6, 0x2a, 0x7d, 0x26, 0xe4, 0x3d, 0xb8, 0xb7, 0x49, 0x93, 0x86, 0x60, 0x9e, 0x41, 0xd7,
0x42, 0x70, 0x9d, 0x5e, 0xdf, 0x01, 0xc8, 0x48, 0x34, 0x6f, 0x8f, 0xf0, 0x58, 0xe5, 0xd7, 0x0f,
0x00, 0x32, 0x6a, 0x54, 0xa8, 0x2a, 0x32, 0xab, 0x1a, 0xb6, 0x4a, 0x9f, 0xbb, 0xd0, 0x4c, 0xe9,
0x2c, 0xbf, 0x06, 0x4e, 0x50, 0x64, 0xc7, 0x4f, 0x77, 0x7f, 0x3f, 0x9a, 0xbb, 0xe2, 0x32, 0x9e,
0x8d, 0xed, 0x60, 0xb1, 0x77, 0x49, 0xa3, 0x4b, 0xd7, 0x0e, 0x78, 0xb8, 0x77, 0x2d, 0xc1, 0xb4,
0x57, 0xf8, 0xc1, 0x35, 0xab, 0xe1, 0x43, 0xef, 0xfd, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xbd,
0xc6, 0x6e, 0xfa, 0xf8, 0x1a, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View file

@ -210,6 +210,9 @@ message Auth {
// TokenType is the type of token being requested
uint32 token_type = 17;
// Whether the default policy should be added automatically by core
bool no_default_policy = 18;
}
message TokenEntry {

View file

@ -507,6 +507,7 @@ func LogicalAuthToProtoAuth(a *logical.Auth) (*Auth, error) {
Policies: a.Policies,
TokenPolicies: a.TokenPolicies,
IdentityPolicies: a.IdentityPolicies,
NoDefaultPolicy: a.NoDefaultPolicy,
Metadata: a.Metadata,
ClientToken: a.ClientToken,
Accessor: a.Accessor,
@ -554,6 +555,7 @@ func ProtoAuthToLogicalAuth(a *Auth) (*logical.Auth, error) {
Policies: a.Policies,
TokenPolicies: a.TokenPolicies,
IdentityPolicies: a.IdentityPolicies,
NoDefaultPolicy: a.NoDefaultPolicy,
Metadata: a.Metadata,
ClientToken: a.ClientToken,
Accessor: a.Accessor,

5
vendor/modules.txt vendored
View file

@ -348,9 +348,9 @@ github.com/hashicorp/vault-plugin-secrets-gcp/plugin/util
github.com/hashicorp/vault-plugin-secrets-gcpkms
# github.com/hashicorp/vault-plugin-secrets-kv v0.5.2-0.20190416155133-fd495225dea0
github.com/hashicorp/vault-plugin-secrets-kv
# github.com/hashicorp/vault/api v1.0.1 => ./api
# github.com/hashicorp/vault/api v1.0.3-0.20190614165924-47d4e5b1f688 => ./api
github.com/hashicorp/vault/api
# github.com/hashicorp/vault/sdk v0.1.11 => ./sdk
# github.com/hashicorp/vault/sdk v0.1.12-0.20190614165924-47d4e5b1f688 => ./sdk
github.com/hashicorp/vault/sdk/helper/salt
github.com/hashicorp/vault/sdk/helper/strutil
github.com/hashicorp/vault/sdk/helper/wrapping
@ -388,6 +388,7 @@ github.com/hashicorp/vault/sdk/helper/pathmanager
github.com/hashicorp/vault/sdk/database/helper/connutil
github.com/hashicorp/vault/sdk/helper/license
github.com/hashicorp/vault/sdk/helper/pluginutil
github.com/hashicorp/vault/sdk/helper/tokenutil
github.com/hashicorp/vault/sdk/plugin/pb
github.com/hashicorp/vault/sdk/helper/kdf
github.com/hashicorp/vault/sdk/plugin/mock

View file

@ -35,7 +35,7 @@ This endpoint creates or updates an Entity.
```json
{
"metadata": {
"organization": "hashicorp",
"organization": "hashicorp",
"team": "vault"
},
"policies": ["eng-dev", "infra-dev"]
@ -134,7 +134,7 @@ This endpoint is used to update an existing entity.
{
"name":"updatedEntityName",
"metadata": {
"organization": "hashi",
"organization": "hashicorp",
"team": "nomad"
},
"policies": ["eng-developers", "infra-developers"]
@ -243,7 +243,7 @@ This endpoint is used to create or update an entity by a given name.
```json
{
"metadata": {
"organization": "hashi",
"organization": "hashicorp",
"team": "nomad"
},
"policies": ["eng-developers", "infra-developers"]
@ -306,7 +306,7 @@ $ curl \
"last_update_time": "2018-09-19T17:20:27.705389973Z",
"merged_entity_ids": null,
"metadata": {
"organization": "hashi",
"organization": "hashicorp",
"team": "nomad"
},
"name": "testentityname",

View file

@ -146,9 +146,9 @@ This endpoint is used to update an existing group.
```json
{
"name": "testgroupname",
"metadata": {
"hello": "everyone"
},
"metadata": {
"hello": "everyone"
},
"policies": ["grouppolicy2", "grouppolicy3"]
}
```
@ -261,9 +261,9 @@ This endpoint is used to create or update a group by its name.
```json
{
"metadata": {
"hello": "everyone"
},
"metadata": {
"hello": "everyone"
},
"policies": ["grouppolicy2", "grouppolicy3"]
}
```

View file

@ -33,9 +33,9 @@ This endpoint creates or updates a group.
```json
{
"name": "engineering-group",
"metadata": ["organization=hashicorp", "team=vault"],
"policies": ["eng-dev", "infra-dev"]
"name": "engineering-group",
"metadata": ["organization=hashicorp", "team=vault"],
"policies": ["eng-dev", "infra-dev"]
}
```
@ -53,10 +53,10 @@ $ curl \
```json
{
"data": {
"id": "454ceeb5-76d7-a131-b92a-7ecfb15523e8",
"name": "engineering-group"
}
"data": {
"id": "454ceeb5-76d7-a131-b92a-7ecfb15523e8",
"name": "engineering-group"
}
}
```
@ -86,8 +86,8 @@ This endpoint updates the group by its ID.
```json
{
"metadata": ["organization=updatedorg", "team=updatedteam"],
"policies": ["updatedpolicy"]
"metadata": ["organization=updatedorg", "team=updatedteam"],
"policies": ["updatedpolicy"]
}
```
@ -105,10 +105,10 @@ $ curl \
```json
{
"data": {
"id": "454ceeb5-76d7-a131-b92a-7ecfb15523e8",
"name": "engineering-group"
}
"data": {
"id": "454ceeb5-76d7-a131-b92a-7ecfb15523e8",
"name": "engineering-group"
}
}
```
@ -136,22 +136,22 @@ $ curl \
```json
{
"data": {
"creation_time": "2017-09-13T01:17:26.755474204Z",
"id": "454ceeb5-76d7-a131-b92a-7ecfb15523e8",
"last_update_time": "2017-09-13T01:17:26.755474204Z",
"member_entity_ids": [],
"member_group_ids": null,
"metadata": {
"organization": "hashicorp",
"team": "vault"
},
"modify_index": 1,
"name": "engineering-group",
"policies": [
"dev-policy"
]
}
"data": {
"creation_time": "2017-09-13T01:17:26.755474204Z",
"id": "454ceeb5-76d7-a131-b92a-7ecfb15523e8",
"last_update_time": "2017-09-13T01:17:26.755474204Z",
"member_entity_ids": [],
"member_group_ids": null,
"metadata": {
"organization": "hashicorp",
"team": "vault"
},
"modify_index": 1,
"name": "engineering-group",
"policies": [
"dev-policy"
]
}
}
```
@ -228,8 +228,8 @@ This endpoint queries the group by its ID.
```json
{
"type": "by_id",
"group_id": "454ceeb5-76d7-a131-b92a-7ecfb15523e8"
"type": "by_id",
"group_id": "454ceeb5-76d7-a131-b92a-7ecfb15523e8"
}
```
@ -247,21 +247,21 @@ $ curl \
```json
{
"data": {
"creation_time": "2017-09-13T01:17:26.755474204Z",
"id": "454ceeb5-76d7-a131-b92a-7ecfb15523e8",
"last_update_time": "2017-09-13T01:17:26.755474204Z",
"member_entity_ids": [],
"member_group_ids": null,
"metadata": {
"organization": "hashicorp",
"team": "vault"
},
"modify_index": 1,
"name": "engineering-group",
"policies": [
"dev-policy"
]
}
"data": {
"creation_time": "2017-09-13T01:17:26.755474204Z",
"id": "454ceeb5-76d7-a131-b92a-7ecfb15523e8",
"last_update_time": "2017-09-13T01:17:26.755474204Z",
"member_entity_ids": [],
"member_group_ids": null,
"metadata": {
"organization": "hashicorp",
"team": "vault"
},
"modify_index": 1,
"name": "engineering-group",
"policies": [
"dev-policy"
]
}
}
```

View file

@ -267,9 +267,9 @@ list of available configuration options, please see the [API documentation](/api
```text
$ vault write auth/jwt/config \
oidc_discovery_url="https://myco.auth0.com/"
oidc_client_id="m5i8bj3iofytj",
oidc_client_secret="f4ubv72nfiu23hnsj",
oidc_discovery_url="https://myco.auth0.com/" \
oidc_client_id="m5i8bj3iofytj" \
oidc_client_secret="f4ubv72nfiu23hnsj" \
default_role="demo"
```

View file

@ -0,0 +1,47 @@
---
layout: "docs"
page_title: "kv delete - Command"
sidebar_title: "<code>delete</code>"
sidebar_current: "docs-commands-kv-delete"
description: |-
The "kv delete" command disables a secrets engine at a given PATH. The
argument corresponds to the enabled PATH of the engine, not the TYPE! All
secrets created by this engine are revoked and its Vault data is removed.
---
# kv delete
The `kv delete` command deletes the data for the provided path in
the key/value secrets engine. If using K/V Version 2, its versioned data will
not be fully removed, but marked as deleted and will no longer be returned in
normal get requests.
## Examples
Delete the latest version of the key "creds":
```text
$ vault kv delete secret/creds
Success! Data deleted (if it existed) at: secret/creds
```
**[K/V Version 2]** Delete version 11 of key "creds":
```text
$ vault kv delete -versions=11 secret/creds
Success! Data deleted (if it existed) at: secret/creds
```
## Usage
There are no flags beyond the [standard set of flags](/docs/commands/index.html)
included on all commands.
### Command Options
- `-versions` `([]int: <required>)` - The versions to be deleted. The versioned
data will not be deleted, but it will no longer be returned in normal get
requests.
~> **NOTE:** This command option is only for K/V v2.

View file

@ -0,0 +1,44 @@
---
layout: "docs"
page_title: "kv destroy - Command"
sidebar_title: "<code>destroy</code>"
sidebar_current: "docs-commands-kv-destroy"
description: |-
The "kv destroy" command permanently removes the specified version data for
the provided key and version numbers from the key-value store.
---
# kv destroy
~> **NOTE:** This is a [K/V Version 2](/docs/secrets/kv/kv-v2.html) secrets
engine command, and not available for Version 1.
The `secrets enable` command permanently removes the specified versions' data
from the key/value secrets engine. If no key exists at the path, no action is
taken.
## Examples
Destroy version 11 of the key "creds":
```text
$ vault kv destroy -versions=11 secret/creds
Success! Data written to: secret/destroy/creds
```
## Usage
There are no flags beyond the [standard set of flags](/docs/commands/index.html)
included on all commands.
### Output Options
- `-format` `(string: "table")` - Print the output in the given format. Valid
formats are "table", "json", or "yaml". This can also be specified via the
`VAULT_FORMAT` environment variable.
### Command Options
- `-versions` `([]int: <required>)` - The versions to destroy. Their data will
be permanently deleted.

View file

@ -0,0 +1,35 @@
---
layout: "docs"
page_title: "kv enable-versioning - Command"
sidebar_title: "<code>enable-versioning</code>"
sidebar_current: "docs-commands-kv-enable-versioning"
description: |-
The "kv enable-versioning" command turns on versioning for the backend
at the provided path.
---
# kv enable-versioning
The `kv enable-versioning` command turns on versioning for an existing
non-versioned key/value secrets engine (K/V Version 1) at its path.
## Examples
This command turns on versioning for the K/V Version 1 secrets engine enabled at
"secret".
```text
$ vault kv enable-versioning secret
Success! Tuned the secrets engine at: secret/
```
## Usage
There are no flags beyond the [standard set of flags](/docs/commands/index.html)
included on all commands.
### Output Options
- `-format` `(string: "table")` - Print the output in the given format. Valid
formats are "table", "json", or "yaml". This can also be specified via the
`VAULT_FORMAT` environment variable.

View file

@ -0,0 +1,68 @@
---
layout: "docs"
page_title: "kv get - Command"
sidebar_title: "<code>get</code>"
sidebar_current: "docs-commands-kv-get"
description: |-
The "kv get" command retrieves the value from Vault's key-value store at the
given key name. If no key exists with that name, an error is returned. If a
key exists with that name but has no data, nothing is returned.
---
# kv get
The `kv get` command retrieves the value from K/V secrets engine at the given
key name. If no key exists with that name, an error is returned. If a key exists
with the name but has no data, nothing is returned.
## Examples
Retrieve the data of the key "creds":
```text
$ vault kv get secret/creds
====== Metadata ======
Key Value
--- -----
created_time 2019-06-06T06:03:26.595978Z
deletion_time n/a
destroyed false
version 5
====== Data ======
Key Value
--- -----
passcode my-long-passcode
```
If K/V Version 1 secrets engine is enabled at "secret", the output has no
metadata since there is no versioning information associated with the data:
```text
$ vault kv get secret/creds
====== Data ======
Key Value
--- -----
passcode my-long-passcode
```
## Usage
There are no flags beyond the [standard set of flags](/docs/commands/index.html)
included on all commands.
### Output Options
- `-field` `(string: "")` - Print only the field with the given name. Specifying
this option will take precedence over other formatting directives. The result
will not have a trailing newline making it ideal for piping to other
processes.
- `-format` `(string: "table")` - Print the output in the given format. Valid
formats are "table", "json", or "yaml". This can also be specified via the
`VAULT_FORMAT` environment variable.
### Command Options
- `-version` `(int: 0)` - Specifies the version to return. If not set the
latest version is returned.

View file

@ -0,0 +1,114 @@
---
layout: "docs"
page_title: "kv - Command"
sidebar_title: "<code>kv</code>"
sidebar_current: "docs-commands-kv"
description: |-
The "kv" command groups subcommands for interacting with Vault's key/value
secret engine.
---
# kv
The `kv` command groups subcommands for interacting with Vault's key/value
secrets engine (both [K/V Version 1](/docs/secrets/kv/kv-v1.html) and [K/V
Version 2](/docs/secrets/kv/kv-v2.html).
## Examples
Create or update the key named "creds" in the K/V Version 2 enabled at "secret"
with the value "passcode=my-long-passcode":
```text
$ vault kv put secret/creds passcode=my-long-passcode
Key Value
--- -----
created_time 2019-06-06T04:07:33.279432Z
deletion_time n/a
destroyed false
version 1
```
Read this value back:
```text
$ vault kv get secret/creds
====== Metadata ======
Key Value
--- -----
created_time 2019-06-06T04:07:33.279432Z
deletion_time n/a
destroyed false
version 1
====== Data ======
Key Value
--- -----
passcode my-long-passcode
```
Get metadata for the key named "creds":
```text
$ vault kv metadata get secret/creds
======= Metadata =======
Key Value
--- -----
cas_required false
created_time 2019-06-06T04:07:33.279432Z
current_version 1
max_versions 0
oldest_version 0
updated_time 2019-06-06T04:07:33.279432Z
====== Version 1 ======
Key Value
--- -----
created_time 2019-06-06T04:07:33.279432Z
deletion_time n/a
destroyed false
```
Get a specific version of the key named "creds":
```text
$ vault kv get -version=1 secret/creds
====== Metadata ======
Key Value
--- -----
created_time 2019-06-06T04:07:33.279432Z
deletion_time n/a
destroyed false
version 1
====== Data ======
Key Value
--- -----
passcode my-long-passcode
```
## Usage
```text
Usage: vault kv <subcommand> [options] [args]
# ...
Subcommands:
delete Deletes versions in the KV store
destroy Permanently removes one or more versions in the KV store
enable-versioning Turns on versioning for a KV store
get Retrieves data from the KV store
list List data or secrets
metadata Interact with Vault's Key-Value storage
patch Sets or updates data in the KV store without overwriting
put Sets or updates data in the KV store
rollback Rolls back to a previous version of data
undelete Undeletes versions in the KV store
```
For more information, examples, and usage about a subcommand, click on the name
of the subcommand in the sidebar.

View file

@ -0,0 +1,45 @@
---
layout: "docs"
page_title: "kv list - Command"
sidebar_title: "<code>list</code>"
sidebar_current: "docs-commands-kv-list"
description: |-
The "kv list" command lists data from Vault's K/V secrets engine at the given
path.
---
# kv list
The `kv list` command returns a list of key names at the specified location.
Folders are suffixed with /. The input must be a folder; list on a file will not
return a value. Note that no policy-based filtering is performed on keys; do not
encode sensitive information in key names. The values themselves are not
accessible via this command.
Use this command to list all existing key names at a specific path.
## Examples
List values under the key "my-app":
```text
$ vault kv list secret/my-app/
Keys
----
admin_creds
domain
eng_creds
qa_creds
release
```
## Usage
There are no flags beyond the [standard set of flags](/docs/commands/index.html)
included on all commands.
### Output Options
- `-format` `(string: "table")` - Print the output in the given format. Valid
formats are "table", "json", or "yaml". This can also be specified via the
`VAULT_FORMAT` environment variable.

View file

@ -0,0 +1,140 @@
---
layout: "docs"
page_title: "kv metadata - Command"
sidebar_title: "<code>metadata</code>"
sidebar_current: "docs-commands-kv-metadata"
description: |-
The "kv metadata" command has subcommands for interacting with the metadata
endpoint in Vault's key-value store.
---
# kv metadata
~> **NOTE:** This is a [K/V Version 2](/docs/secrets/kv/kv-v2.html) secrets
engine command, and not available for Version 1.
The `kv metadata` command has subcommands for interacting with the metadata and
versions for the versioned secrets (K/V Version 2 secrets engine) at the
specified path.
## Usage
```text
Usage: vault kv metadata <subcommand> [options] [args]
# ...
Subcommands:
delete Deletes all versions and metadata for a key in the KV store
get Retrieves key metadata from the KV store
put Sets or updates key settings in the KV store
```
### kv metadata delete
The `kv metadata delete` command deletes all versions and metadata for the
provided key.
#### Examples
Deletes all versions and metadata of the key "creds":
```text
$ vault kv metadata delete secret/creds
Success! Data deleted (if it existed) at: secret/metadata/creds
```
### kv metadata get
The `kv metadata get` command retrieves the metadata of the versioned secrets at
the given key name. If no key exists with that name, an error is returned.
#### Examples
Retrieves the metadata of the key name, "creds":
```text
$ vault kv metadata get secret/creds
======= Metadata =======
Key Value
--- -----
cas_required false
created_time 2019-06-06T04:07:33.279432Z
current_version 5
max_versions 0
oldest_version 0
updated_time 2019-06-06T06:03:26.595978Z
====== Version 1 ======
Key Value
--- -----
created_time 2019-06-06T04:07:33.279432Z
deletion_time n/a
destroyed false
====== Version 2 ======
Key Value
--- -----
created_time 2019-06-06T06:03:12.187441Z
deletion_time n/a
destroyed false
...
```
### kv metadata put
The `kv metadata put` command can be used to create a blank key in the K/V v2
secrets engine or to update key configuration for a specified key.
#### Examples
Create a key in the K/V v2 with no data at the key "creds":
```text
$ vault kv metadata put secret/creds
Success! Data written to: secret/metadata/creds
```
Set the maximum number of versions to keep for the key "creds":
```text
$ vault kv metadata put -max-versions=5 secret/creds
Success! Data written to: secret/metadata/creds
```
**NOTE:** If not set, the backends configured max version is used. Once a key
has more than the configured allowed versions the oldest version will be
permanently deleted.
Require Check-and-Set for the key "creds":
```text
$ vault kv metadata put -cas-required secret/creds
```
**NOTE:** When check-and-set is required, the key will require the `cas`
parameter to be set on all write requests. Otherwise, the backends
configuration will be used.
#### Output Options
- `-format` `(string: "table")` - Print the output in the given format. Valid
formats are "table", "json", or "yaml". This can also be specified via the
`VAULT_FORMAT` environment variable.
#### Subcommand Options
- `-cas-required` `(bool: false)` - If true the key will require the cas
parameter to be set on all write requests. If false, the backends
configuration will be used. The default is false.
- `-max-versions` `(int: 0)` - The number of versions to keep per key. If not
set, the backends configured max version is used. Once a key has more than the
configured allowed versions the oldest version will be permanently deleted.

Some files were not shown because too many files have changed in this diff Show more