Compare commits

..

1 Commits

Author SHA1 Message Date
Daryl White
bcbb3ebbf0 Correcting doc links on Configuration pages 2022-04-29 10:53:02 -05:00
3370 changed files with 462207 additions and 299031 deletions

View File

@@ -3,5 +3,5 @@ dist/
target/
console
!console/
web-app/node_modules/
portal-ui/node_modules/
.git/

View File

@@ -1,48 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: community, triage
assignees: ''
---
## NOTE
If this case is urgent, please subscribe to [Subnet](https://min.io/pricing) so that our 24/7 support team may help you faster.
<!--- Provide a general summary of the issue in the title above -->
## Expected Behavior
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
## Current Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->
## Steps to Reproduce (for bugs)
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
1.
2.
3.
4.
## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
## Regression
<!-- Is this issue a regression? (Yes / No) -->
<!-- If Yes, optionally please include the MinIO version or commit id or PR# that caused this regression, if you have these details. -->
## Your Environment
<!--- Include as many relevant details about the environment you experienced the bug in -->
* MinIO version used (`minio --version`):
* Server setup and configuration:
* Operating System and version (`uname -a`):

94
.github/workflows/common.sh vendored Executable file
View File

@@ -0,0 +1,94 @@
#!/usr/bin/env bash
# Copyright (C) 2022, MinIO, Inc.
#
# This code is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3,
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License, version 3,
# along with this program. If not, see <http://www.gnu.org/licenses/>
yell() { echo "$0: $*" >&2; }
die() {
yell "$*"
(kind delete cluster || true ) && exit 111
}
try() { "$@" || die "cannot $*"; }
function setup_kind() {
# TODO once feature is added: https://github.com/kubernetes-sigs/kind/issues/1300
echo "kind: Cluster" > kind-config.yaml
echo "apiVersion: kind.x-k8s.io/v1alpha4" >> kind-config.yaml
echo "nodes:" >> kind-config.yaml
echo " - role: control-plane" >> kind-config.yaml
echo " - role: worker" >> kind-config.yaml
echo " - role: worker" >> kind-config.yaml
echo " - role: worker" >> kind-config.yaml
echo " - role: worker" >> kind-config.yaml
try kind create cluster --config kind-config.yaml
echo "Kind is ready"
try kubectl get nodes
}
function install_operator() {
echo "Installing Current Operator"
# TODO: Compile the current branch and create an overlay to use that image version
try kubectl apply -k "${SCRIPT_DIR}/../../portal-ui/tests/scripts/resources"
echo "Waiting for k8s api"
sleep 10
echo "Waiting for Operator Pods to come online (2m timeout)"
try kubectl wait --namespace minio-operator \
--for=condition=ready pod \
--selector=name=minio-operator \
--timeout=120s
}
function destroy_kind() {
kind delete cluster
}
function check_tenant_status() {
# Check MinIO is accessible
waitdone=0
totalwait=0
while true; do
waitdone=$(kubectl -n $1 get pods -l v1.min.io/tenant=$2 --no-headers | wc -l)
if [ "$waitdone" -ne 0 ]; then
echo "Found $waitdone pods"
break
fi
sleep 5
totalwait=$((totalwait + 5))
if [ "$totalwait" -gt 305 ]; then
echo "Unable to create tenant after 5 minutes, exiting."
try false
fi
done
echo "Waiting for pods to be ready. (5m timeout)"
USER=$(kubectl -n $1 get secrets $2-env-configuration -o go-template='{{index .data "config.env"|base64decode }}' | grep 'export MINIO_ROOT_USER="' | sed -e 's/export MINIO_ROOT_USER="//g' | sed -e 's/"//g')
PASSWORD=$(kubectl -n $1 get secrets $2-env-configuration -o go-template='{{index .data "config.env"|base64decode }}' | grep 'export MINIO_ROOT_PASSWORD="' | sed -e 's/export MINIO_ROOT_PASSWORD="//g' | sed -e 's/"//g')
try kubectl wait --namespace $1 \
--for=condition=ready pod \
--selector=v1.min.io/tenant=$2 \
--timeout=300s
echo "Tenant is created successfully, proceeding to validate 'mc admin info minio/'"
kubectl run admin-mc -i --tty --image minio/mc --command -- bash -c "until (mc alias set minio/ https://minio.$1.svc.cluster.local $USER $PASSWORD); do echo \"...waiting... for 5secs\" && sleep 5; done; mc admin info minio/;"
echo "Done."
}

View File

@@ -1,166 +0,0 @@
# @format
name: Cross Compile
on:
pull_request:
branches:
- master
paths:
- go.sum
# This ensures that previous jobs for the PR are canceled when the PR is
# updated.
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true
jobs:
cross-compile-1:
name: Cross compile
needs:
- lint-job
- ui-assets
- reuse-golang-dependencies
- semgrep-static-code-analysis
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [ 1.21.x ]
os: [ ubuntu-latest ]
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
cache: true
id: go
- name: Build on ${{ matrix.os }}
env:
GO111MODULE: on
GOOS: linux
run: |
make crosscompile arg1="'linux/ppc64le linux/mips64'"
cross-compile-2:
name: Cross compile 2
needs:
- lint-job
- ui-assets
- reuse-golang-dependencies
- semgrep-static-code-analysis
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [ 1.21.x ]
os: [ ubuntu-latest ]
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
cache: true
id: go
- name: Build on ${{ matrix.os }}
env:
GO111MODULE: on
GOOS: linux
run: |
make crosscompile arg1="'linux/arm64 linux/s390x'"
cross-compile-3:
name: Cross compile 3
needs:
- lint-job
- ui-assets
- reuse-golang-dependencies
- semgrep-static-code-analysis
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [ 1.21.x ]
os: [ ubuntu-latest ]
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
cache: true
id: go
- name: Build on ${{ matrix.os }}
env:
GO111MODULE: on
GOOS: linux
run: |
make crosscompile arg1="'darwin/amd64 freebsd/amd64'"
cross-compile-4:
name: Cross compile 4
needs:
- lint-job
- ui-assets
- reuse-golang-dependencies
- semgrep-static-code-analysis
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [ 1.21.x ]
os: [ ubuntu-latest ]
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
cache: true
id: go
- name: Build on ${{ matrix.os }}
env:
GO111MODULE: on
GOOS: linux
run: |
make crosscompile arg1="'windows/amd64 linux/arm'"
cross-compile-5:
name: Cross compile 5
needs:
- lint-job
- ui-assets
- reuse-golang-dependencies
- semgrep-static-code-analysis
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [ 1.21.x ]
os: [ ubuntu-latest ]
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
cache: true
id: go
- name: Build on ${{ matrix.os }}
env:
GO111MODULE: on
GOOS: linux
run: |
make crosscompile arg1="'linux/386 netbsd/amd64'"

71
.github/workflows/deploy-tenant.sh vendored Executable file
View File

@@ -0,0 +1,71 @@
#!/usr/bin/env bash
# Copyright (C) 2022, MinIO, Inc.
#
# This code is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3,
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License, version 3,
# along with this program. If not, see <http://www.gnu.org/licenses/>
# This script requires: kubectl, kind
SCRIPT_DIR=$(dirname "$0")
export SCRIPT_DIR
source "${SCRIPT_DIR}/common.sh"
function install_tenant() {
echo "Installing lite tenant"
try kubectl apply -k "${SCRIPT_DIR}/../../portal-ui/tests/scripts/tenant"
echo "Waiting for the tenant statefulset, this indicates the tenant is being fulfilled"
waitdone=0
totalwait=0
while true; do
waitdone=$(kubectl -n tenant-lite get pods -l v1.min.io/tenant=storage-lite --no-headers | wc -l)
if [ "$waitdone" -ne 0 ]; then
echo "Found $waitdone pods"
break
fi
sleep 5
totalwait=$((totalwait + 5))
if [ "$totalwait" -gt 300 ]; then
echo "Tenant never created statefulset after 5 minutes"
try false
fi
done
echo "Waiting for tenant pods to come online (5m timeout)"
try kubectl wait --namespace tenant-lite \
--for=condition=ready pod \
--selector="v1.min.io/tenant=storage-lite" \
--timeout=300s
echo "Build passes basic tenant creation"
}
function main() {
destroy_kind
setup_kind
install_operator
install_tenant
check_tenant_status tenant-lite storage-lite
kubectl proxy &
}
main "$@"

View File

@@ -1,18 +0,0 @@
# @format
name: Issue Workflow
on:
issues:
types:
- opened
jobs:
add-to-project:
name: Add issue to project
runs-on: ubuntu-latest
steps:
- uses: actions/add-to-project@v0.5.0
with:
project-url: https://github.com/orgs/miniohq/projects/2
github-token: ${{ secrets.BOT_PAT }}

File diff suppressed because it is too large Load Diff

View File

@@ -1,53 +0,0 @@
# @format
name: Vulnerability Check
on:
pull_request:
branches:
- master
push:
branches:
- master
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
vulncheck:
name: Analysis
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.21.9
check-latest: true
- name: Get official govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@latest
shell: bash
- name: Run govulncheck
run: govulncheck ./...
shell: bash
react-code-known-vulnerabilities:
name: "React Code Has No Known Vulnerable Deps"
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [ 1.21.8 ]
os: [ ubuntu-latest ]
steps:
- name: Check out code
uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ env.NVMRC }}
cache: "yarn"
cache-dependency-path: web-app/yarn.lock
- name: Checks for known security issues with the installed packages
working-directory: ./web-app
continue-on-error: false
run: |
yarn audit --groups dependencies

12
.gitignore vendored
View File

@@ -1,13 +1,3 @@
# Playwright Data
web-app/storage/
web-app/playwright/.auth/admin.json
# Report from Playwright
web-app/playwright-report/
# Coverage from Playwright
web-app/.nyc_output/
# Binaries for programs and plugins
*.exe
*.exe~
@@ -37,7 +27,7 @@ dist/
# Ignore node_modules
web-app/node_modules/
portal-ui/node_modules/
# Ignore tls cert and key
private.key

View File

@@ -5,29 +5,28 @@ linters-settings:
misspell:
locale: US
goheader:
values:
regexp:
copyright-holder: Copyright \(c\) (20\d\d\-20\d\d)|2021|({{year}})
template-path: .license.tmpl
linters:
disable-all: true
enable:
- typecheck
- goimports
- misspell
- govet
- revive
- ineffassign
- gosimple
- gomodguard
- gofmt
- deadcode
- unparam
- unused
- staticcheck
- unconvert
- gocritic
- gofumpt
- durationcheck
- structcheck
- goheader
linters-settings:
goheader:
values:
regexp:
copyright-holder: Copyright \(c\) (20\d\d\-20\d\d)|2021|({{year}})
template-path: .license.tmpl
service:
golangci-lint-version: 1.43.0 # use the fixed version to not introduce new linters unexpectedly
@@ -35,15 +34,14 @@ service:
issues:
exclude-use-default: false
exclude:
- should have a package comment
# TODO(y4m4): Remove once all exported ident. have comments!
- comment on exported function
- comment on exported type
- should have comment
- use leading k in Go names
- comment on exported const
- should have a package comment
# TODO(y4m4): Remove once all exported ident. have comments!
- comment on exported function
- comment on exported type
- should have comment
- use leading k in Go names
- comment on exported const
run:
skip-dirs:
- pkg/clientgen
- pkg/apis/networking.gke.io
- api/operations

195
.goreleaser.yml Normal file
View File

@@ -0,0 +1,195 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
project_name: console
release:
name_template: "Release version {{.Tag}}"
github:
owner: minio
name: console
extra_files:
- glob: "*.minisig"
before:
hooks:
# you may remove this if you don't use vgo
- go mod tidy -compat=1.17
builds:
-
goos:
- linux
- darwin
- windows
goarch:
- amd64
- ppc64le
- s390x
- arm64
ignore:
- goos: darwin
goarch: arm
- goos: windows
goarch: arm64
- goos: windows
goarch: arm
env:
- CGO_ENABLED=0
main: ./cmd/console/
flags:
- -trimpath
- --tags=kqueue,operator
ldflags:
- -s -w -X github.com/minio/console/pkg.ReleaseTag={{.Tag}} -X github.com/minio/console/pkg.CommitID={{.FullCommit}} -X github.com/minio/console/pkg.Version={{.Version}} -X github.com/minio/console/pkg.ShortCommitID={{.ShortCommit}} -X github.com/minio/console/pkg.ReleaseTime={{.Date}}
archives:
-
name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}"
format: binary
replacements:
arm: arm
signs:
-
signature: "${artifact}.minisig"
cmd: "sh"
args:
- '-c'
- 'minisign -s /media/${USER}/minio/minisign.key -Sm ${artifact} < /media/${USER}/minio/minisign-passphrase'
artifacts: all
snapshot:
name_template: v0.0.0@{{.ShortCommit}}
changelog:
sort: asc
nfpms:
-
vendor: MinIO, Inc.
homepage: https://github.com/minio/console
maintainer: MinIO Development <dev@min.io>
description: MinIO Console Server
license: GNU Affero General Public License v3.0
formats:
- deb
- rpm
contents:
# Basic file that applies to all packagers
- src: systemd/console.service
dst: /etc/systemd/system/minio-console.service
dockers:
- image_templates:
- "minio/console:{{ .Tag }}-amd64"
use: buildx
goarch: amd64
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "minio/console:{{ .Tag }}-ppc64le"
use: buildx
goarch: ppc64le
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/ppc64le"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "minio/console:{{ .Tag }}-s390x"
use: buildx
goarch: s390x
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/s390x"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "minio/console:{{ .Tag }}-arm64"
use: buildx
goarch: arm64
goos: linux
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/arm64"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-amd64"
use: buildx
goarch: amd64
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-ppc64le"
use: buildx
goarch: ppc64le
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/ppc64le"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-s390x"
use: buildx
goarch: s390x
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/s390x"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-arm64"
use: buildx
goarch: arm64
goos: linux
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/arm64"
- "--build-arg=TAG={{ .Tag }}"
docker_manifests:
- name_template: minio/console:{{ .Tag }}
image_templates:
- minio/console:{{ .Tag }}-amd64
- minio/console:{{ .Tag }}-arm64
- minio/console:{{ .Tag }}-ppc64le
- minio/console:{{ .Tag }}-s390x
- name_template: quay.io/minio/console:{{ .Tag }}
image_templates:
- quay.io/minio/console:{{ .Tag }}-amd64
- quay.io/minio/console:{{ .Tag }}-arm64
- quay.io/minio/console:{{ .Tag }}-ppc64le
- quay.io/minio/console:{{ .Tag }}-s390x
- name_template: minio/console:latest
image_templates:
- minio/console:{{ .Tag }}-amd64
- minio/console:{{ .Tag }}-arm64
- minio/console:{{ .Tag }}-ppc64le
- minio/console:{{ .Tag }}-s390x

1
.nvmrc
View File

@@ -1 +0,0 @@
18

View File

@@ -1,35 +0,0 @@
# Ignore git items
.gitignore
.git/
:include .gitignore
# Common large paths
node_modules/
web-app/node_modules/
build/
dist/
.idea/
vendor/
.env/
.venv/
.tox/
*.min.js
# Common test paths
test/
tests/
*_test.go
# Semgrep rules folder
.semgrep
# Semgrep-action log folder
.semgrep_logs/
# Ignore VsCode files
.vscode/
*.code-workspace
*~
.eslintcache
consoleApi.ts

View File

@@ -1,290 +0,0 @@
<!-- @format -->
# Changelog
## Release v1.2.0
Features:
- Updated file share logic to work as Proxy
Bug Fix:
- Updated project dependencies
- Fixed Key Permissions UX
- Added permissions validation to rewind button
- Fixed Health report upload to SUBNET
- Misc Cosmetic fixes
## Release v1.1.1
Bug Fix:
- Fixed folder download issue
## Release v1.1.0
Features:
- Added Set Expired object all versions selector
Bug Fix:
- Updated Go Dependencies
## Release v1.0.0
Features:
- Updated Preview message alert
Bug Fix:
- Updated Websocket API
- Fixed issues with download manager
- Fixed policies issues
## Release v0.46.0
Features:
- Added latest help content to forms
Bug Fix:
- Disabled Create User button in certain policy cases
- Fixed an issue with Logout request
- Upgraded project dependencies
## Release v0.45.0
Deprecated:
- Deprecated Heal / Drives page
Features:
- Updated tines on menus & pages
Bug Fix:
- Upgraded project dependencies
## Release v0.44.0
Bug Fix:
- Upgraded project dependencies
- Fixed events icons not loading in subpaths
## Release v0.43.1
Bug Fix:
- Update Share Object UI to reflect maximum expiration time in UI
## Release v0.43.0
Features:
- Updated PDF preview method
Bug Fix:
- Fixed vulnerabilities
- Prevented non-necessary metadata calls in object browser
## Release v0.42.2
Bug Fix:
- Hidden Prometheus metrics if URL is empty
## Release v0.42.1
Bug Fix:
- Reset go version to 1.19
## Release v0.42.0
Features:
- Introducing Dark Mode
Bug Fix:
- Fixed vulnerabilities
- Changes on Upload and Delete object urls
- Fixed blocking subpath creation if not enough permissions
- Removed share object option at prefix level
- Updated allowed actions for a deleted object
## Release v0.41.0
Features:
- Updated pages to use mds components
- support for resolving IPv4/IPv6
Bug Fix:
- Remove cache for ClientIP
- Fixed override environment variables display in settings page
- Fixed daylight savings time support in share modal
## Release v0.40.0
Features:
- Updated OpenID page
- Added New bucket event types support
Bug Fix:
- Fixed crash in access keys page
- Fixed AuditLog filters issue
- Fixed multiple issues with Object Browser
## Release v0.39.0
Features:
- Migrated metrics page to mds
- Migrated Register page to mds
Bug Fix:
- Fixed LDAP configuration page issues
- Load available certificates in logout
- Updated dependencies & go version
- Fixed delete objects functionality
## Release v0.38.0
Features:
- Added extra information to Service Accounts page
- Updated Tiers, Site Replication, Speedtest, Heal & Watch pages components
Bug Fix:
- Fixed IDP expiry time errors
- Updated project Dependencies
## Release v0.37.0
Features:
- Updated Trace and Logs page components
- Updated Prometheus metrics
Bug Fix:
- Disabled input fields for Subscription features if MinIO is not registered
## Release v0.36.0
Features:
- Updated Settings page components
Bug Fix:
- Show LDAP Enabled value LDAP configuration
- Download multiple objects in same path as they were selected
## Release v0.35.1
Bug Fix:
- Change timestamp format for zip creation
## Release v0.35.0
Features:
- Add Exclude Folders and Exclude Prefixes during bucket creation
- Download multiple selected objects as zip and ignore deleted objects
- Updated Call Home, Inspet, Profile and Health components
Bug Fix:
- Remove extra white spaces for configuration strings
- Allow Create New Path in bucket view when having right permissions
## Release v0.34.0
Features:
- Updated Buckets components
Bug Fix:
- Fixed SUBNET Health report upload
- Updated Download Handler
- Fixes issue with rewind
- Avoid 1 hour expiration for IDP credentials
---
## Release v0.33.0
Features:
- Updated OpenID, LDAP components
Bug Fix:
- Fixed security issues
- Fixed navigation issues in Object Browser
- Fixed Dashboard metrics
---
## Release v0.32.0
Features:
- Updated Users and Groups components
- Added placeholder image for Help Menu
Bug Fix:
- Fixed memory leak in WebSocket API for Object Browser
---
## Release v0.31.0
**Breaking Changes:**
- **Removed support for Standalone Deployments**
Features:
- Updated way files are displayed in uploading component
- Updated Audit Logs and Policies components
Bug Fix:
- Fixed Download folders issue in Object Browser
- Added missing Notification Events (ILM & REPLICA) in Events Notification Page
- Fixed Security Vulnerability for `semver` dependency
---
## Release v0.30.0
Features:
- Added MinIO Console Help Menu
- Updated UI Menu components
Bug Fix:
- Disable the Upload button on Object Browser if the user is not allowed
- Fixed security vulnerability for `lestrrat-go/jwx` and `fast-xml-parser`
- Fixed bug on sub-paths for Object Browser
- Reduce the number of calls to `/session` API endpoint to improve performance
- Rolled back the previous change for the Share File feature to no longer ask for Service Account access keys

View File

@@ -4,80 +4,56 @@ This is a REST portal server created using [go-swagger](https://github.com/go-sw
The API handlers are created using a YAML definition located in `swagger.YAML`.
To add new api, the YAML file needs to be updated with all the desired apis using
the [Swagger Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/), this includes paths,
parameters, definitions, tags, etc.
To add new api, the YAML file needs to be updated with all the desired apis using the [Swagger Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/), this includes paths, parameters, definitions, tags, etc.
## Generate server from YAML
Once the YAML file is ready we can autogenerate the code needed for the new api by just running:
Validate it:
```
swagger validate ./swagger.yml
```
Update server code:
```
make swagger-gen
```
This will update all the necessary code.
`./api/configure_console.go` is a file that contains the handlers to be used by the application, here is the only place
where we need to update our code to support the new apis. This file is not affected when running the swagger generator
and it is safe to edit.
`./restapi/configure_console.go` is a file that contains the handlers to be used by the application, here is the only place where we need to update our code to support the new apis. This file is not affected when running the swagger generator and it is safe to edit.
## Unit Tests
`./api/handlers_test.go` needs to be updated with the proper tests for the new api.
`./restapi/handlers_test.go` needs to be updated with the proper tests for the new api.
To run tests:
```
go test ./api
go test ./restapi
```
## Commit changes
After verification, commit your changes. This is a [great post](https://chris.beams.io/posts/git-commit/) on how to
write useful commit messages
After verification, commit your changes. This is a [great post](https://chris.beams.io/posts/git-commit/) on how to write useful commit messages
```
$ git commit -am 'Add some feature'
```
### Push to the branch
Push your locally committed changes to the remote origin (your fork)
```
$ git push origin my-new-feature
```
### Create a Pull Request
Pull requests can be created via GitHub. Refer
to [this document](https://help.github.com/articles/creating-a-pull-request/) for detailed steps on how to create a pull
request. After a Pull Request gets peer reviewed and approved, it will be merged.
Pull requests can be created via GitHub. Refer to [this document](https://help.github.com/articles/creating-a-pull-request/) for detailed steps on how to create a pull request. After a Pull Request gets peer reviewed and approved, it will be merged.
## FAQs
### How does ``console`` manages dependencies?
``MinIO`` uses `go mod` to manage its dependencies.
- Run `go get foo/bar` in the source folder to add the dependency to `go.mod` file.
To remove a dependency
- Edit your code and remove the import reference.
- Run `go mod tidy` in the source folder to remove dependency from `go.mod` file.
### What are the coding guidelines for console?
``console`` is fully conformant with Golang style.
Refer: [Effective Go](https://github.com/golang/go/wiki/CodeReviewComments) article from Golang project. If you observe
offending code, please feel free to send a pull request or ping us on [Slack](https://slack.min.io).
``console`` is fully conformant with Golang style. Refer: [Effective Go](https://github.com/golang/go/wiki/CodeReviewComments) article from Golang project. If you observe offending code, please feel free to send a pull request or ping us on [Slack](https://slack.min.io).

9141
CREDITS

File diff suppressed because it is too large Load Diff

View File

@@ -1,101 +1,3 @@
# Developing MinIO Console
The MinIO Console requires the [MinIO Server](https://github.com/minio/minio). For development purposes, you also need
to run both the MinIO Console web app and the MinIO Console server.
## Running MinIO Console server
Build the server in the main folder by running:
```
make
```
> Note: If it's the first time running the server, you might need to run `go mod tidy` to ensure you have all modules
> required.
> To start the server run:
```
CONSOLE_ACCESS_KEY=<your-access-key>
CONSOLE_SECRET_KEY=<your-secret-key>
CONSOLE_MINIO_SERVER=<minio-server-endpoint>
CONSOLE_DEV_MODE=on
./console server
```
## Running MinIO Console web app
Refer to `/web-app` [instructions](/web-app/README.md) to run the web app locally.
# Building with MinIO
To test console in its shipping format, you need to build it from the MinIO repository, the following step will guide
you to do that.
### 0. Building with UI Changes
If you are performing changes in the UI components of console and want to test inside the MinIO binary, you need to
build assets first.
In the console folder run
```shell
make assets
```
This will regenerate all the static assets that will be served by MinIO.
### 1. Clone the `MinIO` repository
In the parent folder of where you cloned this `console` repository, clone the MinIO Repository
```shell
git clone https://github.com/minio/minio.git
```
### 2. Update `go.mod` to use your local version
In the MinIO repository open `go.mod` and after the first `require()` directive add a `replace()` directive
```
...
)
replace (
github.com/minio/console => "../console"
)
require (
...
```
### 3. Build `MinIO`
Still in the MinIO folder, run
```shell
make build
```
# Testing on Kubernetes
If you want to test console on kubernetes, you can perform all the steps from `Building with MinIO`, but change `Step 3`
to the following:
```shell
TAG=miniodev/console:dev make docker
```
This will build a docker container image that can be used to test with your local kubernetes environment.
For example, if you are using kind:
```shell
kind load docker-image miniodev/console:dev
```
and then deploy any `Tenant` that uses this image
# LDAP authentication with Console
## Setup
@@ -113,8 +15,7 @@ $ docker cp console/docs/ldap/billy.ldif my-openldap-container:/container/servic
$ docker exec my-openldap-container ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin -f /container/service/slapd/assets/test/billy.ldif -H ldap://localhost
```
Query the ldap server to check the user billy was created correctly and got assigned to the consoleAdmin group, you
should get a list
Query the ldap server to check the user billy was created correctly and got assigned to the consoleAdmin group, you should get a list
containing ldap users and groups.
```
@@ -129,7 +30,7 @@ $ docker exec my-openldap-container ldapsearch -x -H ldap://localhost -b uid=bil
### Change the password for user billy
Set the new password for `billy` to `minio123` and enter `admin` as the default `LDAP Password`
Set the new password for `billy` to `minio123` and enter `admin` as the default `LDAP Password`
```
$ docker exec -it my-openldap-container /bin/bash
@@ -140,7 +41,6 @@ Enter LDAP Password:
```
### Add the consoleAdmin policy to user billy on MinIO
```
$ cat > consoleAdmin.json << EOF
{
@@ -166,8 +66,8 @@ $ cat > consoleAdmin.json << EOF
]
}
EOF
$ mc admin policy create myminio consoleAdmin consoleAdmin.json
$ mc admin policy attach myminio consoleAdmin --user="uid=billy,dc=example,dc=org"
$ mc admin policy add myminio consoleAdmin consoleAdmin.json
$ mc admin policy set myminio consoleAdmin user="uid=billy,dc=example,dc=org"
```
## Run MinIO

View File

@@ -1,19 +1,18 @@
ARG NODE_VERSION
FROM node:$NODE_VERSION as uilayer
FROM node:17 as uilayer
WORKDIR /app
COPY ./web-app/package.json ./
COPY ./web-app/yarn.lock ./
COPY ./portal-ui/package.json ./
COPY ./portal-ui/yarn.lock ./
RUN yarn install
COPY ./web-app .
COPY ./portal-ui .
RUN make build-static
USER node
FROM golang:1.19 as golayer
FROM golang:1.17 as golayer
RUN apt-get update -y && apt-get install -y ca-certificates
@@ -29,10 +28,10 @@ WORKDIR /go/src/github.com/minio/console/
ENV CGO_ENABLED=0
COPY --from=uilayer /app/build /go/src/github.com/minio/console/web-app/build
COPY --from=uilayer /app/build /go/src/github.com/minio/console/portal-ui/build
RUN go build --tags=kqueue,operator -ldflags "-w -s" -a -o console ./cmd/console
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.7
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.5
MAINTAINER MinIO Development "dev@min.io"
EXPOSE 9090

View File

@@ -1,13 +1,12 @@
ARG NODE_VERSION
FROM node:$NODE_VERSION as uilayer
FROM node:17 as uilayer
WORKDIR /app
COPY ./web-app/package.json ./
COPY ./web-app/yarn.lock ./
COPY ./portal-ui/package.json ./
COPY ./portal-ui/yarn.lock ./
RUN yarn install
COPY ./web-app .
COPY ./portal-ui .
RUN yarn install && make build-static

View File

@@ -1,11 +1,10 @@
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.2 as build
RUN microdnf update --nodocs && microdnf install ca-certificates --nodocs
FROM registry.access.redhat.com/ubi9/ubi-micro:9.2
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.5
ARG TAG
COPY CREDITS /licenses/CREDITS
COPY LICENSE /licenses/LICENSE
LABEL name="MinIO" \
vendor="MinIO Inc <dev@min.io>" \
maintainer="MinIO Inc <dev@min.io>" \
@@ -14,14 +13,11 @@ LABEL name="MinIO" \
summary="A graphical user interface for MinIO" \
description="MinIO object storage is fundamentally different. Designed for performance and the S3 API, it is 100% open-source. MinIO is ideal for large, private cloud environments with stringent security requirements and delivers mission-critical availability across a diverse range of workloads."
# On RHEL the certificate bundle is located at:
# - /etc/pki/tls/certs/ca-bundle.crt (RHEL 6)
# - /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem (RHEL 7)
COPY --from=build /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /etc/pki/ca-trust/extracted/pem/
COPY LICENSE /LICENSE
COPY CREDITS /CREDITS
COPY console /console
RUN \
microdnf update --nodocs && \
microdnf install ca-certificates --nodocs
EXPOSE 9090
COPY console /console
ENTRYPOINT ["/console"]

198
Makefile
View File

@@ -5,25 +5,31 @@ BUILD_VERSION:=$(shell git describe --exact-match --tags $(git log -n1 --pretty=
BUILD_TIME:=$(shell date 2>/dev/null)
TAG ?= "minio/console:$(BUILD_VERSION)-dev"
MINIO_VERSION ?= "quay.io/minio/minio:latest"
TARGET_BUCKET ?= "target"
NODE_VERSION := $(shell cat .nvmrc)
default: console
.PHONY: console
console:
@echo "Building Console binary to './console'"
@(GO111MODULE=on CGO_ENABLED=0 go build -trimpath --tags=kqueue --ldflags "-s -w" -o console ./cmd/console)
@(GO111MODULE=on CGO_ENABLED=0 go build -trimpath --tags=kqueue,operator --ldflags "-s -w" -o console ./cmd/console)
k8sdev:
@docker build -t $(TAG) --build-arg build_version=$(BUILD_VERSION) --build-arg build_time='$(BUILD_TIME)' .
@kind load docker-image $(TAG)
@echo "Done, now restart your console deployment"
getdeps:
@mkdir -p ${GOPATH}/bin
@echo "Installing golangci-lint" && curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin
@which golangci-lint 1>/dev/null || (echo "Installing golangci-lint" && curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin v1.43.0)
verifiers: getdeps fmt lint
fmt:
@echo "Running $@ check"
@(env bash $(PWD)/verify-gofmt.sh)
@GO111MODULE=on gofmt -d restapi/
@GO111MODULE=on gofmt -d pkg/
@GO111MODULE=on gofmt -d cmd/
@GO111MODULE=on gofmt -d cluster/
crosscompile:
@(env bash $(PWD)/cross-compile.sh $(arg1))
@@ -33,59 +39,45 @@ lint:
@GO111MODULE=on ${GOPATH}/bin/golangci-lint cache clean
@GO111MODULE=on ${GOPATH}/bin/golangci-lint run --timeout=5m --config ./.golangci.yml
lint-fix: getdeps ## runs golangci-lint suite of linters with automatic fixes
@echo "Running $@ check"
@GO111MODULE=on ${GOPATH}/bin/golangci-lint run --timeout=5m --config ./.golangci.yml --fix
install: console
@echo "Installing console binary to '$(GOPATH)/bin/console'"
@mkdir -p $(GOPATH)/bin && cp -f $(PWD)/console $(GOPATH)/bin/console
@echo "Installation successful. To learn more, try \"console --help\"."
swagger-gen: clean-swagger swagger-console apply-gofmt
swagger-gen: clean-swagger swagger-console swagger-operator
@echo "Done Generating swagger server code from yaml"
apply-gofmt:
@echo "Applying gofmt to all generated an existing files"
@GO111MODULE=on gofmt -w .
clean-swagger:
@echo "cleaning"
@rm -rf models
@rm -rf api/operations
@rm -rf restapi/operations
@rm -rf operatorapi/operations
swagger-console:
@echo "Generating swagger server code from yaml"
@swagger generate server -A console --main-package=management --server-package=api --exclude-main -P models.Principal -f ./swagger.yml -r NOTICE
@echo "Generating typescript api"
@npx swagger-typescript-api -p ./swagger.yml -o ./web-app/src/api -n consoleApi.ts
@git restore api/server.go
@swagger generate server -A console --main-package=management --server-package=restapi --exclude-main -P models.Principal -f ./swagger-console.yml -r NOTICE
swagger-operator:
@echo "Generating swagger server code from yaml"
@swagger generate server -A operator --main-package=operator --server-package=operatorapi --exclude-main -P models.Principal -f ./swagger-operator.yml -r NOTICE
assets:
@(if [ -f "${NVM_DIR}/nvm.sh" ]; then \. "${NVM_DIR}/nvm.sh" && nvm install && nvm use && npm install -g yarn ; fi &&\
cd web-app; yarn install --prefer-offline; make build-static; yarn prettier --write . --loglevel warn; cd ..)
@(cd portal-ui; yarn install --prefer-offline; make build-static; yarn prettier --write . --loglevel warn; cd ..)
test-integration:
@(docker stop pgsqlcontainer || true)
@(docker stop minio || true)
@(docker stop minio2 || true)
@(docker network rm mynet123 || true)
@echo "create docker network to communicate containers MinIO & PostgreSQL"
@(docker network create --subnet=173.18.0.0/29 mynet123)
@echo "docker run with MinIO Version below:"
@echo $(MINIO_VERSION)
@echo "MinIO 1"
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 --net=mynet123 -d --name minio --rm -p 9000:9000 -p 9091:9091 -e MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw= $(MINIO_VERSION) server /data{1...4} --console-address ':9091' && sleep 5)
@echo "MinIO 2"
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 --net=mynet123 -d --name minio2 --rm -p 9001:9001 -p 9092:9092 -e MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw= $(MINIO_VERSION) server /data{1...4} --address ':9001' --console-address ':9092' && sleep 5)
@echo "Postgres"
@(docker run --net=mynet123 --ip=173.18.0.4 --name pgsqlcontainer --rm -p 5432:5432 -e POSTGRES_PASSWORD=password -d postgres && sleep 5)
@echo "execute test and get coverage for test-integration:"
@(cd integration && go test -coverpkg=../api -c -tags testrunmain . && mkdir -p coverage && ./integration.test -test.v -test.run "^Test*" -test.coverprofile=coverage/system.out)
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 --net=mynet123 -d --name minio --rm -p 9000:9000 -p 9001:9001 -e MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw= $(MINIO_VERSION) server /data{1...4} --console-address ':9001' && sleep 5)
@(docker run --net=mynet123 --ip=173.18.0.3 --name pgsqlcontainer --rm -p 5432:5432 -e POSTGRES_PASSWORD=password -d postgres && sleep 5)
@echo "execute test and get coverage"
@(cd integration && go test -coverpkg=../restapi -c -tags testrunmain . && mkdir -p coverage && ./integration.test -test.v -test.run "^Test*" -test.coverprofile=coverage/system.out)
@(docker stop pgsqlcontainer)
@(docker stop minio)
@(docker stop minio2)
@(docker network rm mynet123)
test-replication:
@@ -130,7 +122,7 @@ test-replication:
$(MINIO_VERSION) server /data{1...4} \
--address :9002 \
--console-address :6002)
@(cd replication && go test -coverpkg=../api -c -tags testrunmain . && mkdir -p coverage && ./replication.test -test.v -test.run "^Test*" -test.coverprofile=coverage/replication.out)
@(cd replication && go test -coverpkg=../restapi -c -tags testrunmain . && mkdir -p coverage && ./replication.test -test.v -test.run "^Test*" -test.coverprofile=coverage/replication.out)
@(docker stop minio || true)
@(docker stop minio1 || true)
@(docker stop minio2 || true)
@@ -139,25 +131,29 @@ test-replication:
test-sso-integration:
@echo "create the network in bridge mode to communicate all containers"
@(docker network create my-net)
@echo "run openldap container using MinIO Image: quay.io/minio/openldap:latest"
@echo "execute latest keycloak container"
@(docker run \
-e LDAP_ORGANIZATION="MinIO Inc" \
-e LDAP_DOMAIN="min.io" \
-e LDAP_ADMIN_PASSWORD="admin" \
--network my-net \
-p 389:389 \
-p 636:636 \
--name openldap \
--detach quay.io/minio/openldap:latest)
@echo "Run Dex container using MinIO Image: quay.io/minio/dex:latest"
--rm \
--name keycloak-container \
--network my-net \
-p 8080:8080 \
-e KEYCLOAK_USER=admin \
-e KEYCLOAK_PASSWORD=admin jboss/keycloak:latest -b 0.0.0.0 -bprivate 127.0.0.1 &)
@echo "wait 60 sec until keycloak is listenning on port, then go for minio server"
@(sleep 60)
@echo "execute keycloak-config-cli container to configure keycloak for Single Sign On with MinIO"
@(docker run \
-e DEX_ISSUER=http://dex:5556/dex \
-e DEX_CLIENT_REDIRECT_URI=http://127.0.0.1:9090/oauth_callback \
-e DEX_LDAP_SERVER=openldap:389 \
--network my-net \
-p 5556:5556 \
--name dex \
--detach quay.io/minio/dex:latest)
--rm \
--network my-net \
--name keycloak-config-cli \
-e KEYCLOAK_URL=http://keycloak-container:8080/auth \
-e KEYCLOAK_USER="admin" \
-e KEYCLOAK_PASSWORD="admin" \
-e KEYCLOAK_AVAILABILITYCHECK_ENABLED=true \
-e KEYCLOAK_AVAILABILITYCHECK_TIMEOUT=120s \
-e IMPORT_FILES_LOCATIONS='/config/realm-export.json' \
-v /home/runner/work/console/console/sso-integration/config:/config \
adorsys/keycloak-config-cli:latest)
@echo "running minio server"
@(docker run \
-v /data1 -v /data2 -v /data3 -v /data4 \
@@ -167,114 +163,72 @@ test-sso-integration:
--rm \
-p 9000:9000 \
-p 9001:9001 \
-e MINIO_IDENTITY_OPENID_CLIENT_ID="minio-client-app" \
-e MINIO_IDENTITY_OPENID_CLIENT_SECRET="minio-client-app-secret" \
-e MINIO_IDENTITY_OPENID_CLAIM_NAME=name \
-e MINIO_IDENTITY_OPENID_CONFIG_URL=http://dex:5556/dex/.well-known/openid-configuration \
-e MINIO_IDENTITY_OPENID_REDIRECT_URI=http://127.0.0.1:9090/oauth_callback \
-e MINIO_IDENTITY_OPENID_CLIENT_SECRET=0nfJuqIt0iPnRIUJkvetve5l38C6gi9W \
-e MINIO_ROOT_USER=minio \
-e MINIO_ROOT_PASSWORD=minio123 $(MINIO_VERSION) server /data{1...4} --address :9000 --console-address :9001)
@echo "run mc commands to set the policy"
@(sleep 60)
@echo "run mc commands"
@(docker run --name minio-client --network my-net -dit --entrypoint=/bin/sh minio/mc)
@(docker exec minio-client mc alias set myminio/ http://minio:9000 minio minio123)
@echo "adding policy to Dillon Harper to be able to login:"
@(cd sso-integration && docker cp allaccess.json minio-client:/ && docker exec minio-client mc admin policy create myminio "Dillon Harper" allaccess.json)
@(docker exec minio-client mc admin config set myminio identity_openid config_url="http://keycloak-container:8080/auth/realms/myrealm/.well-known/openid-configuration" client_id="account")
@(docker exec minio-client mc admin service restart myminio)
@echo "starting bash script"
@(env bash $(PWD)/sso-integration/set-sso.sh)
@echo "add python module"
@(pip3 install bs4)
@echo "install jq"
@(sudo apt install jq)
@echo "Executing the test:"
@(cd sso-integration && go test -coverpkg=../api -c -tags testrunmain . && mkdir -p coverage && ./sso-integration.test -test.v -test.run "^Test*" -test.coverprofile=coverage/sso-system.out)
@(cd sso-integration && go test -coverpkg=../restapi -c -tags testrunmain . && mkdir -p coverage && ./sso-integration.test -test.v -test.run "^Test*" -test.coverprofile=coverage/sso-system.out)
test-operator-integration:
@(echo "Start cd operator-integration && go test:")
@(pwd)
@(cd operator-integration && go test -coverpkg=../operatorapi -c -tags testrunmain . && mkdir -p coverage && ./operator-integration.test -test.v -test.run "^Test*" -test.coverprofile=coverage/operator-api.out)
test-operator:
@(env bash $(PWD)/portal-ui/tests/scripts/operator.sh)
@(docker stop minio)
test-permissions-1:
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-1/")
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-1/")
@(docker stop minio)
test-permissions-2:
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-2/")
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-2/")
@(docker stop minio)
test-permissions-3:
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-3/")
@(docker stop minio)
test-permissions-4:
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-4/")
@(docker stop minio)
test-permissions-5:
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-5/")
@(docker stop minio)
test-permissions-6:
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-6/")
@(docker stop minio)
test-permissions-7:
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-7/")
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-3/")
@(docker stop minio)
test-apply-permissions:
@(env bash $(PWD)/web-app/tests/scripts/initialize-env.sh)
@(env bash $(PWD)/portal-ui/tests/scripts/initialize-env.sh)
test-start-docker-minio:
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
initialize-operator:
@echo "Done initializing operator test"
initialize-permissions: test-start-docker-minio test-apply-permissions
@echo "Done initializing permissions test"
cleanup-permissions:
@(env bash $(PWD)/web-app/tests/scripts/cleanup-env.sh)
@(env bash $(PWD)/portal-ui/tests/scripts/cleanup-env.sh)
@(docker stop minio)
initialize-docker-network:
@(docker network create test-network)
test-start-docker-minio-w-redirect-url: initialize-docker-network
@(docker run \
-e MINIO_BROWSER_REDIRECT_URL='http://localhost:8000/console/subpath/' \
-e MINIO_SERVER_URL='http://localhost:9000' \
-v /data1 -v /data2 -v /data3 -v /data4 \
-d --network host --name minio --rm\
quay.io/minio/minio:latest server /data{1...4})
test-start-docker-nginx-w-subpath:
@(docker run \
--network host \
-d --rm \
--add-host=host.docker.internal:host-gateway \
-v ./web-app/tests/subpath-nginx/nginx.conf:/etc/nginx/nginx.conf \
--name test-nginx nginx)
test-initialize-minio-nginx: test-start-docker-minio-w-redirect-url test-start-docker-nginx-w-subpath
cleanup-minio-nginx:
@(docker stop minio test-nginx & docker network rm test-network)
# https://stackoverflow.com/questions/19200235/golang-tests-in-sub-directory
# Note: go test ./... will run tests on the current folder and all subfolders.
# This is needed because tests can be in the folder or sub-folder(s), let's include them all please!.
test:
@echo "execute test and get coverage"
@(cd api && mkdir -p coverage && GO111MODULE=on go test ./... -test.v -coverprofile=coverage/coverage.out)
@(cd restapi && mkdir coverage && GO111MODULE=on go test -test.v -coverprofile=coverage/coverage.out)
# https://stackoverflow.com/questions/19200235/golang-tests-in-sub-directory
# Note: go test ./... will run tests on the current folder and all subfolders.
# This is since tests in pkg folder are in subfolders and were not executed.
test-pkg:
@echo "execute test and get coverage"
@(cd pkg && mkdir -p coverage && GO111MODULE=on go test ./... -test.v -coverprofile=coverage/coverage-pkg.out)
@(cd pkg && mkdir coverage && GO111MODULE=on go test -test.v -coverprofile=coverage/coverage-pkg.out)
coverage:
@(GO111MODULE=on go test -v -coverprofile=coverage.out github.com/minio/console/api/... && go tool cover -html=coverage.out && open coverage.html)
@(GO111MODULE=on go test -v -coverprofile=coverage.out github.com/minio/console/restapi/... && go tool cover -html=coverage.out && open coverage.html)
clean:
@echo "Cleaning up all the generated files"
@@ -283,10 +237,12 @@ clean:
@rm -vf console
docker:
@docker buildx build --output=type=docker --platform linux/amd64 -t $(TAG) --build-arg build_version=$(BUILD_VERSION) --build-arg build_time='$(BUILD_TIME)' --build-arg NODE_VERSION='$(NODE_VERSION)' .
@docker buildx build --output=type=docker --platform linux/amd64 -t $(TAG) --build-arg build_version=$(BUILD_VERSION) --build-arg build_time='$(BUILD_TIME)' .
release: swagger-gen
@echo "Generating Release: $(RELEASE)"
@make assets
@yq -i e '.spec.template.spec.containers[0].image |= "minio/console:$(RELEASE)"' k8s/operator-console/base/console-deployment.yaml
@yq -i e 'select(.kind == "Deployment").spec.template.spec.containers[0].image |= "minio/console:$(RELEASE)"' k8s/operator-console/standalone/console-deployment.yaml
@git add -u .
@git add web-app/build/
@git add portal-ui/build/

2
NOTICE
View File

@@ -1,5 +1,5 @@
This file is part of MinIO Console Server
Copyright (c) 2023 MinIO, Inc.
Copyright (c) 2022 MinIO, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by

136
README.md
View File

@@ -4,38 +4,57 @@
A graphical user interface for [MinIO](https://github.com/minio/minio)
| Object Browser | Dashboard | Creating a bucket |
|------------------------------------|-------------------------------|-------------------------------|
| ![Object Browser](images/pic3.png) | ![Dashboard](images/pic1.png) | ![Dashboard](images/pic2.png) |
| Dashboard | Creating a bucket |
| ------------- | ------------- |
| ![Dashboard](images/pic1.png) | ![Dashboard](images/pic2.png) |
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
**Table of Contents**
- [MinIO Console](#minio-console)
- [Install](#install)
- [Build from source](#build-from-source)
- [Setup](#setup)
- [1. Create a user `console` using `mc`](#1-create-a-user-console-using-mc)
- [2. Create a policy for `console` with admin access to all resources (for testing)](#2-create-a-policy-for-console-with-admin-access-to-all-resources-for-testing)
- [3. Set the policy for the new `console` user](#3-set-the-policy-for-the-new-console-user)
- [Start Console service:](#start-console-service)
- [Start Console service with TLS:](#start-console-service-with-tls)
- [Connect Console to a Minio using TLS and a self-signed certificate](#connect-console-to-a-minio-using-tls-and-a-self-signed-certificate)
- [Install](#install)
- [Binary Releases](#binary-releases)
- [Docker](#docker)
- [Build from source](#build-from-source)
- [Setup](#setup)
- [1. Create a user `console` using `mc`](#1-create-a-user-console-using-mc)
- [2. Create a policy for `console` with admin access to all resources (for testing)](#2-create-a-policy-for-console-with-admin-access-to-all-resources-for-testing)
- [3. Set the policy for the new `console` user](#3-set-the-policy-for-the-new-console-user)
- [Start Console service:](#start-console-service)
- [Start Console service with TLS:](#start-console-service-with-tls)
- [Connect Console to a Minio using TLS and a self-signed certificate](#connect-console-to-a-minio-using-tls-and-a-self-signed-certificate)
- [Contribute to console Project](#contribute-to-console-project)
<!-- markdown-toc end -->
## Install
MinIO Console is a library that provides a management and browser UI overlay for the MinIO Server.
The standalone binary installation path has been removed.
### Binary Releases
In case a Console standalone binary is needed, it can be generated by building this package from source as follows:
| OS | ARCH | Binary |
|:-------:|:-------:|:----------------------------------------------------------------------------------------------------:|
| Linux | amd64 | [linux-amd64](https://github.com/minio/console/releases/latest/download/console-linux-amd64) |
| Linux | arm64 | [linux-arm64](https://github.com/minio/console/releases/latest/download/console-linux-arm64) |
| Linux | ppc64le | [linux-ppc64le](https://github.com/minio/console/releases/latest/download/console-linux-ppc64le) |
| Linux | s390x | [linux-s390x](https://github.com/minio/console/releases/latest/download/console-linux-s390x) |
| Apple | amd64 | [darwin-amd64](https://github.com/minio/console/releases/latest/download/console-darwin-amd64) |
| Windows | amd64 | [windows-amd64](https://github.com/minio/console/releases/latest/download/console-windows-amd64.exe) |
You can also verify the binary with [minisign](https://jedisct1.github.io/minisign/) by downloading the corresponding [`.minisig`](https://github.com/minio/console/releases/latest) signature file. Then run:
```
minisign -Vm console-<OS>-<ARCH> -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
```
### Docker
Pull the latest release via:
```
docker pull minio/console
```
### Build from source
> You will need a working Go environment. Therefore, please follow [How to install Go](https://golang.org/doc/install).
> Minimum version required is go1.21
> Minimum version required is go1.17
```
go install github.com/minio/console/cmd/console@latest
@@ -84,64 +103,60 @@ EOF
```
```sh
mc admin policy create myminio/ consoleAdmin admin.json
mc admin policy add myminio/ consoleAdmin admin.json
```
### 3. Set the policy for the new `console` user
```sh
mc admin policy attach myminio consoleAdmin --user=console
mc admin policy set myminio consoleAdmin user=console
```
> NOTE: Additionally, you can create policies to limit the privileges for other `console` users, for example, if you
> want the user to only have access to dashboard, buckets, notifications and watch page, the policy should look like
> this:
> NOTE: Additionally, you can create policies to limit the privileges for other `console` users, for example, if you want the user to only have access to dashboard, buckets, notifications and watch page, the policy should look like this:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"admin:ServerInfo"
],
"Effect": "Allow",
"Sid": ""
},
{
"Action": [
"s3:ListenBucketNotification",
"s3:PutBucketNotification",
"s3:GetBucketNotification",
"s3:ListMultipartUploadParts",
"s3:ListBucketMultipartUploads",
"s3:ListBucket",
"s3:HeadBucket",
"s3:GetObject",
"s3:GetBucketLocation",
"s3:AbortMultipartUpload",
"s3:CreateBucket",
"s3:PutObject",
"s3:DeleteObject",
"s3:DeleteBucket",
"s3:PutBucketPolicy",
"s3:DeleteBucketPolicy",
"s3:GetBucketPolicy"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::*"
],
"Sid": ""
}
]
"Version": "2012-10-17",
"Statement": [{
"Action": [
"admin:ServerInfo"
],
"Effect": "Allow",
"Sid": ""
},
{
"Action": [
"s3:ListenBucketNotification",
"s3:PutBucketNotification",
"s3:GetBucketNotification",
"s3:ListMultipartUploadParts",
"s3:ListBucketMultipartUploads",
"s3:ListBucket",
"s3:HeadBucket",
"s3:GetObject",
"s3:GetBucketLocation",
"s3:AbortMultipartUpload",
"s3:CreateBucket",
"s3:PutObject",
"s3:DeleteObject",
"s3:DeleteBucket",
"s3:PutBucketPolicy",
"s3:DeleteBucketPolicy",
"s3:GetBucketPolicy"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::*"
],
"Sid": ""
}
]
}
```
## Start Console service:
Before running console service, following environment settings must be supplied
```sh
# Salt to encrypt JWT payload
export CONSOLE_PBKDF_PASSPHRASE=SECRET
@@ -154,7 +169,6 @@ export CONSOLE_MINIO_SERVER=http://localhost:9000
```
Now start the console service.
```
./console server
2021-01-19 02:36:08.893735 I | 2021/01/19 02:36:08 server.go:129: Serving console at http://localhost:9090
@@ -175,7 +189,6 @@ Copy your `public.crt` and `private.key` to `~/.console/certs`, then:
For advanced users, `console` has support for multiple certificates to service clients through multiple domains.
Following tree structure is expected for supporting multiple domains:
```sh
certs/
@@ -206,5 +219,4 @@ export CONSOLE_MINIO_SERVER=https://localhost:9000
You can verify that the apis work by doing the request on `localhost:9090/api/v1/...`
# Contribute to console Project
Please follow console [Contributor's Guide](https://github.com/minio/console/blob/master/CONTRIBUTING.md)

View File

@@ -18,10 +18,9 @@ you need access credentials for a successful exploit).
If you have not received a reply to your email within 48 hours or you have not heard from the security team
for the past five days please contact the security team directly:
- Primary security coordinator: daniel@min.io
- Secondary coordinator: security@min.io
- If you receive no response: dev@min.io
- Primary security coordinator: lenin@min.io
- Secondary coordinator: security@min.io
- If you receive no response: dev@min.io
### Disclosure Process

View File

@@ -1,97 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"errors"
"fmt"
"net/http"
"strings"
"testing"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations/system"
"github.com/minio/console/models"
"github.com/go-openapi/loads"
"github.com/minio/console/api/operations"
"github.com/minio/madmin-go/v3"
asrt "github.com/stretchr/testify/assert"
)
func TestArnsList(t *testing.T) {
assert := asrt.New(t)
adminClient := AdminClientMock{}
// Test-1 : getArns() returns proper arn list
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{
SQSARN: []string{"uno"},
}, nil
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
arnsList, err := getArns(ctx, adminClient)
assert.NotNil(arnsList, "arn list was returned nil")
if arnsList != nil {
assert.Equal(len(arnsList.Arns), 1, "Incorrect arns count")
}
assert.Nil(err, "Error should have been nil")
// Test-2 : getArns(ctx) fails for whatever reason
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{}, errors.New("some reason")
}
arnsList, err = getArns(ctx, adminClient)
assert.Nil(arnsList, "arn list was not returned nil")
assert.NotNil(err, "An error should have been returned")
}
func TestRegisterAdminArnsHandlers(t *testing.T) {
assert := asrt.New(t)
swaggerSpec, err := loads.Embedded(SwaggerJSON, FlatSwaggerJSON)
if err != nil {
assert.Fail("Error")
}
api := operations.NewConsoleAPI(swaggerSpec)
api.SystemArnListHandler = nil
registerAdminArnsHandlers(api)
if api.SystemArnListHandler == nil {
assert.Fail("Assignment should happen")
} else {
fmt.Println("Function got assigned: ", api.SystemArnListHandler)
}
// To test error case in registerAdminArnsHandlers
request, _ := http.NewRequest(
"GET",
"http://localhost:9090/api/v1/buckets/",
nil,
)
ArnListParamsStruct := system.ArnListParams{
HTTPRequest: request,
}
modelsPrincipal := models.Principal{
STSAccessKeyID: "accesskey",
}
var value middleware.Responder = api.SystemArnListHandler.Handle(ArnListParamsStruct, &modelsPrincipal)
str := fmt.Sprintf("%#v", value)
fmt.Println("value: ", str)
assert.Equal(strings.Contains(str, "_statusCode:500"), true)
}

View File

@@ -1,402 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"io"
"time"
"github.com/minio/madmin-go/v3"
iampolicy "github.com/minio/pkg/v2/policy"
)
type AdminClientMock struct{}
var (
MinioServerInfoMock func(ctx context.Context) (madmin.InfoMessage, error)
minioChangePasswordMock func(ctx context.Context, accessKey, secretKey string) error
minioHelpConfigKVMock func(subSys, key string, envOnly bool) (madmin.Help, error)
minioGetConfigKVMock func(key string) ([]byte, error)
minioSetConfigKVMock func(kv string) (restart bool, err error)
minioDelConfigKVMock func(name string) (err error)
minioHelpConfigKVGlobalMock func(envOnly bool) (madmin.Help, error)
minioGetLogsMock func(ctx context.Context, node string, lineCnt int, logKind string) <-chan madmin.LogInfo
minioListGroupsMock func() ([]string, error)
minioUpdateGroupMembersMock func(madmin.GroupAddRemove) error
minioGetGroupDescriptionMock func(group string) (*madmin.GroupDesc, error)
minioSetGroupStatusMock func(group string, status madmin.GroupStatus) error
minioHealMock func(ctx context.Context, bucket, prefix string, healOpts madmin.HealOpts, clientToken string,
forceStart, forceStop bool) (healStart madmin.HealStartSuccess, healTaskStatus madmin.HealTaskStatus, err error)
minioServerHealthInfoMock func(ctx context.Context, healthDataTypes []madmin.HealthDataType, deadline time.Duration) (interface{}, string, error)
minioListPoliciesMock func() (map[string]*iampolicy.Policy, error)
minioGetPolicyMock func(name string) (*iampolicy.Policy, error)
minioRemovePolicyMock func(name string) error
minioAddPolicyMock func(name string, policy *iampolicy.Policy) error
minioSetPolicyMock func(policyName, entityName string, isGroup bool) error
minioStartProfiling func(profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error)
minioStopProfiling func() (io.ReadCloser, error)
minioServiceRestartMock func(ctx context.Context) error
getSiteReplicationInfo func(ctx context.Context) (*madmin.SiteReplicationInfo, error)
addSiteReplicationInfo func(ctx context.Context, sites []madmin.PeerSite) (*madmin.ReplicateAddStatus, error)
editSiteReplicationInfo func(ctx context.Context, site madmin.PeerInfo) (*madmin.ReplicateEditStatus, error)
deleteSiteReplicationInfoMock func(ctx context.Context, removeReq madmin.SRRemoveReq) (*madmin.ReplicateRemoveStatus, error)
getSiteReplicationStatus func(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error)
minioListTiersMock func(ctx context.Context) ([]*madmin.TierConfig, error)
minioTierStatsMock func(ctx context.Context) ([]madmin.TierInfo, error)
minioAddTiersMock func(ctx context.Context, tier *madmin.TierConfig) error
minioEditTiersMock func(ctx context.Context, tierName string, creds madmin.TierCreds) error
minioServiceTraceMock func(ctx context.Context, threshold int64, s3, internal, storage, os, errTrace bool) <-chan madmin.ServiceTraceInfo
minioListUsersMock func() (map[string]madmin.UserInfo, error)
minioAddUserMock func(accessKey, secreyKey string) error
minioRemoveUserMock func(accessKey string) error
minioGetUserInfoMock func(accessKey string) (madmin.UserInfo, error)
minioSetUserStatusMock func(accessKey string, status madmin.AccountStatus) error
minioAccountInfoMock func(ctx context.Context) (madmin.AccountInfo, error)
minioAddServiceAccountMock func(ctx context.Context, policy string, user string, accessKey string, secretKey string, description string, name string, expiry *time.Time, status string) (madmin.Credentials, error)
minioListServiceAccountsMock func(ctx context.Context, user string) (madmin.ListServiceAccountsResp, error)
minioDeleteServiceAccountMock func(ctx context.Context, serviceAccount string) error
minioInfoServiceAccountMock func(ctx context.Context, serviceAccount string) (madmin.InfoServiceAccountResp, error)
minioUpdateServiceAccountMock func(ctx context.Context, serviceAccount string, opts madmin.UpdateServiceAccountReq) error
minioGetLDAPPolicyEntitiesMock func(ctx context.Context, query madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error)
minioListRemoteBucketsMock func(ctx context.Context, bucket, arnType string) (targets []madmin.BucketTarget, err error)
minioGetRemoteBucketMock func(ctx context.Context, bucket, arnType string) (targets *madmin.BucketTarget, err error)
minioAddRemoteBucketMock func(ctx context.Context, bucket string, target *madmin.BucketTarget) (string, error)
)
func (ac AdminClientMock) serverInfo(ctx context.Context) (madmin.InfoMessage, error) {
return MinioServerInfoMock(ctx)
}
func (ac AdminClientMock) listRemoteBuckets(ctx context.Context, bucket, arnType string) (targets []madmin.BucketTarget, err error) {
return minioListRemoteBucketsMock(ctx, bucket, arnType)
}
func (ac AdminClientMock) getRemoteBucket(ctx context.Context, bucket, arnType string) (targets *madmin.BucketTarget, err error) {
return minioGetRemoteBucketMock(ctx, bucket, arnType)
}
func (ac AdminClientMock) removeRemoteBucket(_ context.Context, _, _ string) error {
return nil
}
func (ac AdminClientMock) addRemoteBucket(ctx context.Context, bucket string, target *madmin.BucketTarget) (string, error) {
return minioAddRemoteBucketMock(ctx, bucket, target)
}
func (ac AdminClientMock) changePassword(ctx context.Context, accessKey, secretKey string) error {
return minioChangePasswordMock(ctx, accessKey, secretKey)
}
func (ac AdminClientMock) speedtest(_ context.Context, _ madmin.SpeedtestOpts) (chan madmin.SpeedTestResult, error) {
return nil, nil
}
func (ac AdminClientMock) verifyTierStatus(_ context.Context, _ string) error {
return nil
}
// mock function helpConfigKV()
func (ac AdminClientMock) helpConfigKV(_ context.Context, subSys, key string, envOnly bool) (madmin.Help, error) {
return minioHelpConfigKVMock(subSys, key, envOnly)
}
// mock function getConfigKV()
func (ac AdminClientMock) getConfigKV(_ context.Context, name string) ([]byte, error) {
return minioGetConfigKVMock(name)
}
// mock function setConfigKV()
func (ac AdminClientMock) setConfigKV(_ context.Context, kv string) (restart bool, err error) {
return minioSetConfigKVMock(kv)
}
// mock function helpConfigKV()
func (ac AdminClientMock) helpConfigKVGlobal(_ context.Context, envOnly bool) (madmin.Help, error) {
return minioHelpConfigKVGlobalMock(envOnly)
}
func (ac AdminClientMock) delConfigKV(_ context.Context, name string) (err error) {
return minioDelConfigKVMock(name)
}
func (ac AdminClientMock) getLogs(ctx context.Context, node string, lineCnt int, logKind string) <-chan madmin.LogInfo {
return minioGetLogsMock(ctx, node, lineCnt, logKind)
}
func (ac AdminClientMock) listGroups(_ context.Context) ([]string, error) {
return minioListGroupsMock()
}
func (ac AdminClientMock) updateGroupMembers(_ context.Context, req madmin.GroupAddRemove) error {
return minioUpdateGroupMembersMock(req)
}
func (ac AdminClientMock) getGroupDescription(_ context.Context, group string) (*madmin.GroupDesc, error) {
return minioGetGroupDescriptionMock(group)
}
func (ac AdminClientMock) setGroupStatus(_ context.Context, group string, status madmin.GroupStatus) error {
return minioSetGroupStatusMock(group, status)
}
func (ac AdminClientMock) heal(ctx context.Context, bucket, prefix string, healOpts madmin.HealOpts, clientToken string,
forceStart, forceStop bool,
) (healStart madmin.HealStartSuccess, healTaskStatus madmin.HealTaskStatus, err error) {
return minioHealMock(ctx, bucket, prefix, healOpts, clientToken, forceStart, forceStop)
}
func (ac AdminClientMock) serverHealthInfo(ctx context.Context, healthDataTypes []madmin.HealthDataType, deadline time.Duration) (interface{}, string, error) {
return minioServerHealthInfoMock(ctx, healthDataTypes, deadline)
}
func (ac AdminClientMock) addOrUpdateIDPConfig(_ context.Context, _, _, _ string, _ bool) (restart bool, err error) {
return true, nil
}
func (ac AdminClientMock) listIDPConfig(_ context.Context, _ string) ([]madmin.IDPListItem, error) {
return []madmin.IDPListItem{{Name: "mock"}}, nil
}
func (ac AdminClientMock) deleteIDPConfig(_ context.Context, _, _ string) (restart bool, err error) {
return true, nil
}
func (ac AdminClientMock) getIDPConfig(_ context.Context, _, _ string) (c madmin.IDPConfig, err error) {
return madmin.IDPConfig{Info: []madmin.IDPCfgInfo{{Key: "mock", Value: "mock"}}}, nil
}
func (ac AdminClientMock) kmsStatus(_ context.Context) (madmin.KMSStatus, error) {
return madmin.KMSStatus{Name: "name", DefaultKeyID: "key", Endpoints: map[string]madmin.ItemState{"localhost": madmin.ItemState("online")}}, nil
}
func (ac AdminClientMock) kmsAPIs(_ context.Context) ([]madmin.KMSAPI, error) {
return []madmin.KMSAPI{{Method: "GET", Path: "/mock"}}, nil
}
func (ac AdminClientMock) kmsMetrics(_ context.Context) (*madmin.KMSMetrics, error) {
return &madmin.KMSMetrics{}, nil
}
func (ac AdminClientMock) kmsVersion(_ context.Context) (*madmin.KMSVersion, error) {
return &madmin.KMSVersion{Version: "test-version"}, nil
}
func (ac AdminClientMock) createKey(_ context.Context, _ string) error {
return nil
}
func (ac AdminClientMock) importKey(_ context.Context, _ string, _ []byte) error {
return nil
}
func (ac AdminClientMock) listKeys(_ context.Context, _ string) ([]madmin.KMSKeyInfo, error) {
return []madmin.KMSKeyInfo{{
Name: "name",
CreatedBy: "by",
}}, nil
}
func (ac AdminClientMock) keyStatus(_ context.Context, _ string) (*madmin.KMSKeyStatus, error) {
return &madmin.KMSKeyStatus{KeyID: "key"}, nil
}
func (ac AdminClientMock) deleteKey(_ context.Context, _ string) error {
return nil
}
func (ac AdminClientMock) setKMSPolicy(_ context.Context, _ string, _ []byte) error {
return nil
}
func (ac AdminClientMock) assignPolicy(_ context.Context, _ string, _ []byte) error {
return nil
}
func (ac AdminClientMock) describePolicy(_ context.Context, _ string) (*madmin.KMSDescribePolicy, error) {
return &madmin.KMSDescribePolicy{Name: "name"}, nil
}
func (ac AdminClientMock) getKMSPolicy(_ context.Context, _ string) (*madmin.KMSPolicy, error) {
return &madmin.KMSPolicy{Allow: []string{""}, Deny: []string{""}}, nil
}
func (ac AdminClientMock) listKMSPolicies(_ context.Context, _ string) ([]madmin.KMSPolicyInfo, error) {
return []madmin.KMSPolicyInfo{{
Name: "name",
CreatedBy: "by",
}}, nil
}
func (ac AdminClientMock) deletePolicy(_ context.Context, _ string) error {
return nil
}
func (ac AdminClientMock) describeIdentity(_ context.Context, _ string) (*madmin.KMSDescribeIdentity, error) {
return &madmin.KMSDescribeIdentity{}, nil
}
func (ac AdminClientMock) describeSelfIdentity(_ context.Context) (*madmin.KMSDescribeSelfIdentity, error) {
return &madmin.KMSDescribeSelfIdentity{
Policy: &madmin.KMSPolicy{Allow: []string{}, Deny: []string{}},
}, nil
}
func (ac AdminClientMock) deleteIdentity(_ context.Context, _ string) error {
return nil
}
func (ac AdminClientMock) listIdentities(_ context.Context, _ string) ([]madmin.KMSIdentityInfo, error) {
return []madmin.KMSIdentityInfo{{Identity: "identity"}}, nil
}
func (ac AdminClientMock) listPolicies(_ context.Context) (map[string]*iampolicy.Policy, error) {
return minioListPoliciesMock()
}
func (ac AdminClientMock) getPolicy(_ context.Context, name string) (*iampolicy.Policy, error) {
return minioGetPolicyMock(name)
}
func (ac AdminClientMock) removePolicy(_ context.Context, name string) error {
return minioRemovePolicyMock(name)
}
func (ac AdminClientMock) addPolicy(_ context.Context, name string, policy *iampolicy.Policy) error {
return minioAddPolicyMock(name, policy)
}
func (ac AdminClientMock) setPolicy(_ context.Context, policyName, entityName string, isGroup bool) error {
return minioSetPolicyMock(policyName, entityName, isGroup)
}
// mock function for startProfiling()
func (ac AdminClientMock) startProfiling(_ context.Context, profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
return minioStartProfiling(profiler)
}
// mock function for stopProfiling()
func (ac AdminClientMock) stopProfiling(_ context.Context) (io.ReadCloser, error) {
return minioStopProfiling()
}
// mock function of serviceRestart()
func (ac AdminClientMock) serviceRestart(ctx context.Context) error {
return minioServiceRestartMock(ctx)
}
func (ac AdminClientMock) getSiteReplicationInfo(ctx context.Context) (*madmin.SiteReplicationInfo, error) {
return getSiteReplicationInfo(ctx)
}
func (ac AdminClientMock) addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite, _ madmin.SRAddOptions) (*madmin.ReplicateAddStatus, error) {
return addSiteReplicationInfo(ctx, sites)
}
func (ac AdminClientMock) editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo, _ madmin.SREditOptions) (*madmin.ReplicateEditStatus, error) {
return editSiteReplicationInfo(ctx, site)
}
func (ac AdminClientMock) deleteSiteReplicationInfo(ctx context.Context, removeReq madmin.SRRemoveReq) (*madmin.ReplicateRemoveStatus, error) {
return deleteSiteReplicationInfoMock(ctx, removeReq)
}
func (ac AdminClientMock) getSiteReplicationStatus(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error) {
return getSiteReplicationStatus(ctx, params)
}
func (ac AdminClientMock) listTiers(ctx context.Context) ([]*madmin.TierConfig, error) {
return minioListTiersMock(ctx)
}
func (ac AdminClientMock) tierStats(ctx context.Context) ([]madmin.TierInfo, error) {
return minioTierStatsMock(ctx)
}
func (ac AdminClientMock) addTier(ctx context.Context, tier *madmin.TierConfig) error {
return minioAddTiersMock(ctx, tier)
}
func (ac AdminClientMock) editTierCreds(ctx context.Context, tierName string, creds madmin.TierCreds) error {
return minioEditTiersMock(ctx, tierName, creds)
}
func (ac AdminClientMock) serviceTrace(ctx context.Context, threshold int64, s3, internal, storage, os, errTrace bool) <-chan madmin.ServiceTraceInfo {
return minioServiceTraceMock(ctx, threshold, s3, internal, storage, os, errTrace)
}
func (ac AdminClientMock) listUsers(_ context.Context) (map[string]madmin.UserInfo, error) {
return minioListUsersMock()
}
func (ac AdminClientMock) addUser(_ context.Context, accessKey, secretKey string) error {
return minioAddUserMock(accessKey, secretKey)
}
func (ac AdminClientMock) removeUser(_ context.Context, accessKey string) error {
return minioRemoveUserMock(accessKey)
}
func (ac AdminClientMock) getUserInfo(_ context.Context, accessKey string) (madmin.UserInfo, error) {
return minioGetUserInfoMock(accessKey)
}
func (ac AdminClientMock) setUserStatus(_ context.Context, accessKey string, status madmin.AccountStatus) error {
return minioSetUserStatusMock(accessKey, status)
}
func (ac AdminClientMock) AccountInfo(ctx context.Context) (madmin.AccountInfo, error) {
return minioAccountInfoMock(ctx)
}
func (ac AdminClientMock) addServiceAccount(ctx context.Context, policy string, user string, accessKey string, secretKey string, description string, name string, expiry *time.Time, status string) (madmin.Credentials, error) {
return minioAddServiceAccountMock(ctx, policy, user, accessKey, secretKey, description, name, expiry, status)
}
func (ac AdminClientMock) listServiceAccounts(ctx context.Context, user string) (madmin.ListServiceAccountsResp, error) {
return minioListServiceAccountsMock(ctx, user)
}
func (ac AdminClientMock) deleteServiceAccount(ctx context.Context, serviceAccount string) error {
return minioDeleteServiceAccountMock(ctx, serviceAccount)
}
func (ac AdminClientMock) infoServiceAccount(ctx context.Context, serviceAccount string) (madmin.InfoServiceAccountResp, error) {
return minioInfoServiceAccountMock(ctx, serviceAccount)
}
func (ac AdminClientMock) updateServiceAccount(ctx context.Context, serviceAccount string, opts madmin.UpdateServiceAccountReq) error {
return minioUpdateServiceAccountMock(ctx, serviceAccount, opts)
}
func (ac AdminClientMock) getLDAPPolicyEntities(ctx context.Context, query madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error) {
return minioGetLDAPPolicyEntitiesMock(ctx, query)
}

View File

@@ -1,316 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"encoding/base64"
"fmt"
"strings"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/swag"
"github.com/minio/console/api/operations"
"github.com/minio/console/models"
madmin "github.com/minio/madmin-go/v3"
cfgApi "github.com/minio/console/api/operations/configuration"
)
func registerConfigHandlers(api *operations.ConsoleAPI) {
// List Configurations
api.ConfigurationListConfigHandler = cfgApi.ListConfigHandlerFunc(func(params cfgApi.ListConfigParams, session *models.Principal) middleware.Responder {
configListResp, err := getListConfigResponse(session, params)
if err != nil {
return cfgApi.NewListConfigDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewListConfigOK().WithPayload(configListResp)
})
// Configuration Info
api.ConfigurationConfigInfoHandler = cfgApi.ConfigInfoHandlerFunc(func(params cfgApi.ConfigInfoParams, session *models.Principal) middleware.Responder {
config, err := getConfigResponse(session, params)
if err != nil {
return cfgApi.NewConfigInfoDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewConfigInfoOK().WithPayload(config)
})
// Set Configuration
api.ConfigurationSetConfigHandler = cfgApi.SetConfigHandlerFunc(func(params cfgApi.SetConfigParams, session *models.Principal) middleware.Responder {
resp, err := setConfigResponse(session, params)
if err != nil {
return cfgApi.NewSetConfigDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewSetConfigOK().WithPayload(resp)
})
// Reset Configuration
api.ConfigurationResetConfigHandler = cfgApi.ResetConfigHandlerFunc(func(params cfgApi.ResetConfigParams, session *models.Principal) middleware.Responder {
resp, err := resetConfigResponse(session, params)
if err != nil {
return cfgApi.NewResetConfigDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewResetConfigOK().WithPayload(resp)
})
// Export Configuration as base64 string.
api.ConfigurationExportConfigHandler = cfgApi.ExportConfigHandlerFunc(func(params cfgApi.ExportConfigParams, session *models.Principal) middleware.Responder {
resp, err := exportConfigResponse(session, params)
if err != nil {
return cfgApi.NewExportConfigDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewExportConfigOK().WithPayload(resp)
})
api.ConfigurationPostConfigsImportHandler = cfgApi.PostConfigsImportHandlerFunc(func(params cfgApi.PostConfigsImportParams, session *models.Principal) middleware.Responder {
_, err := importConfigResponse(session, params)
if err != nil {
return cfgApi.NewPostConfigsImportDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewPostConfigsImportDefault(200)
})
}
// listConfig gets all configurations' names and their descriptions
func listConfig(client MinioAdmin) ([]*models.ConfigDescription, error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
configKeysHelp, err := client.helpConfigKV(ctx, "", "", false)
if err != nil {
return nil, err
}
var configDescs []*models.ConfigDescription
for _, c := range configKeysHelp.KeysHelp {
desc := &models.ConfigDescription{
Key: c.Key,
Description: c.Description,
}
configDescs = append(configDescs, desc)
}
return configDescs, nil
}
// getListConfigResponse performs listConfig() and serializes it to the handler's output
func getListConfigResponse(session *models.Principal, params cfgApi.ListConfigParams) (*models.ListConfigResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
configDescs, err := listConfig(adminClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
listGroupsResponse := &models.ListConfigResponse{
Configurations: configDescs,
Total: int64(len(configDescs)),
}
return listGroupsResponse, nil
}
// getConfig gets the key values for a defined configuration.
func getConfig(ctx context.Context, client MinioAdmin, name string) ([]*models.Configuration, error) {
configBytes, err := client.getConfigKV(ctx, name)
if err != nil {
return nil, err
}
subSysConfigs, err := madmin.ParseServerConfigOutput(string(configBytes))
if err != nil {
return nil, err
}
var configSubSysList []*models.Configuration
for _, scfg := range subSysConfigs {
if !madmin.SubSystems.Contains(scfg.SubSystem) {
return nil, fmt.Errorf("no sub-systems found")
}
var confkv []*models.ConfigurationKV
for _, kv := range scfg.KV {
var envOverride *models.EnvOverride
if kv.EnvOverride != nil {
envOverride = &models.EnvOverride{
Name: kv.EnvOverride.Name,
Value: kv.EnvOverride.Value,
}
}
confkv = append(confkv, &models.ConfigurationKV{Key: kv.Key, Value: kv.Value, EnvOverride: envOverride})
}
if len(confkv) == 0 {
continue
}
var fullConfigName string
if scfg.Target == "" {
fullConfigName = scfg.SubSystem
} else {
fullConfigName = scfg.SubSystem + ":" + scfg.Target
}
configSubSysList = append(configSubSysList, &models.Configuration{KeyValues: confkv, Name: fullConfigName})
}
return configSubSysList, nil
}
// getConfigResponse performs getConfig() and serializes it to the handler's output
func getConfigResponse(session *models.Principal, params cfgApi.ConfigInfoParams) ([]*models.Configuration, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
configurations, err := getConfig(ctx, adminClient, params.Name)
if err != nil {
errorVal := ErrorWithContext(ctx, err)
minioError := madmin.ToErrorResponse(err)
if minioError.Code == "XMinioConfigError" {
errorVal.Code = 404
}
return nil, errorVal
}
return configurations, nil
}
// setConfig sets a configuration with the defined key values
func setConfig(ctx context.Context, client MinioAdmin, configName *string, kvs []*models.ConfigurationKV) (restart bool, err error) {
config := buildConfig(configName, kvs)
restart, err = client.setConfigKV(ctx, *config)
if err != nil {
return false, err
}
return restart, nil
}
func setConfigWithARNAccountID(ctx context.Context, client MinioAdmin, configName *string, kvs []*models.ConfigurationKV, arnAccountID string) (restart bool, err error) {
// if arnAccountID is not empty the configuration will be treated as a notification target
// arnAccountID will be used as an identifier for that specific target
// docs: https://min.io/docs/minio/linux/administration/monitoring/bucket-notifications.html
if arnAccountID != "" {
configName = swag.String(fmt.Sprintf("%s:%s", *configName, arnAccountID))
}
return setConfig(ctx, client, configName, kvs)
}
// buildConfig builds a concatenated string including name and keyvalues
// e.g. `region name=us-west-1`
func buildConfig(configName *string, kvs []*models.ConfigurationKV) *string {
var builder strings.Builder
builder.WriteString(*configName)
for _, kv := range kvs {
key := strings.TrimSpace(kv.Key)
if key == "" {
continue
}
builder.WriteString(" ")
builder.WriteString(key)
builder.WriteString("=")
// All newlines must be converted to ','
builder.WriteString(strings.ReplaceAll(strings.TrimSpace(fmt.Sprintf("\"%s\"", kv.Value)), "\n", ","))
}
config := builder.String()
return &config
}
// setConfigResponse implements setConfig() to be used by handler
func setConfigResponse(session *models.Principal, params cfgApi.SetConfigParams) (*models.SetConfigResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
configName := params.Name
needsRestart, err := setConfigWithARNAccountID(ctx, adminClient, &configName, params.Body.KeyValues, params.Body.ArnResourceID)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.SetConfigResponse{Restart: needsRestart}, nil
}
func resetConfig(ctx context.Context, client MinioAdmin, configName *string) (err error) {
err = client.delConfigKV(ctx, *configName)
return err
}
// resetConfigResponse implements resetConfig() to be used by handler
func resetConfigResponse(session *models.Principal, params cfgApi.ResetConfigParams) (*models.SetConfigResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
err = resetConfig(ctx, adminClient, &params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.SetConfigResponse{Restart: true}, nil
}
func exportConfigResponse(session *models.Principal, params cfgApi.ExportConfigParams) (*models.ConfigExportResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
configRes, err := mAdmin.GetConfig(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// may contain sensitive information so unpack only when required.
return &models.ConfigExportResponse{
Status: "success",
Value: base64.StdEncoding.EncodeToString(configRes),
}, nil
}
func importConfigResponse(session *models.Principal, params cfgApi.PostConfigsImportParams) (*cfgApi.PostConfigsImportDefault, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
file, _, err := params.HTTPRequest.FormFile("file")
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
defer file.Close()
err = mAdmin.SetConfig(ctx, file)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &cfgApi.PostConfigsImportDefault{}, nil
}

View File

@@ -1,172 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
b64 "encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"os"
"time"
"github.com/minio/console/pkg/logger"
"github.com/minio/console/pkg/utils"
subnet "github.com/minio/console/pkg/subnet"
"github.com/minio/madmin-go/v3"
mc "github.com/minio/mc/cmd"
"github.com/minio/websocket"
)
// startHealthInfo starts fetching mc.ServerHealthInfo and
// sends messages with the corresponding data on the websocket connection
func startHealthInfo(ctx context.Context, conn WSConn, client MinioAdmin, deadline *time.Duration) error {
if deadline == nil {
return errors.New("duration can't be nil on startHealthInfo")
}
// Fetch info of all servers (cluster or single server)
healthDataTypes := []madmin.HealthDataType{
madmin.HealthDataTypeMinioInfo,
madmin.HealthDataTypeMinioConfig,
madmin.HealthDataTypeSysCPU,
madmin.HealthDataTypeSysDriveHw,
madmin.HealthDataTypeSysDocker,
madmin.HealthDataTypeSysOsInfo,
madmin.HealthDataTypeSysLoad,
madmin.HealthDataTypeSysMem,
madmin.HealthDataTypeSysNet,
madmin.HealthDataTypeSysProcess,
}
var err error
// Fetch info of all servers (cluster or single server)
healthInfo, version, err := client.serverHealthInfo(ctx, healthDataTypes, *deadline)
if err != nil {
return err
}
compressedDiag, err := mc.TarGZHealthInfo(healthInfo, version)
if err != nil {
return err
}
encodedDiag := b64.StdEncoding.EncodeToString(compressedDiag)
type messageReport struct {
Encoded string `json:"encoded"`
ServerHealthInfo interface{} `json:"serverHealthInfo"`
SubnetResponse string `json:"subnetResponse"`
}
ctx = context.WithValue(ctx, utils.ContextClientIP, conn.remoteAddress())
err = sendHealthInfoToSubnet(ctx, healthInfo, client)
report := messageReport{
Encoded: encodedDiag,
ServerHealthInfo: healthInfo,
SubnetResponse: mc.SubnetBaseURL() + "/health",
}
if err != nil {
report.SubnetResponse = fmt.Sprintf("Error: %s", err.Error())
}
message, err := json.Marshal(report)
if err != nil {
return err
}
// Send Message through websocket connection
return conn.writeMessage(websocket.TextMessage, message)
}
// getHealthInfoOptionsFromReq gets duration for startHealthInfo request
// path come as : `/health-info?deadline=2h`
func getHealthInfoOptionsFromReq(req *http.Request) (*time.Duration, error) {
deadlineDuration, err := time.ParseDuration(req.FormValue("deadline"))
if err != nil {
return nil, err
}
return &deadlineDuration, nil
}
func updateMcGlobals(subnetTokenConfig subnet.LicenseTokenConfig) error {
mc.GlobalDevMode = getConsoleDevMode()
if len(subnetTokenConfig.Proxy) > 0 {
proxyURL, e := url.Parse(subnetTokenConfig.Proxy)
if e != nil {
return e
}
mc.GlobalSubnetProxyURL = proxyURL
}
return nil
}
func sendHealthInfoToSubnet(ctx context.Context, healthInfo interface{}, client MinioAdmin) error {
filename := fmt.Sprintf("health_%d.json.gz", time.Now().Unix())
subnetTokenConfig, e := GetSubnetKeyFromMinIOConfig(ctx, client)
if e != nil {
return e
}
e = updateMcGlobals(*subnetTokenConfig)
if e != nil {
return e
}
var apiKey string
if len(subnetTokenConfig.APIKey) != 0 {
apiKey = subnetTokenConfig.APIKey
} else {
apiKey, e = subnet.GetSubnetAPIKeyUsingLicense(subnetTokenConfig.License)
if e != nil {
return e
}
}
compressedHealthInfo, e := mc.TarGZHealthInfo(healthInfo, madmin.HealthInfoVersion)
if e != nil {
return e
}
e = os.WriteFile(filename, compressedHealthInfo, 0o666)
if e != nil {
return e
}
headers := mc.SubnetAPIKeyAuthHeaders(apiKey)
resp, e := (&mc.SubnetFileUploader{
FilePath: filename,
ReqURL: mc.SubnetUploadURL("health"),
Headers: headers,
DeleteAfterUpload: true,
}).UploadFileToSubnet()
if e != nil {
// file gets deleted only if upload is successful
// so we delete explicitly here as we already have the bytes
logger.LogIf(ctx, os.Remove(filename))
return e
}
type SubnetResponse struct {
LicenseV2 string `json:"license_v2,omitempty"`
APIKey string `json:"api_key,omitempty"`
}
var subnetResp SubnetResponse
e = json.Unmarshal([]byte(resp), &subnetResp)
if e != nil {
return e
}
return nil
}

View File

@@ -1,147 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"encoding/json"
"errors"
"reflect"
"testing"
"time"
madmin "github.com/minio/madmin-go/v3"
)
func Test_serverHealthInfo(t *testing.T) {
var testReceiver chan madmin.HealthInfo
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
client := AdminClientMock{}
mockWSConn := mockConn{}
deadlineDuration, _ := time.ParseDuration("1h")
type args struct {
deadline time.Duration
wsWriteMock func(messageType int, data []byte) error
mockMessages []madmin.HealthInfo
}
tests := []struct {
test string
args args
wantError error
}{
{
test: "Return simple health info, no errors",
args: args{
deadline: deadlineDuration,
mockMessages: []madmin.HealthInfo{{}, {}},
wsWriteMock: func(_ int, data []byte) error {
// mock connection WriteMessage() no error
// emulate that receiver gets the message written
var t madmin.HealthInfo
_ = json.Unmarshal(data, &t)
testReceiver <- t
return nil
},
},
wantError: nil,
},
{
test: "Return simple health info2, no errors",
args: args{
deadline: deadlineDuration,
mockMessages: []madmin.HealthInfo{{}},
wsWriteMock: func(_ int, data []byte) error {
// mock connection WriteMessage() no error
// emulate that receiver gets the message written
var t madmin.HealthInfo
_ = json.Unmarshal(data, &t)
testReceiver <- t
return nil
},
},
wantError: nil,
},
{
test: "Handle error on ws write",
args: args{
deadline: deadlineDuration,
mockMessages: []madmin.HealthInfo{{}},
wsWriteMock: func(_ int, data []byte) error {
// mock connection WriteMessage() no error
// emulate that receiver gets the message written
var t madmin.HealthInfo
_ = json.Unmarshal(data, &t)
return errors.New("error on write")
},
},
wantError: errors.New("error on write"),
},
{
test: "Handle error on health function",
args: args{
deadline: deadlineDuration,
mockMessages: []madmin.HealthInfo{
{
Error: "error on healthInfo",
},
},
wsWriteMock: func(_ int, data []byte) error {
// mock connection WriteMessage() no error
// emulate that receiver gets the message written
var t madmin.HealthInfo
_ = json.Unmarshal(data, &t)
return nil
},
},
wantError: nil,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.test, func(_ *testing.T) {
// make testReceiver channel
testReceiver = make(chan madmin.HealthInfo, len(tt.args.mockMessages))
// mock function same for all tests, changes mockMessages
minioServerHealthInfoMock = func(_ context.Context, _ []madmin.HealthDataType,
_ time.Duration,
) (interface{}, string, error) {
info := tt.args.mockMessages[0]
return info, madmin.HealthInfoVersion, nil
}
connWriteMessageMock = tt.args.wsWriteMock
err := startHealthInfo(ctx, mockWSConn, client, &deadlineDuration)
// close test mock channel
close(testReceiver)
// check that the TestReceiver got the same number of data from Console.
index := 0
for info := range testReceiver {
if !reflect.DeepEqual(info, tt.args.mockMessages[index]) {
t.Errorf("startHealthInfo() got: %v, want: %v", info, tt.args.mockMessages[index])
return
}
index++
}
if !reflect.DeepEqual(err, tt.wantError) {
t.Errorf("startHealthInfo() error: %v, wantError: %v", err, tt.wantError)
return
}
})
}
}

View File

@@ -1,290 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package api
import (
"context"
"fmt"
"time"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
"github.com/minio/console/api/operations/idp"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
)
var errInvalidIDPType = fmt.Errorf("IDP type must be one of %v", madmin.ValidIDPConfigTypes)
func registerIDPHandlers(api *operations.ConsoleAPI) {
api.IdpCreateConfigurationHandler = idp.CreateConfigurationHandlerFunc(func(params idp.CreateConfigurationParams, session *models.Principal) middleware.Responder {
response, err := createIDPConfigurationResponse(session, params)
if err != nil {
return idp.NewCreateConfigurationDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewCreateConfigurationCreated().WithPayload(response)
})
api.IdpUpdateConfigurationHandler = idp.UpdateConfigurationHandlerFunc(func(params idp.UpdateConfigurationParams, session *models.Principal) middleware.Responder {
response, err := updateIDPConfigurationResponse(session, params)
if err != nil {
return idp.NewUpdateConfigurationDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewUpdateConfigurationOK().WithPayload(response)
})
api.IdpListConfigurationsHandler = idp.ListConfigurationsHandlerFunc(func(params idp.ListConfigurationsParams, session *models.Principal) middleware.Responder {
response, err := listIDPConfigurationsResponse(session, params)
if err != nil {
return idp.NewListConfigurationsDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewListConfigurationsOK().WithPayload(response)
})
api.IdpDeleteConfigurationHandler = idp.DeleteConfigurationHandlerFunc(func(params idp.DeleteConfigurationParams, session *models.Principal) middleware.Responder {
response, err := deleteIDPConfigurationResponse(session, params)
if err != nil {
return idp.NewDeleteConfigurationDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewDeleteConfigurationOK().WithPayload(response)
})
api.IdpGetConfigurationHandler = idp.GetConfigurationHandlerFunc(func(params idp.GetConfigurationParams, session *models.Principal) middleware.Responder {
response, err := getIDPConfigurationsResponse(session, params)
if err != nil {
return idp.NewGetConfigurationDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewGetConfigurationOK().WithPayload(response)
})
api.IdpGetLDAPEntitiesHandler = idp.GetLDAPEntitiesHandlerFunc(func(params idp.GetLDAPEntitiesParams, session *models.Principal) middleware.Responder {
response, err := getLDAPEntitiesResponse(session, params)
if err != nil {
return idp.NewGetLDAPEntitiesDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewGetLDAPEntitiesOK().WithPayload(response)
})
}
func createIDPConfigurationResponse(session *models.Principal, params idp.CreateConfigurationParams) (*models.SetIDPResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
restart, err := createOrUpdateIDPConfig(ctx, params.Type, params.Body.Name, params.Body.Input, false, AdminClient{Client: mAdmin})
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.SetIDPResponse{Restart: restart}, nil
}
func updateIDPConfigurationResponse(session *models.Principal, params idp.UpdateConfigurationParams) (*models.SetIDPResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
restart, err := createOrUpdateIDPConfig(ctx, params.Type, params.Name, params.Body.Input, true, AdminClient{Client: mAdmin})
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.SetIDPResponse{Restart: restart}, nil
}
func createOrUpdateIDPConfig(ctx context.Context, idpType, name, input string, update bool, client MinioAdmin) (bool, error) {
if !madmin.ValidIDPConfigTypes.Contains(idpType) {
return false, errInvalidIDPType
}
restart, err := client.addOrUpdateIDPConfig(ctx, idpType, name, input, update)
if err != nil {
return false, err
}
return restart, nil
}
func listIDPConfigurationsResponse(session *models.Principal, params idp.ListConfigurationsParams) (*models.IdpListConfigurationsResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
results, err := listIDPConfigurations(ctx, params.Type, AdminClient{Client: mAdmin})
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.IdpListConfigurationsResponse{Results: results}, nil
}
func listIDPConfigurations(ctx context.Context, idpType string, client MinioAdmin) ([]*models.IdpServerConfiguration, error) {
if !madmin.ValidIDPConfigTypes.Contains(idpType) {
return nil, errInvalidIDPType
}
results, err := client.listIDPConfig(ctx, idpType)
if err != nil {
return nil, err
}
return parseIDPConfigurations(results), nil
}
func parseIDPConfigurations(configs []madmin.IDPListItem) (serverConfigs []*models.IdpServerConfiguration) {
for _, c := range configs {
serverConfigs = append(serverConfigs, &models.IdpServerConfiguration{
Name: c.Name,
Enabled: c.Enabled,
Type: c.Type,
})
}
return serverConfigs
}
func deleteIDPConfigurationResponse(session *models.Principal, params idp.DeleteConfigurationParams) (*models.SetIDPResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
restart, err := deleteIDPConfig(ctx, params.Type, params.Name, AdminClient{Client: mAdmin})
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.SetIDPResponse{Restart: restart}, nil
}
func deleteIDPConfig(ctx context.Context, idpType, name string, client MinioAdmin) (bool, error) {
if !madmin.ValidIDPConfigTypes.Contains(idpType) {
return false, errInvalidIDPType
}
restart, err := client.deleteIDPConfig(ctx, idpType, name)
if err != nil {
return false, err
}
return restart, nil
}
func getIDPConfigurationsResponse(session *models.Principal, params idp.GetConfigurationParams) (*models.IdpServerConfiguration, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
result, err := getIDPConfiguration(ctx, params.Type, params.Name, AdminClient{Client: mAdmin})
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return result, nil
}
func getIDPConfiguration(ctx context.Context, idpType, name string, client MinioAdmin) (*models.IdpServerConfiguration, error) {
if !madmin.ValidIDPConfigTypes.Contains(idpType) {
return nil, errInvalidIDPType
}
config, err := client.getIDPConfig(ctx, idpType, name)
if err != nil {
return nil, err
}
return &models.IdpServerConfiguration{
Name: config.Name,
Type: config.Type,
Info: parseIDPConfigurationsInfo(config.Info),
}, nil
}
func parseIDPConfigurationsInfo(infoList []madmin.IDPCfgInfo) (results []*models.IdpServerConfigurationInfo) {
for _, info := range infoList {
results = append(results, &models.IdpServerConfigurationInfo{
Key: info.Key,
Value: info.Value,
IsCfg: info.IsCfg,
IsEnv: info.IsEnv,
})
}
return results
}
func getLDAPEntitiesResponse(session *models.Principal, params idp.GetLDAPEntitiesParams) (*models.LdapEntities, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
result, err := getEntitiesResult(ctx, AdminClient{Client: mAdmin}, params.Body.Users, params.Body.Groups, params.Body.Policies)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return result, nil
}
func getEntitiesResult(ctx context.Context, client MinioAdmin, users, groups, policies []string) (*models.LdapEntities, error) {
entities, err := client.getLDAPPolicyEntities(ctx, madmin.PolicyEntitiesQuery{
Users: users,
Groups: groups,
Policy: policies,
})
if err != nil {
return nil, err
}
var result models.LdapEntities
var usersEntity []*models.LdapUserPolicyEntity
var groupsEntity []*models.LdapGroupPolicyEntity
var policiesEntity []*models.LdapPolicyEntity
result.Timestamp = entities.Timestamp.Format(time.RFC3339)
for _, userMapping := range entities.UserMappings {
mapItem := models.LdapUserPolicyEntity{
User: userMapping.User,
Policies: userMapping.Policies,
}
usersEntity = append(usersEntity, &mapItem)
}
result.Users = usersEntity
for _, groupsMapping := range entities.GroupMappings {
mapItem := models.LdapGroupPolicyEntity{
Group: groupsMapping.Group,
Policies: groupsMapping.Policies,
}
groupsEntity = append(groupsEntity, &mapItem)
}
result.Groups = groupsEntity
for _, policyMapping := range entities.PolicyMappings {
mapItem := models.LdapPolicyEntity{
Policy: policyMapping.Policy,
Users: policyMapping.Users,
Groups: policyMapping.Groups,
}
policiesEntity = append(policiesEntity, &mapItem)
}
result.Policies = policiesEntity
return &result, nil
}

View File

@@ -1,319 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/minio/madmin-go/v3"
"github.com/minio/console/api/operations"
"github.com/minio/console/api/operations/idp"
"github.com/minio/console/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type IDPTestSuite struct {
suite.Suite
assert *assert.Assertions
currentServer string
isServerSet bool
server *httptest.Server
adminClient AdminClientMock
}
func (suite *IDPTestSuite) SetupSuite() {
suite.assert = assert.New(suite.T())
suite.adminClient = AdminClientMock{}
minioServiceRestartMock = func(_ context.Context) error {
return nil
}
}
func (suite *IDPTestSuite) SetupTest() {
suite.server = httptest.NewServer(http.HandlerFunc(suite.serverHandler))
suite.currentServer, suite.isServerSet = os.LookupEnv(ConsoleMinIOServer)
os.Setenv(ConsoleMinIOServer, suite.server.URL)
}
func (suite *IDPTestSuite) serverHandler(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(400)
}
func (suite *IDPTestSuite) TearDownSuite() {
}
func (suite *IDPTestSuite) TearDownTest() {
if suite.isServerSet {
os.Setenv(ConsoleMinIOServer, suite.currentServer)
} else {
os.Unsetenv(ConsoleMinIOServer)
}
}
func (suite *IDPTestSuite) TestRegisterIDPHandlers() {
api := &operations.ConsoleAPI{}
suite.assertHandlersAreNil(api)
registerIDPHandlers(api)
suite.assertHandlersAreNotNil(api)
}
func (suite *IDPTestSuite) assertHandlersAreNil(api *operations.ConsoleAPI) {
suite.assert.Nil(api.IdpCreateConfigurationHandler)
suite.assert.Nil(api.IdpListConfigurationsHandler)
suite.assert.Nil(api.IdpUpdateConfigurationHandler)
suite.assert.Nil(api.IdpGetConfigurationHandler)
suite.assert.Nil(api.IdpGetConfigurationHandler)
suite.assert.Nil(api.IdpDeleteConfigurationHandler)
}
func (suite *IDPTestSuite) assertHandlersAreNotNil(api *operations.ConsoleAPI) {
suite.assert.NotNil(api.IdpCreateConfigurationHandler)
suite.assert.NotNil(api.IdpListConfigurationsHandler)
suite.assert.NotNil(api.IdpUpdateConfigurationHandler)
suite.assert.NotNil(api.IdpGetConfigurationHandler)
suite.assert.NotNil(api.IdpGetConfigurationHandler)
suite.assert.NotNil(api.IdpDeleteConfigurationHandler)
}
func (suite *IDPTestSuite) TestCreateIDPConfigurationHandlerWithError() {
params, api := suite.initCreateIDPConfigurationRequest()
response := api.IdpCreateConfigurationHandler.Handle(params, &models.Principal{})
_, ok := response.(*idp.CreateConfigurationDefault)
suite.assert.True(ok)
}
func (suite *IDPTestSuite) initCreateIDPConfigurationRequest() (params idp.CreateConfigurationParams, api operations.ConsoleAPI) {
registerIDPHandlers(&api)
params.HTTPRequest = &http.Request{}
params.Body = &models.IdpServerConfiguration{}
params.Type = "ldap"
return params, api
}
func (suite *IDPTestSuite) TestCreateIDPConfigurationWithoutError() {
ctx := context.Background()
_, err := createOrUpdateIDPConfig(ctx, "ldap", "", "", false, suite.adminClient)
suite.assert.Nil(err)
}
func (suite *IDPTestSuite) TestCreateIDPConfigurationWithWrongType() {
ctx := context.Background()
_, err := createOrUpdateIDPConfig(ctx, "", "", "", false, suite.adminClient)
suite.assert.NotNil(err)
}
func (suite *IDPTestSuite) TestUpdateIDPConfigurationHandlerWithError() {
params, api := suite.initUpdateIDPConfigurationRequest()
response := api.IdpUpdateConfigurationHandler.Handle(params, &models.Principal{})
_, ok := response.(*idp.UpdateConfigurationDefault)
suite.assert.True(ok)
}
func (suite *IDPTestSuite) initUpdateIDPConfigurationRequest() (params idp.UpdateConfigurationParams, api operations.ConsoleAPI) {
registerIDPHandlers(&api)
params.HTTPRequest = &http.Request{}
params.Body = &models.IdpServerConfiguration{}
params.Type = "ldap"
return params, api
}
func (suite *IDPTestSuite) TestUpdateIDPConfigurationWithoutError() {
ctx := context.Background()
_, err := createOrUpdateIDPConfig(ctx, "ldap", "", "", true, suite.adminClient)
suite.assert.Nil(err)
}
func (suite *IDPTestSuite) TestUpdateIDPConfigurationWithWrongType() {
ctx := context.Background()
_, err := createOrUpdateIDPConfig(ctx, "", "", "", true, suite.adminClient)
suite.assert.NotNil(err)
}
func (suite *IDPTestSuite) TestListIDPConfigurationHandlerWithError() {
params, api := suite.initListIDPConfigurationsRequest()
response := api.IdpListConfigurationsHandler.Handle(params, &models.Principal{})
_, ok := response.(*idp.ListConfigurationsDefault)
suite.assert.True(ok)
}
func (suite *IDPTestSuite) initListIDPConfigurationsRequest() (params idp.ListConfigurationsParams, api operations.ConsoleAPI) {
registerIDPHandlers(&api)
params.HTTPRequest = &http.Request{}
params.Type = "ldap"
return params, api
}
func (suite *IDPTestSuite) TestListIDPConfigurationsWithoutError() {
ctx := context.Background()
res, err := listIDPConfigurations(ctx, "ldap", suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *IDPTestSuite) TestListIDPConfigurationsWithWrongType() {
ctx := context.Background()
res, err := listIDPConfigurations(ctx, "", suite.adminClient)
suite.assert.Nil(res)
suite.assert.NotNil(err)
}
func (suite *IDPTestSuite) TestDeleteIDPConfigurationHandlerWithError() {
params, api := suite.initDeleteIDPConfigurationRequest()
response := api.IdpDeleteConfigurationHandler.Handle(params, &models.Principal{})
_, ok := response.(*idp.DeleteConfigurationDefault)
suite.assert.True(ok)
}
func (suite *IDPTestSuite) initDeleteIDPConfigurationRequest() (params idp.DeleteConfigurationParams, api operations.ConsoleAPI) {
registerIDPHandlers(&api)
params.HTTPRequest = &http.Request{}
params.Type = "ldap"
return params, api
}
func (suite *IDPTestSuite) TestDeleteIDPConfigurationWithoutError() {
ctx := context.Background()
_, err := deleteIDPConfig(ctx, "ldap", "", suite.adminClient)
suite.assert.Nil(err)
}
func (suite *IDPTestSuite) TestDeleteIDPConfigurationWithWrongType() {
ctx := context.Background()
_, err := deleteIDPConfig(ctx, "", "", suite.adminClient)
suite.assert.NotNil(err)
}
func (suite *IDPTestSuite) TestGetIDPConfigurationHandlerWithError() {
params, api := suite.initGetIDPConfigurationRequest()
response := api.IdpGetConfigurationHandler.Handle(params, &models.Principal{})
_, ok := response.(*idp.GetConfigurationDefault)
suite.assert.True(ok)
}
func (suite *IDPTestSuite) initGetIDPConfigurationRequest() (params idp.GetConfigurationParams, api operations.ConsoleAPI) {
registerIDPHandlers(&api)
params.HTTPRequest = &http.Request{}
params.Type = "ldap"
return params, api
}
func (suite *IDPTestSuite) TestGetIDPConfigurationWithoutError() {
ctx := context.Background()
res, err := getIDPConfiguration(ctx, "ldap", "", suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *IDPTestSuite) TestGetIDPConfigurationWithWrongType() {
ctx := context.Background()
res, err := getIDPConfiguration(ctx, "", "", suite.adminClient)
suite.assert.Nil(res)
suite.assert.NotNil(err)
}
func TestIDP(t *testing.T) {
suite.Run(t, new(IDPTestSuite))
}
func TestGetEntitiesResult(t *testing.T) {
assert := assert.New(t)
// mock minIO client
client := AdminClientMock{}
function := "getEntitiesResult()"
usersList := []string{"user1", "user2", "user3"}
policiesList := []string{"policy1", "policy2", "policy3"}
groupsList := []string{"group1", "group3", "group5"}
policyMap := []madmin.PolicyEntities{
{Policy: "testPolicy0", Groups: groupsList, Users: usersList},
{Policy: "testPolicy1", Groups: groupsList, Users: usersList},
}
usersMap := []madmin.UserPolicyEntities{
{User: "testUser0", Policies: policiesList},
{User: "testUser1", Policies: policiesList},
}
groupsMap := []madmin.GroupPolicyEntities{
{Group: "group0", Policies: policiesList},
{Group: "group1", Policies: policiesList},
}
// Test-1: getEntitiesResult list all information provided
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mockResponse := madmin.PolicyEntitiesResult{
PolicyMappings: policyMap,
GroupMappings: groupsMap,
UserMappings: usersMap,
}
minioGetLDAPPolicyEntitiesMock = func(_ context.Context, _ madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error) {
return mockResponse, nil
}
entities, err := getEntitiesResult(ctx, client, usersList, groupsList, policiesList)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
for i, groupIt := range entities.Groups {
assert.Equal(fmt.Sprintf("group%d", i), groupIt.Group)
for i, polItm := range groupIt.Policies {
assert.Equal(policiesList[i], polItm)
}
}
for i, usrIt := range entities.Users {
assert.Equal(fmt.Sprintf("testUser%d", i), usrIt.User)
for i, polItm := range usrIt.Policies {
assert.Equal(policiesList[i], polItm)
}
}
for i, policyIt := range entities.Policies {
assert.Equal(fmt.Sprintf("testPolicy%d", i), policyIt.Policy)
for i, userItm := range policyIt.Users {
assert.Equal(usersList[i], userItm)
}
for i, grItm := range policyIt.Groups {
assert.Equal(groupsList[i], grItm)
}
}
// Test-2: getEntitiesResult error is returned from getLDAPPolicyEntities()
minioGetLDAPPolicyEntitiesMock = func(_ context.Context, _ madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error) {
return madmin.PolicyEntitiesResult{}, errors.New("error")
}
_, err = getEntitiesResult(ctx, client, usersList, groupsList, policiesList)
if assert.Error(err) {
assert.Equal("error", err.Error())
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,152 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/minio/console/pkg/utils"
"github.com/minio/console/api/operations"
systemApi "github.com/minio/console/api/operations/system"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type AdminInfoTestSuite struct {
suite.Suite
assert *assert.Assertions
currentServer string
isServerSet bool
isPrometheusRequest bool
server *httptest.Server
adminClient AdminClientMock
}
func (suite *AdminInfoTestSuite) SetupSuite() {
suite.assert = assert.New(suite.T())
suite.adminClient = AdminClientMock{}
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{
Servers: []madmin.ServerProperties{{
Disks: []madmin.Disk{{}},
}},
Backend: madmin.ErasureBackend{Type: "mock"},
}, nil
}
}
func (suite *AdminInfoTestSuite) SetupTest() {
suite.server = httptest.NewServer(http.HandlerFunc(suite.serverHandler))
suite.currentServer, suite.isServerSet = os.LookupEnv(ConsoleMinIOServer)
os.Setenv(ConsoleMinIOServer, suite.server.URL)
}
func (suite *AdminInfoTestSuite) serverHandler(w http.ResponseWriter, _ *http.Request) {
if suite.isPrometheusRequest {
w.WriteHeader(200)
} else {
w.WriteHeader(400)
}
}
func (suite *AdminInfoTestSuite) TearDownSuite() {
}
func (suite *AdminInfoTestSuite) TearDownTest() {
if suite.isServerSet {
os.Setenv(ConsoleMinIOServer, suite.currentServer)
} else {
os.Unsetenv(ConsoleMinIOServer)
}
}
func (suite *AdminInfoTestSuite) TestRegisterAdminInfoHandlers() {
api := &operations.ConsoleAPI{}
suite.assertHandlersAreNil(api)
registerAdminInfoHandlers(api)
suite.assertHandlersAreNotNil(api)
}
func (suite *AdminInfoTestSuite) assertHandlersAreNil(api *operations.ConsoleAPI) {
suite.assert.Nil(api.SystemAdminInfoHandler)
suite.assert.Nil(api.SystemDashboardWidgetDetailsHandler)
}
func (suite *AdminInfoTestSuite) assertHandlersAreNotNil(api *operations.ConsoleAPI) {
suite.assert.NotNil(api.SystemAdminInfoHandler)
suite.assert.NotNil(api.SystemDashboardWidgetDetailsHandler)
}
func (suite *AdminInfoTestSuite) TestSystemAdminInfoHandlerWithError() {
params, api := suite.initSystemAdminInfoRequest()
response := api.SystemAdminInfoHandler.Handle(params, &models.Principal{})
_, ok := response.(*systemApi.AdminInfoDefault)
suite.assert.True(ok)
}
func (suite *AdminInfoTestSuite) initSystemAdminInfoRequest() (params systemApi.AdminInfoParams, api operations.ConsoleAPI) {
registerAdminInfoHandlers(&api)
params.HTTPRequest = &http.Request{}
defaultOnly := false
params.DefaultOnly = &defaultOnly
return params, api
}
func (suite *AdminInfoTestSuite) TestSystemDashboardWidgetDetailsHandlerWithError() {
params, api := suite.initSystemDashboardWidgetDetailsRequest()
response := api.SystemDashboardWidgetDetailsHandler.Handle(params, &models.Principal{})
_, ok := response.(*systemApi.DashboardWidgetDetailsDefault)
suite.assert.True(ok)
}
func (suite *AdminInfoTestSuite) initSystemDashboardWidgetDetailsRequest() (params systemApi.DashboardWidgetDetailsParams, api operations.ConsoleAPI) {
registerAdminInfoHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *AdminInfoTestSuite) TestGetUsageWidgetsForDeploymentWithoutError() {
ctx := context.WithValue(context.Background(), utils.ContextClientIP, "127.0.0.1")
suite.isPrometheusRequest = true
res, err := getUsageWidgetsForDeployment(ctx, suite.server.URL, suite.adminClient)
suite.assert.Nil(err)
suite.assert.NotNil(res)
suite.isPrometheusRequest = false
}
func (suite *AdminInfoTestSuite) TestGetWidgetDetailsWithoutError() {
ctx := context.WithValue(context.Background(), utils.ContextClientIP, "127.0.0.1")
suite.isPrometheusRequest = true
var step int32 = 1
var start int64
var end int64 = 1
res, err := getWidgetDetails(ctx, suite.server.URL, "mock", 1, &step, &start, &end)
suite.assert.Nil(err)
suite.assert.NotNil(res)
suite.isPrometheusRequest = false
}
func TestAdminInfo(t *testing.T) {
suite.Run(t, new(AdminInfoTestSuite))
}

View File

@@ -1,126 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"encoding/base64"
"fmt"
"io"
"net/http"
"strings"
"unicode/utf8"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
inspectApi "github.com/minio/console/api/operations/inspect"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
"github.com/secure-io/sio-go"
)
func registerInspectHandler(api *operations.ConsoleAPI) {
api.InspectInspectHandler = inspectApi.InspectHandlerFunc(func(params inspectApi.InspectParams, principal *models.Principal) middleware.Responder {
if v, err := base64.URLEncoding.DecodeString(params.File); err == nil && utf8.Valid(v) {
params.File = string(v)
}
if v, err := base64.URLEncoding.DecodeString(params.Volume); err == nil && utf8.Valid(v) {
params.Volume = string(v)
}
k, r, err := getInspectResult(principal, &params)
if err != nil {
return inspectApi.NewInspectDefault(err.Code).WithPayload(err.APIError)
}
return middleware.ResponderFunc(processInspectResponse(&params, k, r))
})
}
func getInspectResult(session *models.Principal, params *inspectApi.InspectParams) ([]byte, io.ReadCloser, *CodedAPIError) {
ctx := params.HTTPRequest.Context()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, nil, ErrorWithContext(ctx, err)
}
cfg := madmin.InspectOptions{
File: params.File,
Volume: params.Volume,
}
// TODO: Remove encryption option and always encrypt.
// Maybe also add public key field.
if params.Encrypt != nil && *params.Encrypt {
cfg.PublicKey, _ = base64.StdEncoding.DecodeString("MIIBCgKCAQEAs/128UFS9A8YSJY1XqYKt06dLVQQCGDee69T+0Tip/1jGAB4z0/3QMpH0MiS8Wjs4BRWV51qvkfAHzwwdU7y6jxU05ctb/H/WzRj3FYdhhHKdzear9TLJftlTs+xwj2XaADjbLXCV1jGLS889A7f7z5DgABlVZMQd9BjVAR8ED3xRJ2/ZCNuQVJ+A8r7TYPGMY3wWvhhPgPk3Lx4WDZxDiDNlFs4GQSaESSsiVTb9vyGe/94CsCTM6Cw9QG6ifHKCa/rFszPYdKCabAfHcS3eTr0GM+TThSsxO7KfuscbmLJkfQev1srfL2Ii2RbnysqIJVWKEwdW05ID8ryPkuTuwIDAQAB")
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
k, r, err := adminClient.inspect(ctx, cfg)
if err != nil {
return nil, nil, ErrorWithContext(ctx, err)
}
return k, r, nil
}
// borrowed from mc cli
func decryptInspectV1(key [32]byte, r io.Reader) io.ReadCloser {
stream, err := sio.AES_256_GCM.Stream(key[:])
if err != nil {
return nil
}
nonce := make([]byte, stream.NonceSize())
return io.NopCloser(stream.DecryptReader(r, nonce, nil))
}
func processInspectResponse(params *inspectApi.InspectParams, k []byte, r io.ReadCloser) func(w http.ResponseWriter, _ runtime.Producer) {
isEnc := params.Encrypt != nil && *params.Encrypt
return func(w http.ResponseWriter, _ runtime.Producer) {
ext := "enc"
if len(k) == 32 && !isEnc {
ext = "zip"
r = decryptInspectV1(*(*[32]byte)(k), r)
}
fileName := fmt.Sprintf("inspect-%s-%s.%s", params.Volume, params.File, ext)
fileName = strings.Map(func(r rune) rune {
switch {
case r >= 'A' && r <= 'Z':
return r
case r >= 'a' && r <= 'z':
return r
case r >= '0' && r <= '9':
return r
default:
if strings.ContainsAny(string(r), "-+._") {
return r
}
return '_'
}
}, fileName)
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileName))
_, err := io.Copy(w, r)
if err != nil {
LogError("unable to write all the data: %v", err)
}
}
}

View File

@@ -1,669 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package api
import (
"context"
"encoding/json"
"sort"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
kmsAPI "github.com/minio/console/api/operations/k_m_s"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
)
func registerKMSHandlers(api *operations.ConsoleAPI) {
registerKMSStatusHandlers(api)
registerKMSKeyHandlers(api)
registerKMSPolicyHandlers(api)
registerKMSIdentityHandlers(api)
}
func registerKMSStatusHandlers(api *operations.ConsoleAPI) {
api.KmsKMSStatusHandler = kmsAPI.KMSStatusHandlerFunc(func(params kmsAPI.KMSStatusParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSStatusResponse(session, params)
if err != nil {
return kmsAPI.NewKMSStatusDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSStatusOK().WithPayload(resp)
})
api.KmsKMSMetricsHandler = kmsAPI.KMSMetricsHandlerFunc(func(params kmsAPI.KMSMetricsParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSMetricsResponse(session, params)
if err != nil {
return kmsAPI.NewKMSMetricsDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSMetricsOK().WithPayload(resp)
})
api.KmsKMSAPIsHandler = kmsAPI.KMSAPIsHandlerFunc(func(params kmsAPI.KMSAPIsParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSAPIsResponse(session, params)
if err != nil {
return kmsAPI.NewKMSAPIsDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSAPIsOK().WithPayload(resp)
})
api.KmsKMSVersionHandler = kmsAPI.KMSVersionHandlerFunc(func(params kmsAPI.KMSVersionParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSVersionResponse(session, params)
if err != nil {
return kmsAPI.NewKMSVersionDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSVersionOK().WithPayload(resp)
})
}
func GetKMSStatusResponse(session *models.Principal, params kmsAPI.KMSStatusParams) (*models.KmsStatusResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return kmsStatus(ctx, AdminClient{Client: mAdmin})
}
func kmsStatus(ctx context.Context, minioClient MinioAdmin) (*models.KmsStatusResponse, *CodedAPIError) {
st, err := minioClient.kmsStatus(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsStatusResponse{
DefaultKeyID: st.DefaultKeyID,
Name: st.Name,
Endpoints: parseStatusEndpoints(st.Endpoints),
}, nil
}
func parseStatusEndpoints(endpoints map[string]madmin.ItemState) (kmsEndpoints []*models.KmsEndpoint) {
for key, value := range endpoints {
kmsEndpoints = append(kmsEndpoints, &models.KmsEndpoint{URL: key, Status: string(value)})
}
return kmsEndpoints
}
func GetKMSMetricsResponse(session *models.Principal, params kmsAPI.KMSMetricsParams) (*models.KmsMetricsResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return kmsMetrics(ctx, AdminClient{Client: mAdmin})
}
func kmsMetrics(ctx context.Context, minioClient MinioAdmin) (*models.KmsMetricsResponse, *CodedAPIError) {
metrics, err := minioClient.kmsMetrics(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsMetricsResponse{
RequestOK: &metrics.RequestOK,
RequestErr: &metrics.RequestErr,
RequestFail: &metrics.RequestFail,
RequestActive: &metrics.RequestActive,
AuditEvents: &metrics.AuditEvents,
ErrorEvents: &metrics.ErrorEvents,
LatencyHistogram: parseHistogram(metrics.LatencyHistogram),
Uptime: &metrics.UpTime,
Cpus: &metrics.CPUs,
UsableCPUs: &metrics.UsableCPUs,
Threads: &metrics.Threads,
HeapAlloc: &metrics.HeapAlloc,
HeapObjects: metrics.HeapObjects,
StackAlloc: &metrics.StackAlloc,
}, nil
}
func parseHistogram(histogram map[int64]int64) (records []*models.KmsLatencyHistogram) {
for duration, total := range histogram {
records = append(records, &models.KmsLatencyHistogram{Duration: duration, Total: total})
}
cp := func(i, j int) bool {
return records[i].Duration < records[j].Duration
}
sort.Slice(records, cp)
return records
}
func GetKMSAPIsResponse(session *models.Principal, params kmsAPI.KMSAPIsParams) (*models.KmsAPIsResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return kmsAPIs(ctx, AdminClient{Client: mAdmin})
}
func kmsAPIs(ctx context.Context, minioClient MinioAdmin) (*models.KmsAPIsResponse, *CodedAPIError) {
apis, err := minioClient.kmsAPIs(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsAPIsResponse{
Results: parseApis(apis),
}, nil
}
func parseApis(apis []madmin.KMSAPI) (data []*models.KmsAPI) {
for _, api := range apis {
data = append(data, &models.KmsAPI{
Method: api.Method,
Path: api.Path,
MaxBody: api.MaxBody,
Timeout: api.Timeout,
})
}
return data
}
func GetKMSVersionResponse(session *models.Principal, params kmsAPI.KMSVersionParams) (*models.KmsVersionResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return kmsVersion(ctx, AdminClient{Client: mAdmin})
}
func kmsVersion(ctx context.Context, minioClient MinioAdmin) (*models.KmsVersionResponse, *CodedAPIError) {
version, err := minioClient.kmsVersion(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsVersionResponse{
Version: version.Version,
}, nil
}
func registerKMSKeyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSCreateKeyHandler = kmsAPI.KMSCreateKeyHandlerFunc(func(params kmsAPI.KMSCreateKeyParams, session *models.Principal) middleware.Responder {
err := GetKMSCreateKeyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSCreateKeyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSCreateKeyCreated()
})
api.KmsKMSImportKeyHandler = kmsAPI.KMSImportKeyHandlerFunc(func(params kmsAPI.KMSImportKeyParams, session *models.Principal) middleware.Responder {
err := GetKMSImportKeyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSImportKeyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSImportKeyCreated()
})
api.KmsKMSListKeysHandler = kmsAPI.KMSListKeysHandlerFunc(func(params kmsAPI.KMSListKeysParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSListKeysResponse(session, params)
if err != nil {
return kmsAPI.NewKMSListKeysDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSListKeysOK().WithPayload(resp)
})
api.KmsKMSKeyStatusHandler = kmsAPI.KMSKeyStatusHandlerFunc(func(params kmsAPI.KMSKeyStatusParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSKeyStatusResponse(session, params)
if err != nil {
return kmsAPI.NewKMSKeyStatusDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSKeyStatusOK().WithPayload(resp)
})
api.KmsKMSDeleteKeyHandler = kmsAPI.KMSDeleteKeyHandlerFunc(func(params kmsAPI.KMSDeleteKeyParams, session *models.Principal) middleware.Responder {
err := GetKMSDeleteKeyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDeleteKeyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDeleteKeyOK()
})
}
func GetKMSCreateKeyResponse(session *models.Principal, params kmsAPI.KMSCreateKeyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
return createKey(ctx, *params.Body.Key, AdminClient{Client: mAdmin})
}
func createKey(ctx context.Context, key string, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.createKey(ctx, key); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
func GetKMSImportKeyResponse(session *models.Principal, params kmsAPI.KMSImportKeyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
bytes, err := json.Marshal(params.Body)
if err != nil {
return ErrorWithContext(ctx, err)
}
return importKey(ctx, params.Name, bytes, AdminClient{Client: mAdmin})
}
func importKey(ctx context.Context, key string, bytes []byte, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.importKey(ctx, key, bytes); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
func GetKMSListKeysResponse(session *models.Principal, params kmsAPI.KMSListKeysParams) (*models.KmsListKeysResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
pattern := ""
if params.Pattern != nil {
pattern = *params.Pattern
}
return listKeys(ctx, pattern, AdminClient{Client: mAdmin})
}
func listKeys(ctx context.Context, pattern string, minioClient MinioAdmin) (*models.KmsListKeysResponse, *CodedAPIError) {
results, err := minioClient.listKeys(ctx, pattern)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsListKeysResponse{Results: parseKeys(results)}, nil
}
func parseKeys(results []madmin.KMSKeyInfo) (data []*models.KmsKeyInfo) {
for _, key := range results {
data = append(data, &models.KmsKeyInfo{
CreatedAt: key.CreatedAt,
CreatedBy: key.CreatedBy,
Name: key.Name,
})
}
return data
}
func GetKMSKeyStatusResponse(session *models.Principal, params kmsAPI.KMSKeyStatusParams) (*models.KmsKeyStatusResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return keyStatus(ctx, params.Name, AdminClient{Client: mAdmin})
}
func keyStatus(ctx context.Context, key string, minioClient MinioAdmin) (*models.KmsKeyStatusResponse, *CodedAPIError) {
ks, err := minioClient.keyStatus(ctx, key)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsKeyStatusResponse{
KeyID: ks.KeyID,
EncryptionErr: ks.EncryptionErr,
DecryptionErr: ks.DecryptionErr,
}, nil
}
func GetKMSDeleteKeyResponse(session *models.Principal, params kmsAPI.KMSDeleteKeyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
return deleteKey(ctx, params.Name, AdminClient{Client: mAdmin})
}
func deleteKey(ctx context.Context, key string, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.deleteKey(ctx, key); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
func registerKMSPolicyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSSetPolicyHandler = kmsAPI.KMSSetPolicyHandlerFunc(func(params kmsAPI.KMSSetPolicyParams, session *models.Principal) middleware.Responder {
err := GetKMSSetPolicyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSSetPolicyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSSetPolicyOK()
})
api.KmsKMSAssignPolicyHandler = kmsAPI.KMSAssignPolicyHandlerFunc(func(params kmsAPI.KMSAssignPolicyParams, session *models.Principal) middleware.Responder {
err := GetKMSAssignPolicyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSAssignPolicyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSAssignPolicyOK()
})
api.KmsKMSDescribePolicyHandler = kmsAPI.KMSDescribePolicyHandlerFunc(func(params kmsAPI.KMSDescribePolicyParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSDescribePolicyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDescribePolicyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDescribePolicyOK().WithPayload(resp)
})
api.KmsKMSGetPolicyHandler = kmsAPI.KMSGetPolicyHandlerFunc(func(params kmsAPI.KMSGetPolicyParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSGetPolicyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSGetPolicyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSGetPolicyOK().WithPayload(resp)
})
api.KmsKMSListPoliciesHandler = kmsAPI.KMSListPoliciesHandlerFunc(func(params kmsAPI.KMSListPoliciesParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSListPoliciesResponse(session, params)
if err != nil {
return kmsAPI.NewKMSListPoliciesDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSListPoliciesOK().WithPayload(resp)
})
api.KmsKMSDeletePolicyHandler = kmsAPI.KMSDeletePolicyHandlerFunc(func(params kmsAPI.KMSDeletePolicyParams, session *models.Principal) middleware.Responder {
err := GetKMSDeletePolicyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDeletePolicyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDeletePolicyOK()
})
}
func GetKMSSetPolicyResponse(session *models.Principal, params kmsAPI.KMSSetPolicyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
bytes, err := json.Marshal(params.Body)
if err != nil {
return ErrorWithContext(ctx, err)
}
return setPolicy(ctx, *params.Body.Policy, bytes, AdminClient{Client: mAdmin})
}
func setPolicy(ctx context.Context, policy string, content []byte, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.setKMSPolicy(ctx, policy, content); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
func GetKMSAssignPolicyResponse(session *models.Principal, params kmsAPI.KMSAssignPolicyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
bytes, err := json.Marshal(params.Body)
if err != nil {
return ErrorWithContext(ctx, err)
}
return assignPolicy(ctx, params.Name, bytes, AdminClient{Client: mAdmin})
}
func assignPolicy(ctx context.Context, policy string, content []byte, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.assignPolicy(ctx, policy, content); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
func GetKMSDescribePolicyResponse(session *models.Principal, params kmsAPI.KMSDescribePolicyParams) (*models.KmsDescribePolicyResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return describePolicy(ctx, params.Name, AdminClient{Client: mAdmin})
}
func describePolicy(ctx context.Context, policy string, minioClient MinioAdmin) (*models.KmsDescribePolicyResponse, *CodedAPIError) {
dp, err := minioClient.describePolicy(ctx, policy)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsDescribePolicyResponse{
Name: dp.Name,
CreatedAt: dp.CreatedAt,
CreatedBy: dp.CreatedBy,
}, nil
}
func GetKMSGetPolicyResponse(session *models.Principal, params kmsAPI.KMSGetPolicyParams) (*models.KmsGetPolicyResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return getPolicy(ctx, params.Name, AdminClient{Client: mAdmin})
}
func getPolicy(ctx context.Context, policy string, minioClient MinioAdmin) (*models.KmsGetPolicyResponse, *CodedAPIError) {
p, err := minioClient.getKMSPolicy(ctx, policy)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsGetPolicyResponse{
Allow: p.Allow,
Deny: p.Deny,
}, nil
}
func GetKMSListPoliciesResponse(session *models.Principal, params kmsAPI.KMSListPoliciesParams) (*models.KmsListPoliciesResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
pattern := ""
if params.Pattern != nil {
pattern = *params.Pattern
}
return listKMSPolicies(ctx, pattern, AdminClient{Client: mAdmin})
}
func listKMSPolicies(ctx context.Context, pattern string, minioClient MinioAdmin) (*models.KmsListPoliciesResponse, *CodedAPIError) {
results, err := minioClient.listKMSPolicies(ctx, pattern)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsListPoliciesResponse{Results: parsePolicies(results)}, nil
}
func parsePolicies(results []madmin.KMSPolicyInfo) (data []*models.KmsPolicyInfo) {
for _, policy := range results {
data = append(data, &models.KmsPolicyInfo{
CreatedAt: policy.CreatedAt,
CreatedBy: policy.CreatedBy,
Name: policy.Name,
})
}
return data
}
func GetKMSDeletePolicyResponse(session *models.Principal, params kmsAPI.KMSDeletePolicyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
return deletePolicy(ctx, params.Name, AdminClient{Client: mAdmin})
}
func deletePolicy(ctx context.Context, policy string, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.deletePolicy(ctx, policy); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
func registerKMSIdentityHandlers(api *operations.ConsoleAPI) {
api.KmsKMSDescribeIdentityHandler = kmsAPI.KMSDescribeIdentityHandlerFunc(func(params kmsAPI.KMSDescribeIdentityParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSDescribeIdentityResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDescribeIdentityDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDescribeIdentityOK().WithPayload(resp)
})
api.KmsKMSDescribeSelfIdentityHandler = kmsAPI.KMSDescribeSelfIdentityHandlerFunc(func(params kmsAPI.KMSDescribeSelfIdentityParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSDescribeSelfIdentityResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDescribeSelfIdentityDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDescribeSelfIdentityOK().WithPayload(resp)
})
api.KmsKMSListIdentitiesHandler = kmsAPI.KMSListIdentitiesHandlerFunc(func(params kmsAPI.KMSListIdentitiesParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSListIdentitiesResponse(session, params)
if err != nil {
return kmsAPI.NewKMSListIdentitiesDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSListIdentitiesOK().WithPayload(resp)
})
api.KmsKMSDeleteIdentityHandler = kmsAPI.KMSDeleteIdentityHandlerFunc(func(params kmsAPI.KMSDeleteIdentityParams, session *models.Principal) middleware.Responder {
err := GetKMSDeleteIdentityResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDeleteIdentityDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDeleteIdentityOK()
})
}
func GetKMSDescribeIdentityResponse(session *models.Principal, params kmsAPI.KMSDescribeIdentityParams) (*models.KmsDescribeIdentityResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return describeIdentity(ctx, params.Name, AdminClient{Client: mAdmin})
}
func describeIdentity(ctx context.Context, identity string, minioClient MinioAdmin) (*models.KmsDescribeIdentityResponse, *CodedAPIError) {
i, err := minioClient.describeIdentity(ctx, identity)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsDescribeIdentityResponse{
Policy: i.Policy,
Admin: i.IsAdmin,
Identity: i.Identity,
CreatedAt: i.CreatedAt,
CreatedBy: i.CreatedBy,
}, nil
}
func GetKMSDescribeSelfIdentityResponse(session *models.Principal, params kmsAPI.KMSDescribeSelfIdentityParams) (*models.KmsDescribeSelfIdentityResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return describeSelfIdentity(ctx, AdminClient{Client: mAdmin})
}
func describeSelfIdentity(ctx context.Context, minioClient MinioAdmin) (*models.KmsDescribeSelfIdentityResponse, *CodedAPIError) {
i, err := minioClient.describeSelfIdentity(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsDescribeSelfIdentityResponse{
Policy: &models.KmsGetPolicyResponse{
Allow: i.Policy.Allow,
Deny: i.Policy.Deny,
},
Identity: i.Identity,
Admin: i.IsAdmin,
CreatedAt: i.CreatedAt,
CreatedBy: i.CreatedBy,
}, nil
}
func GetKMSListIdentitiesResponse(session *models.Principal, params kmsAPI.KMSListIdentitiesParams) (*models.KmsListIdentitiesResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
pattern := ""
if params.Pattern != nil {
pattern = *params.Pattern
}
return listIdentities(ctx, pattern, AdminClient{Client: mAdmin})
}
func listIdentities(ctx context.Context, pattern string, minioClient MinioAdmin) (*models.KmsListIdentitiesResponse, *CodedAPIError) {
results, err := minioClient.listIdentities(ctx, pattern)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.KmsListIdentitiesResponse{Results: parseIdentities(results)}, nil
}
func parseIdentities(results []madmin.KMSIdentityInfo) (data []*models.KmsIdentityInfo) {
for _, policy := range results {
data = append(data, &models.KmsIdentityInfo{
CreatedAt: policy.CreatedAt,
CreatedBy: policy.CreatedBy,
Identity: policy.Identity,
Error: policy.Error,
Policy: policy.Policy,
})
}
return data
}
func GetKMSDeleteIdentityResponse(session *models.Principal, params kmsAPI.KMSDeleteIdentityParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
return deleteIdentity(ctx, params.Name, AdminClient{Client: mAdmin})
}
func deleteIdentity(ctx context.Context, identity string, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.deleteIdentity(ctx, identity); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}

View File

@@ -1,498 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/minio/console/api/operations"
kmsAPI "github.com/minio/console/api/operations/k_m_s"
"github.com/minio/console/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type KMSTestSuite struct {
suite.Suite
assert *assert.Assertions
currentServer string
isServerSet bool
server *httptest.Server
adminClient AdminClientMock
}
func (suite *KMSTestSuite) SetupSuite() {
suite.assert = assert.New(suite.T())
suite.adminClient = AdminClientMock{}
}
func (suite *KMSTestSuite) SetupTest() {
suite.server = httptest.NewServer(http.HandlerFunc(suite.serverHandler))
suite.currentServer, suite.isServerSet = os.LookupEnv(ConsoleMinIOServer)
os.Setenv(ConsoleMinIOServer, suite.server.URL)
}
func (suite *KMSTestSuite) serverHandler(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(400)
}
func (suite *KMSTestSuite) TearDownSuite() {
}
func (suite *KMSTestSuite) TearDownTest() {
if suite.isServerSet {
os.Setenv(ConsoleMinIOServer, suite.currentServer)
} else {
os.Unsetenv(ConsoleMinIOServer)
}
}
func (suite *KMSTestSuite) TestRegisterKMSHandlers() {
api := &operations.ConsoleAPI{}
suite.assertHandlersAreNil(api)
registerKMSHandlers(api)
suite.assertHandlersAreNotNil(api)
}
func (suite *KMSTestSuite) assertHandlersAreNil(api *operations.ConsoleAPI) {
suite.assert.Nil(api.KmsKMSStatusHandler)
suite.assert.Nil(api.KmsKMSMetricsHandler)
suite.assert.Nil(api.KmsKMSAPIsHandler)
suite.assert.Nil(api.KmsKMSVersionHandler)
suite.assert.Nil(api.KmsKMSCreateKeyHandler)
suite.assert.Nil(api.KmsKMSImportKeyHandler)
suite.assert.Nil(api.KmsKMSListKeysHandler)
suite.assert.Nil(api.KmsKMSKeyStatusHandler)
suite.assert.Nil(api.KmsKMSDeleteKeyHandler)
suite.assert.Nil(api.KmsKMSSetPolicyHandler)
suite.assert.Nil(api.KmsKMSAssignPolicyHandler)
suite.assert.Nil(api.KmsKMSDescribePolicyHandler)
suite.assert.Nil(api.KmsKMSGetPolicyHandler)
suite.assert.Nil(api.KmsKMSListPoliciesHandler)
suite.assert.Nil(api.KmsKMSDeletePolicyHandler)
suite.assert.Nil(api.KmsKMSDescribeIdentityHandler)
suite.assert.Nil(api.KmsKMSDescribeSelfIdentityHandler)
suite.assert.Nil(api.KmsKMSListIdentitiesHandler)
suite.assert.Nil(api.KmsKMSDeleteIdentityHandler)
}
func (suite *KMSTestSuite) assertHandlersAreNotNil(api *operations.ConsoleAPI) {
suite.assert.NotNil(api.KmsKMSStatusHandler)
suite.assert.NotNil(api.KmsKMSMetricsHandler)
suite.assert.NotNil(api.KmsKMSAPIsHandler)
suite.assert.NotNil(api.KmsKMSVersionHandler)
suite.assert.NotNil(api.KmsKMSCreateKeyHandler)
suite.assert.NotNil(api.KmsKMSImportKeyHandler)
suite.assert.NotNil(api.KmsKMSListKeysHandler)
suite.assert.NotNil(api.KmsKMSKeyStatusHandler)
suite.assert.NotNil(api.KmsKMSDeleteKeyHandler)
suite.assert.NotNil(api.KmsKMSSetPolicyHandler)
suite.assert.NotNil(api.KmsKMSAssignPolicyHandler)
suite.assert.NotNil(api.KmsKMSDescribePolicyHandler)
suite.assert.NotNil(api.KmsKMSGetPolicyHandler)
suite.assert.NotNil(api.KmsKMSListPoliciesHandler)
suite.assert.NotNil(api.KmsKMSDeletePolicyHandler)
suite.assert.NotNil(api.KmsKMSDescribeIdentityHandler)
suite.assert.NotNil(api.KmsKMSDescribeSelfIdentityHandler)
suite.assert.NotNil(api.KmsKMSListIdentitiesHandler)
suite.assert.NotNil(api.KmsKMSDeleteIdentityHandler)
}
func (suite *KMSTestSuite) TestKMSStatusHandlerWithError() {
params, api := suite.initKMSStatusRequest()
response := api.KmsKMSStatusHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSStatusDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSStatusRequest() (params kmsAPI.KMSStatusParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSStatusWithoutError() {
ctx := context.Background()
res, err := kmsStatus(ctx, suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSMetricsHandlerWithError() {
params, api := suite.initKMSMetricsRequest()
response := api.KmsKMSMetricsHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSMetricsDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSMetricsRequest() (params kmsAPI.KMSMetricsParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSMetricsWithoutError() {
ctx := context.Background()
res, err := kmsMetrics(ctx, suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSAPIsHandlerWithError() {
params, api := suite.initKMSAPIsRequest()
response := api.KmsKMSAPIsHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSAPIsDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSAPIsRequest() (params kmsAPI.KMSAPIsParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSAPIsWithoutError() {
ctx := context.Background()
res, err := kmsAPIs(ctx, suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSVersionHandlerWithError() {
params, api := suite.initKMSVersionRequest()
response := api.KmsKMSVersionHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSVersionDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSVersionRequest() (params kmsAPI.KMSVersionParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSVersionWithoutError() {
ctx := context.Background()
res, err := kmsVersion(ctx, suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSCreateKeyHandlerWithError() {
params, api := suite.initKMSCreateKeyRequest()
response := api.KmsKMSCreateKeyHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSCreateKeyDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSCreateKeyRequest() (params kmsAPI.KMSCreateKeyParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
key := "key"
params.Body = &models.KmsCreateKeyRequest{Key: &key}
return params, api
}
func (suite *KMSTestSuite) TestKMSCreateKeyWithoutError() {
ctx := context.Background()
err := createKey(ctx, "key", suite.adminClient)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSImportKeyHandlerWithError() {
params, api := suite.initKMSImportKeyRequest()
response := api.KmsKMSImportKeyHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSImportKeyDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSImportKeyRequest() (params kmsAPI.KMSImportKeyParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSImportKeyWithoutError() {
ctx := context.Background()
err := importKey(ctx, "key", []byte(""), suite.adminClient)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSListKeysHandlerWithError() {
params, api := suite.initKMSListKeysRequest()
response := api.KmsKMSListKeysHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSListKeysDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSListKeysRequest() (params kmsAPI.KMSListKeysParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSListKeysWithoutError() {
ctx := context.Background()
res, err := listKeys(ctx, "", suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSKeyStatusHandlerWithError() {
params, api := suite.initKMSKeyStatusRequest()
response := api.KmsKMSKeyStatusHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSKeyStatusDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSKeyStatusRequest() (params kmsAPI.KMSKeyStatusParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSKeyStatusWithoutError() {
ctx := context.Background()
res, err := keyStatus(ctx, "key", suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSDeleteKeyHandlerWithError() {
params, api := suite.initKMSDeleteKeyRequest()
response := api.KmsKMSDeleteKeyHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSDeleteKeyDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSDeleteKeyRequest() (params kmsAPI.KMSDeleteKeyParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSDeleteKeyWithoutError() {
ctx := context.Background()
err := deleteKey(ctx, "key", suite.adminClient)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSSetPolicyHandlerWithError() {
params, api := suite.initKMSSetPolicyRequest()
response := api.KmsKMSSetPolicyHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSSetPolicyDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSSetPolicyRequest() (params kmsAPI.KMSSetPolicyParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
policy := "policy"
params.Body = &models.KmsSetPolicyRequest{Policy: &policy}
return params, api
}
func (suite *KMSTestSuite) TestKMSSetPolicyWithoutError() {
ctx := context.Background()
err := setPolicy(ctx, "policy", []byte(""), suite.adminClient)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSAssignPolicyHandlerWithError() {
params, api := suite.initKMSAssignPolicyRequest()
response := api.KmsKMSAssignPolicyHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSAssignPolicyDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSAssignPolicyRequest() (params kmsAPI.KMSAssignPolicyParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSAssignPolicyWithoutError() {
ctx := context.Background()
err := assignPolicy(ctx, "policy", []byte(""), suite.adminClient)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSDescribePolicyHandlerWithError() {
params, api := suite.initKMSDescribePolicyRequest()
response := api.KmsKMSDescribePolicyHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSDescribePolicyDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSDescribePolicyRequest() (params kmsAPI.KMSDescribePolicyParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSDescribePolicyWithoutError() {
ctx := context.Background()
res, err := describePolicy(ctx, "policy", suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSGetPolicyHandlerWithError() {
params, api := suite.initKMSGetPolicyRequest()
response := api.KmsKMSGetPolicyHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSGetPolicyDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSGetPolicyRequest() (params kmsAPI.KMSGetPolicyParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSGetPolicyWithoutError() {
ctx := context.Background()
res, err := getPolicy(ctx, "policy", suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSListPoliciesHandlerWithError() {
params, api := suite.initKMSListPoliciesRequest()
response := api.KmsKMSListPoliciesHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSListPoliciesDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSListPoliciesRequest() (params kmsAPI.KMSListPoliciesParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSListPoliciesWithoutError() {
ctx := context.Background()
res, err := listKMSPolicies(ctx, "", suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSDeletePolicyHandlerWithError() {
params, api := suite.initKMSDeletePolicyRequest()
response := api.KmsKMSDeletePolicyHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSDeletePolicyDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSDeletePolicyRequest() (params kmsAPI.KMSDeletePolicyParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSDeletePolicyWithoutError() {
ctx := context.Background()
err := deletePolicy(ctx, "policy", suite.adminClient)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSDescribeIdentityHandlerWithError() {
params, api := suite.initKMSDescribeIdentityRequest()
response := api.KmsKMSDescribeIdentityHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSDescribeIdentityDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSDescribeIdentityRequest() (params kmsAPI.KMSDescribeIdentityParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSDescribeIdentityWithoutError() {
ctx := context.Background()
res, err := describeIdentity(ctx, "identity", suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSDescribeSelfIdentityHandlerWithError() {
params, api := suite.initKMSDescribeSelfIdentityRequest()
response := api.KmsKMSDescribeSelfIdentityHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSDescribeSelfIdentityDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSDescribeSelfIdentityRequest() (params kmsAPI.KMSDescribeSelfIdentityParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSDescribeSelfIdentityWithoutError() {
ctx := context.Background()
res, err := describeSelfIdentity(ctx, suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSListIdentitiesHandlerWithError() {
params, api := suite.initKMSListIdentitiesRequest()
response := api.KmsKMSListIdentitiesHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSListIdentitiesDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSListIdentitiesRequest() (params kmsAPI.KMSListIdentitiesParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSListIdentitiesWithoutError() {
ctx := context.Background()
res, err := listIdentities(ctx, "", suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *KMSTestSuite) TestKMSDeleteIdentityHandlerWithError() {
params, api := suite.initKMSDeleteIdentityRequest()
response := api.KmsKMSDeleteIdentityHandler.Handle(params, &models.Principal{})
_, ok := response.(*kmsAPI.KMSDeleteIdentityDefault)
suite.assert.True(ok)
}
func (suite *KMSTestSuite) initKMSDeleteIdentityRequest() (params kmsAPI.KMSDeleteIdentityParams, api operations.ConsoleAPI) {
registerKMSHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *KMSTestSuite) TestKMSDeleteIdentityWithoutError() {
ctx := context.Background()
err := deleteIdentity(ctx, "identity", suite.adminClient)
suite.assert.Nil(err)
}
func TestKMS(t *testing.T) {
suite.Run(t, new(KMSTestSuite))
}

View File

@@ -1,104 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"encoding/base64"
"time"
"github.com/minio/mc/cmd"
"github.com/minio/minio-go/v7"
)
type objectsListOpts struct {
BucketName string
Prefix string
Date time.Time
}
type ObjectsRequest struct {
Mode string `json:"mode,omitempty"`
BucketName string `json:"bucket_name"`
Prefix string `json:"prefix"`
Date string `json:"date"`
RequestID int64 `json:"request_id"`
}
type WSResponse struct {
RequestID int64 `json:"request_id,omitempty"`
Error *CodedAPIError `json:"error,omitempty"`
RequestEnd bool `json:"request_end,omitempty"`
Prefix string `json:"prefix,omitempty"`
BucketName string `json:"bucketName,omitempty"`
Data []ObjectResponse `json:"data,omitempty"`
}
type ObjectResponse struct {
Name string `json:"name,omitempty"`
LastModified string `json:"last_modified,omitempty"`
Size int64 `json:"size,omitempty"`
VersionID string `json:"version_id,omitempty"`
DeleteMarker bool `json:"delete_flag,omitempty"`
IsLatest bool `json:"is_latest,omitempty"`
}
func getObjectsOptionsFromReq(request ObjectsRequest) (*objectsListOpts, error) {
pOptions := objectsListOpts{
BucketName: request.BucketName,
Prefix: "",
}
prefix := request.Prefix
if prefix != "" {
encodedPrefix := SanitizeEncodedPrefix(prefix)
decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix)
if err != nil {
LogError("error decoding prefix: %v", err)
return nil, err
}
pOptions.Prefix = string(decodedPrefix)
}
if request.Mode == "rewind" {
parsedDate, errDate := time.Parse(time.RFC3339, request.Date)
if errDate != nil {
return nil, errDate
}
pOptions.Date = parsedDate
}
return &pOptions, nil
}
func startObjectsListing(ctx context.Context, client MinioClient, objOpts *objectsListOpts) <-chan minio.ObjectInfo {
opts := minio.ListObjectsOptions{
Prefix: objOpts.Prefix,
}
return client.listObjects(ctx, objOpts.BucketName, opts)
}
func startRewindListing(ctx context.Context, client MCClient, objOpts *objectsListOpts) <-chan *cmd.ClientContent {
lsRewind := client.list(ctx, cmd.ListOptions{TimeRef: objOpts.Date, WithDeleteMarkers: true})
return lsRewind
}

View File

@@ -1,236 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"testing"
"time"
mc "github.com/minio/mc/cmd"
"github.com/minio/minio-go/v7"
"github.com/stretchr/testify/assert"
)
func TestWSRewindObjects(t *testing.T) {
assert := assert.New(t)
client := s3ClientMock{}
tests := []struct {
name string
testOptions objectsListOpts
testMessages []*mc.ClientContent
}{
{
name: "Get list with multiple elements",
testOptions: objectsListOpts{
BucketName: "buckettest",
Prefix: "/",
Date: time.Now(),
},
testMessages: []*mc.ClientContent{
{
BucketName: "buckettest",
URL: mc.ClientURL{Path: "/file1.txt"},
},
{
BucketName: "buckettest",
URL: mc.ClientURL{Path: "/file2.txt"},
},
{
BucketName: "buckettest",
URL: mc.ClientURL{Path: "/path1"},
},
},
},
{
name: "Empty list of elements",
testOptions: objectsListOpts{
BucketName: "emptybucket",
Prefix: "/",
Date: time.Now(),
},
testMessages: []*mc.ClientContent{},
},
{
name: "Get list with one element",
testOptions: objectsListOpts{
BucketName: "buckettest",
Prefix: "/",
Date: time.Now(),
},
testMessages: []*mc.ClientContent{
{
BucketName: "buckettestsingle",
URL: mc.ClientURL{Path: "/file12.txt"},
},
},
},
{
name: "Get data from subpaths",
testOptions: objectsListOpts{
BucketName: "buckettest",
Prefix: "/path1/path2",
Date: time.Now(),
},
testMessages: []*mc.ClientContent{
{
BucketName: "buckettestsingle",
URL: mc.ClientURL{Path: "/path1/path2/file12.txt"},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mcListMock = func(_ context.Context, _ mc.ListOptions) <-chan *mc.ClientContent {
ch := make(chan *mc.ClientContent)
go func() {
defer close(ch)
for _, m := range tt.testMessages {
ch <- m
}
}()
return ch
}
rewindList := startRewindListing(ctx, client, &tt.testOptions)
// check that the rewindList got the same number of data from Console.
totalItems := 0
for data := range rewindList {
// Compare elements as we are defining the channel responses
assert.Equal(tt.testMessages[totalItems].URL.Path, data.URL.Path)
totalItems++
}
assert.Equal(len(tt.testMessages), totalItems)
})
}
}
func TestWSListObjects(t *testing.T) {
assert := assert.New(t)
client := minioClientMock{}
tests := []struct {
name string
wantErr bool
testOptions objectsListOpts
testMessages []minio.ObjectInfo
}{
{
name: "Get list with multiple elements",
wantErr: false,
testOptions: objectsListOpts{
BucketName: "buckettest",
Prefix: "/",
},
testMessages: []minio.ObjectInfo{
{
Key: "/file1.txt",
Size: 500,
IsLatest: true,
LastModified: time.Now(),
},
{
Key: "/file2.txt",
Size: 500,
IsLatest: true,
LastModified: time.Now(),
},
{
Key: "/path1",
},
},
},
{
name: "Empty list of elements",
wantErr: false,
testOptions: objectsListOpts{
BucketName: "emptybucket",
Prefix: "/",
},
testMessages: []minio.ObjectInfo{},
},
{
name: "Get list with one element",
wantErr: false,
testOptions: objectsListOpts{
BucketName: "buckettest",
Prefix: "/",
},
testMessages: []minio.ObjectInfo{
{
Key: "/file2.txt",
Size: 500,
IsLatest: true,
LastModified: time.Now(),
},
},
},
{
name: "Get data from subpaths",
wantErr: false,
testOptions: objectsListOpts{
BucketName: "buckettest",
Prefix: "/path1/path2",
},
testMessages: []minio.ObjectInfo{
{
Key: "/path1/path2/file1.txt",
Size: 500,
IsLatest: true,
LastModified: time.Now(),
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
minioListObjectsMock = func(_ context.Context, _ string, _ minio.ListObjectsOptions) <-chan minio.ObjectInfo {
ch := make(chan minio.ObjectInfo)
go func() {
defer close(ch)
for _, m := range tt.testMessages {
ch <- m
}
}()
return ch
}
objectsListing := startObjectsListing(ctx, client, &tt.testOptions)
// check that the TestReceiver got the same number of data from Console
totalItems := 0
for data := range objectsListing {
// Compare elements as we are defining the channel responses
assert.Equal(tt.testMessages[totalItems].Key, data.Key)
totalItems++
}
assert.Equal(len(tt.testMessages), totalItems)
})
}
}

View File

@@ -1,720 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"bytes"
"context"
"encoding/json"
"fmt"
"sort"
"strings"
bucketApi "github.com/minio/console/api/operations/bucket"
policyApi "github.com/minio/console/api/operations/policy"
"github.com/minio/console/pkg/utils"
s3 "github.com/minio/minio-go/v7"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
"github.com/minio/console/models"
iampolicy "github.com/minio/pkg/v2/policy"
policies "github.com/minio/console/api/policy"
)
func registersPoliciesHandler(api *operations.ConsoleAPI) {
// List Policies
api.PolicyListPoliciesHandler = policyApi.ListPoliciesHandlerFunc(func(params policyApi.ListPoliciesParams, session *models.Principal) middleware.Responder {
listPoliciesResponse, err := getListPoliciesResponse(session, params)
if err != nil {
return policyApi.NewListPoliciesDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewListPoliciesOK().WithPayload(listPoliciesResponse)
})
// Policy Info
api.PolicyPolicyInfoHandler = policyApi.PolicyInfoHandlerFunc(func(params policyApi.PolicyInfoParams, session *models.Principal) middleware.Responder {
policyInfo, err := getPolicyInfoResponse(session, params)
if err != nil {
return policyApi.NewPolicyInfoDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewPolicyInfoOK().WithPayload(policyInfo)
})
// Add Policy
api.PolicyAddPolicyHandler = policyApi.AddPolicyHandlerFunc(func(params policyApi.AddPolicyParams, session *models.Principal) middleware.Responder {
policyResponse, err := getAddPolicyResponse(session, params)
if err != nil {
return policyApi.NewAddPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewAddPolicyCreated().WithPayload(policyResponse)
})
// Remove Policy
api.PolicyRemovePolicyHandler = policyApi.RemovePolicyHandlerFunc(func(params policyApi.RemovePolicyParams, session *models.Principal) middleware.Responder {
if err := getRemovePolicyResponse(session, params); err != nil {
return policyApi.NewRemovePolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewRemovePolicyNoContent()
})
// Set Policy
api.PolicySetPolicyHandler = policyApi.SetPolicyHandlerFunc(func(params policyApi.SetPolicyParams, session *models.Principal) middleware.Responder {
if err := getSetPolicyResponse(session, params); err != nil {
return policyApi.NewSetPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewSetPolicyNoContent()
})
// Set Policy Multiple User/Groups
api.PolicySetPolicyMultipleHandler = policyApi.SetPolicyMultipleHandlerFunc(func(params policyApi.SetPolicyMultipleParams, session *models.Principal) middleware.Responder {
if err := getSetPolicyMultipleResponse(session, params); err != nil {
return policyApi.NewSetPolicyMultipleDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewSetPolicyMultipleNoContent()
})
api.BucketListPoliciesWithBucketHandler = bucketApi.ListPoliciesWithBucketHandlerFunc(func(params bucketApi.ListPoliciesWithBucketParams, session *models.Principal) middleware.Responder {
policyResponse, err := getListPoliciesWithBucketResponse(session, params)
if err != nil {
return bucketApi.NewListPoliciesWithBucketDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewListPoliciesWithBucketOK().WithPayload(policyResponse)
})
api.BucketListAccessRulesWithBucketHandler = bucketApi.ListAccessRulesWithBucketHandlerFunc(func(params bucketApi.ListAccessRulesWithBucketParams, session *models.Principal) middleware.Responder {
policyResponse, err := getListAccessRulesWithBucketResponse(session, params)
if err != nil {
return bucketApi.NewListAccessRulesWithBucketDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewListAccessRulesWithBucketOK().WithPayload(policyResponse)
})
api.BucketSetAccessRuleWithBucketHandler = bucketApi.SetAccessRuleWithBucketHandlerFunc(func(params bucketApi.SetAccessRuleWithBucketParams, session *models.Principal) middleware.Responder {
policyResponse, err := getSetAccessRuleWithBucketResponse(session, params)
if err != nil {
return bucketApi.NewSetAccessRuleWithBucketDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewSetAccessRuleWithBucketOK().WithPayload(policyResponse)
})
api.BucketDeleteAccessRuleWithBucketHandler = bucketApi.DeleteAccessRuleWithBucketHandlerFunc(func(params bucketApi.DeleteAccessRuleWithBucketParams, session *models.Principal) middleware.Responder {
policyResponse, err := getDeleteAccessRuleWithBucketResponse(session, params)
if err != nil {
return bucketApi.NewDeleteAccessRuleWithBucketDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewDeleteAccessRuleWithBucketOK().WithPayload(policyResponse)
})
api.PolicyListUsersForPolicyHandler = policyApi.ListUsersForPolicyHandlerFunc(func(params policyApi.ListUsersForPolicyParams, session *models.Principal) middleware.Responder {
policyUsersResponse, err := getListUsersForPolicyResponse(session, params)
if err != nil {
return policyApi.NewListUsersForPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewListUsersForPolicyOK().WithPayload(policyUsersResponse)
})
api.PolicyListGroupsForPolicyHandler = policyApi.ListGroupsForPolicyHandlerFunc(func(params policyApi.ListGroupsForPolicyParams, session *models.Principal) middleware.Responder {
policyGroupsResponse, err := getListGroupsForPolicyResponse(session, params)
if err != nil {
return policyApi.NewListGroupsForPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewListGroupsForPolicyOK().WithPayload(policyGroupsResponse)
})
// Gets policies for currently logged in user
api.PolicyGetUserPolicyHandler = policyApi.GetUserPolicyHandlerFunc(func(params policyApi.GetUserPolicyParams, session *models.Principal) middleware.Responder {
userPolicyResponse, err := getUserPolicyResponse(params.HTTPRequest.Context(), session)
if err != nil {
return policyApi.NewGetUserPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewGetUserPolicyOK().WithPayload(userPolicyResponse)
})
// Gets policies for specified user
api.PolicyGetSAUserPolicyHandler = policyApi.GetSAUserPolicyHandlerFunc(func(params policyApi.GetSAUserPolicyParams, session *models.Principal) middleware.Responder {
userPolicyResponse, err := getSAUserPolicyResponse(session, params)
if err != nil {
return policyApi.NewGetSAUserPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewGetSAUserPolicyOK().WithPayload(userPolicyResponse)
})
}
func getListAccessRulesWithBucketResponse(session *models.Principal, params bucketApi.ListAccessRulesWithBucketParams) (*models.ListAccessRulesResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
bucket := params.Bucket
client, err := newS3BucketClient(session, bucket, "", getClientIP(params.HTTPRequest))
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
accessRules, _ := client.GetAccessRules(ctx)
var accessRuleList []*models.AccessRule
for k, v := range accessRules {
accessRuleList = append(accessRuleList, &models.AccessRule{Prefix: k[len(bucket)+1 : len(k)-1], Access: v})
}
return &models.ListAccessRulesResponse{AccessRules: accessRuleList}, nil
}
func getSetAccessRuleWithBucketResponse(session *models.Principal, params bucketApi.SetAccessRuleWithBucketParams) (bool, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
prefixAccess := params.Prefixaccess
client, err := newS3BucketClient(session, params.Bucket, prefixAccess.Prefix, getClientIP(params.HTTPRequest))
if err != nil {
return false, ErrorWithContext(ctx, err)
}
errorVal := client.SetAccess(ctx, prefixAccess.Access, false)
if errorVal != nil {
returnError := ErrorWithContext(ctx, errorVal.Cause)
minioError := s3.ToErrorResponse(errorVal.Cause)
if minioError.Code == "NoSuchBucket" {
returnError.Code = 404
}
return false, returnError
}
return true, nil
}
func getDeleteAccessRuleWithBucketResponse(session *models.Principal, params bucketApi.DeleteAccessRuleWithBucketParams) (bool, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
bucket := params.Bucket
prefix := params.Prefix
client, err := newS3BucketClient(session, bucket, prefix.Prefix, getClientIP(params.HTTPRequest))
if err != nil {
return false, ErrorWithContext(ctx, err)
}
errorVal := client.SetAccess(ctx, "none", false)
if errorVal != nil {
return false, ErrorWithContext(ctx, errorVal.Cause)
}
return true, nil
}
func getListPoliciesWithBucketResponse(session *models.Principal, params bucketApi.ListPoliciesWithBucketParams) (*models.ListPoliciesResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
policies, err := listPoliciesWithBucket(ctx, params.Bucket, adminClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// serialize output
listPoliciesResponse := &models.ListPoliciesResponse{
Policies: policies,
Total: int64(len(policies)),
}
return listPoliciesResponse, nil
}
// listPoliciesWithBucket calls MinIO server to list all policy names present on the server that apply to a particular bucket.
// listPoliciesWithBucket() converts the map[string][]byte returned by client.listPolicies()
// to []*models.Policy by iterating over each key in policyRawMap and
// then using Unmarshal on the raw bytes to create a *models.Policy
func listPoliciesWithBucket(ctx context.Context, bucket string, client MinioAdmin) ([]*models.Policy, error) {
policyMap, err := client.listPolicies(ctx)
var policies []*models.Policy
if err != nil {
return nil, err
}
for name, policy := range policyMap {
policy, err := parsePolicy(name, policy)
if err != nil {
return nil, err
}
if policyMatchesBucket(ctx, policy, bucket) {
policies = append(policies, policy)
}
}
return policies, nil
}
func policyMatchesBucket(ctx context.Context, policy *models.Policy, bucket string) bool {
policyData := &iampolicy.Policy{}
err := json.Unmarshal([]byte(policy.Policy), policyData)
if err != nil {
ErrorWithContext(ctx, fmt.Errorf("error parsing policy: %v", err))
return false
}
policyStatements := policyData.Statements
for i := 0; i < len(policyStatements); i++ {
resources := policyStatements[i].Resources
if resources.Match(bucket, map[string][]string{}) {
return true
}
if resources.Match(fmt.Sprintf("%s/*", bucket), map[string][]string{}) {
return true
}
}
return false
}
// listPolicies calls MinIO server to list all policy names present on the server.
// listPolicies() converts the map[string][]byte returned by client.listPolicies()
// to []*models.Policy by iterating over each key in policyRawMap and
// then using Unmarshal on the raw bytes to create a *models.Policy
func listPolicies(ctx context.Context, client MinioAdmin) ([]*models.Policy, error) {
policyMap, err := client.listPolicies(ctx)
var policies []*models.Policy
if err != nil {
return nil, err
}
for name, policy := range policyMap {
policy, err := parsePolicy(name, policy)
if err != nil {
return nil, err
}
policies = append(policies, policy)
}
return policies, nil
}
// getListPoliciesResponse performs listPolicies() and serializes it to the handler's output
func getListPoliciesResponse(session *models.Principal, params policyApi.ListPoliciesParams) (*models.ListPoliciesResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
policies, err := listPolicies(ctx, adminClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// serialize output
listPoliciesResponse := &models.ListPoliciesResponse{
Policies: policies,
Total: int64(len(policies)),
}
return listPoliciesResponse, nil
}
// getListUsersForPoliciesResponse performs lists users affected by a given policy.
func getListUsersForPolicyResponse(session *models.Principal, params policyApi.ListUsersForPolicyParams) ([]string, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
policy, err := utils.DecodeBase64(params.Policy)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
policies, err := listPolicies(ctx, adminClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
found := false
for i := range policies {
if policies[i].Name == policy {
found = true
}
}
if !found {
return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", policy))
}
users, err := listUsers(ctx, adminClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
var filteredUsers []string
for _, user := range users {
for _, upolicy := range user.Policy {
if upolicy == policy {
filteredUsers = append(filteredUsers, user.AccessKey)
break
}
}
}
sort.Strings(filteredUsers)
return filteredUsers, nil
}
func getUserPolicyResponse(ctx context.Context, session *models.Principal) (string, *CodedAPIError) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// serialize output
if session == nil {
return "nil", ErrorWithContext(ctx, ErrPolicyNotFound)
}
tokenClaims, _ := getClaimsFromToken(session.STSSessionToken)
// initialize admin client
mAdminClient, err := NewMinioAdminClient(ctx, &models.Principal{
STSAccessKeyID: session.STSAccessKeyID,
STSSecretAccessKey: session.STSSecretAccessKey,
STSSessionToken: session.STSSessionToken,
})
if err != nil {
return "nil", ErrorWithContext(ctx, err)
}
userAdminClient := AdminClient{Client: mAdminClient}
// Obtain the current policy assigned to this user
// necessary for generating the list of allowed endpoints
accountInfo, err := getAccountInfo(ctx, userAdminClient)
if err != nil {
return "nil", ErrorWithContext(ctx, err)
}
rawPolicy := policies.ReplacePolicyVariables(tokenClaims, accountInfo)
return string(rawPolicy), nil
}
func getSAUserPolicyResponse(session *models.Principal, params policyApi.GetSAUserPolicyParams) (*models.AUserPolicyResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
// serialize output
if session == nil {
return nil, ErrorWithContext(ctx, ErrPolicyNotFound)
}
// initialize admin client
mAdminClient, err := NewMinioAdminClient(params.HTTPRequest.Context(), &models.Principal{
STSAccessKeyID: session.STSAccessKeyID,
STSSecretAccessKey: session.STSSecretAccessKey,
STSSessionToken: session.STSSessionToken,
})
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
userAdminClient := AdminClient{Client: mAdminClient}
userName, err := utils.DecodeBase64(params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
user, err := getUserInfo(ctx, userAdminClient, userName)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
var userPolicies []string
if len(user.PolicyName) > 0 {
userPolicies = strings.Split(user.PolicyName, ",")
}
for _, group := range user.MemberOf {
groupDesc, err := groupInfo(ctx, userAdminClient, group)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
if groupDesc.Policy != "" {
userPolicies = append(userPolicies, strings.Split(groupDesc.Policy, ",")...)
}
}
allKeys := make(map[string]bool)
var userPolicyList []string
for _, item := range userPolicies {
if _, value := allKeys[item]; !value {
allKeys[item] = true
userPolicyList = append(userPolicyList, item)
}
}
var userStatements []iampolicy.Statement
for _, pol := range userPolicyList {
policy, err := getPolicyStatements(ctx, userAdminClient, pol)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
userStatements = append(userStatements, policy...)
}
combinedPolicy := iampolicy.Policy{
Version: "2012-10-17",
Statements: userStatements,
}
stringPolicy, err := json.Marshal(combinedPolicy)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
parsedPolicy := string(stringPolicy)
getUserPoliciesResponse := &models.AUserPolicyResponse{
Policy: parsedPolicy,
}
return getUserPoliciesResponse, nil
}
func getListGroupsForPolicyResponse(session *models.Principal, params policyApi.ListGroupsForPolicyParams) ([]string, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a minioClient interface implementation
// defining the client to be used
policy, err := utils.DecodeBase64(params.Policy)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
adminClient := AdminClient{Client: mAdmin}
policies, err := listPolicies(ctx, adminClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
found := false
for i := range policies {
if policies[i].Name == policy {
found = true
}
}
if !found {
return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", policy))
}
groups, err := adminClient.listGroups(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
var filteredGroups []string
for _, group := range groups {
info, err := groupInfo(ctx, adminClient, group)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
groupPolicies := strings.Split(info.Policy, ",")
for _, groupPolicy := range groupPolicies {
if groupPolicy == policy {
filteredGroups = append(filteredGroups, group)
}
}
}
sort.Strings(filteredGroups)
return filteredGroups, nil
}
// removePolicy() calls MinIO server to remove a policy based on name.
func removePolicy(ctx context.Context, client MinioAdmin, name string) error {
err := client.removePolicy(ctx, name)
if err != nil {
return err
}
return nil
}
// getRemovePolicyResponse() performs removePolicy() and serializes it to the handler's output
func getRemovePolicyResponse(session *models.Principal, params policyApi.RemovePolicyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
if params.Name == "" {
return ErrorWithContext(ctx, ErrPolicyNameNotInRequest)
}
policyName, err := utils.DecodeBase64(params.Name)
if err != nil {
return ErrorWithContext(ctx, err)
}
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
if err := removePolicy(ctx, adminClient, policyName); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
// addPolicy calls MinIO server to add a canned policy.
// addPolicy() takes name and policy in string format, policy
// policy must be string in json format, in the future this will change
// to a Policy struct{} - https://github.com/minio/minio/issues/9171
func addPolicy(ctx context.Context, client MinioAdmin, name, policy string) (*models.Policy, error) {
iamp, err := iampolicy.ParseConfig(bytes.NewReader([]byte(policy)))
if err != nil {
return nil, err
}
if err := client.addPolicy(ctx, name, iamp); err != nil {
return nil, err
}
policyObject, err := policyInfo(ctx, client, name)
if err != nil {
return nil, err
}
return policyObject, nil
}
// getAddPolicyResponse performs addPolicy() and serializes it to the handler's output
func getAddPolicyResponse(session *models.Principal, params policyApi.AddPolicyParams) (*models.Policy, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
if params.Body == nil {
return nil, ErrorWithContext(ctx, ErrPolicyBodyNotInRequest)
}
if strings.Contains(*params.Body.Name, " ") {
return nil, ErrorWithContext(ctx, ErrPolicyNameContainsSpace)
}
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
policy, err := addPolicy(ctx, adminClient, *params.Body.Name, *params.Body.Policy)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return policy, nil
}
// policyInfo calls MinIO server to retrieve information of a canned policy.
// policyInfo() takes a policy name, obtains the []byte (represents a string in JSON format)
// and return it as *models.Policy , in the future this will change
// to a Policy struct{} - https://github.com/minio/minio/issues/9171
func policyInfo(ctx context.Context, client MinioAdmin, name string) (*models.Policy, error) {
policyRaw, err := client.getPolicy(ctx, name)
if err != nil {
return nil, err
}
policy, err := parsePolicy(name, policyRaw)
if err != nil {
return nil, err
}
return policy, nil
}
// getPolicy Statements calls MinIO server to retrieve information of a canned policy.
// and returns the associated Statements
func getPolicyStatements(ctx context.Context, client MinioAdmin, name string) ([]iampolicy.Statement, error) {
policyRaw, err := client.getPolicy(ctx, name)
if err != nil {
return nil, err
}
return policyRaw.Statements, nil
}
// getPolicyInfoResponse performs policyInfo() and serializes it to the handler's output
func getPolicyInfoResponse(session *models.Principal, params policyApi.PolicyInfoParams) (*models.Policy, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
policyName, err := utils.DecodeBase64(params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
policy, err := policyInfo(ctx, adminClient, policyName)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return policy, nil
}
// SetPolicy calls MinIO server to assign policy to a group or user.
func SetPolicy(ctx context.Context, client MinioAdmin, name, entityName string, entityType models.PolicyEntity) error {
isGroup := false
if entityType == models.PolicyEntityGroup {
isGroup = true
}
return client.setPolicy(ctx, name, entityName, isGroup)
}
// getSetPolicyResponse() performs SetPolicy() and serializes it to the handler's output
func getSetPolicyResponse(session *models.Principal, params policyApi.SetPolicyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
// Removing this section
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
if err := SetPolicy(ctx, adminClient, strings.Join(params.Body.Name, ","), *params.Body.EntityName, *params.Body.EntityType); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
func getSetPolicyMultipleResponse(session *models.Principal, params policyApi.SetPolicyMultipleParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
if err := setPolicyMultipleEntities(ctx, adminClient, strings.Join(params.Body.Name, ","), params.Body.Users, params.Body.Groups); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
// setPolicyMultipleEntities sets a policy to multiple users/groups
func setPolicyMultipleEntities(ctx context.Context, client MinioAdmin, policyName string, users, groups []models.IamEntity) error {
for _, user := range users {
if err := client.setPolicy(ctx, policyName, string(user), false); err != nil {
return err
}
}
for _, group := range groups {
groupDesc, err := groupInfo(ctx, client, string(group))
if err != nil {
return err
}
allGroupPolicies := ""
if len(groups) > 1 {
allGroupPolicies = groupDesc.Policy + "," + policyName
s := strings.Split(allGroupPolicies, ",")
allGroupPolicies = strings.Join(UniqueKeys(s), ",")
} else {
allGroupPolicies = policyName
}
if err := client.setPolicy(ctx, allGroupPolicies, string(group), true); err != nil {
return err
}
}
return nil
}
// parsePolicy() converts from *rawPolicy to *models.Policy
func parsePolicy(name string, rawPolicy *iampolicy.Policy) (*models.Policy, error) {
stringPolicy, err := json.Marshal(rawPolicy)
if err != nil {
return nil, err
}
policy := &models.Policy{
Name: name,
Policy: string(stringPolicy),
}
return policy, nil
}

View File

@@ -1,63 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"io"
"net/http"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
"github.com/minio/websocket"
)
var items []*models.StartProfilingItem
type profileOptions struct {
Types string
}
func getProfileOptionsFromReq(req *http.Request) (*profileOptions, error) {
pOptions := profileOptions{}
pOptions.Types = req.FormValue("types")
return &pOptions, nil
}
func startProfiling(ctx context.Context, conn WSConn, client MinioAdmin, pOpts *profileOptions) error {
profilingResults, err := client.startProfiling(ctx, madmin.ProfilerType(pOpts.Types))
if err != nil {
return err
}
items = []*models.StartProfilingItem{}
for _, result := range profilingResults {
items = append(items, &models.StartProfilingItem{
Success: result.Success,
Error: result.Error,
NodeName: result.NodeName,
})
}
zippedData, err := client.stopProfiling(ctx)
if err != nil {
return err
}
message, err := io.ReadAll(zippedData)
if err != nil {
return err
}
return conn.writeMessage(websocket.BinaryMessage, message)
}

View File

@@ -1,105 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"bytes"
"context"
"errors"
"io"
"net/http"
"net/url"
"testing"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
)
// Implementing fake closingBuffer to mock stopProfiling() (io.ReadCloser, error)
type ClosingBuffer struct {
*bytes.Buffer
}
// Implementing a fake Close function for io.ReadCloser
func (cb *ClosingBuffer) Close() error {
return nil
}
func TestStartProfiling(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
assert := assert.New(t)
adminClient := AdminClientMock{}
mockWSConn := mockConn{}
function := "startProfiling()"
testOptions := &profileOptions{
Types: "cpu",
}
// Test-1 : startProfiling() Get response from MinIO server with one profiling object without errors
// mock function response from startProfiling()
minioStartProfiling = func(_ madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
return []madmin.StartProfilingResult{
{
NodeName: "http://127.0.0.1:9000/",
Success: true,
Error: "",
},
{
NodeName: "http://127.0.0.1:9001/",
Success: true,
Error: "",
},
}, nil
}
// mock function response from stopProfiling()
minioStopProfiling = func() (io.ReadCloser, error) {
return &ClosingBuffer{bytes.NewBufferString("In memory string eaeae")}, nil
}
// mock function response from mockConn.writeMessage()
connWriteMessageMock = func(_ int, _ []byte) error {
return nil
}
err := startProfiling(ctx, mockWSConn, adminClient, testOptions)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
assert.Equal(err, nil)
// Test-2 : startProfiling() Correctly handles errors returned by MinIO
// mock function response from startProfiling()
minioStartProfiling = func(_ madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
return nil, errors.New("error")
}
err = startProfiling(ctx, mockWSConn, adminClient, testOptions)
if assert.Error(err) {
assert.Equal("error", err.Error())
}
// Test-3: getProfileOptionsFromReq() correctly returns profile options from request
u, _ := url.Parse("ws://localhost/ws/profile?types=cpu,mem,block,mutex,trace,threads,goroutines")
req := &http.Request{
URL: u,
}
opts, err := getProfileOptionsFromReq(req)
if assert.NoError(err) {
expectedOptions := profileOptions{
Types: "cpu,mem,block,mutex,trace,threads,goroutines",
}
assert.Equal(expectedOptions.Types, opts.Types)
}
}

View File

@@ -1,116 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
"github.com/minio/console/pkg/utils"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
release "github.com/minio/console/api/operations/release"
"github.com/minio/console/models"
"github.com/minio/pkg/v2/env"
)
var (
releaseServiceHostEnvVar = "RELEASE_SERVICE_HOST"
defaultReleaseServiceHost = "https://enterprise-updates.ic.min.dev"
)
func registerReleasesHandlers(api *operations.ConsoleAPI) {
api.ReleaseListReleasesHandler = release.ListReleasesHandlerFunc(func(params release.ListReleasesParams, session *models.Principal) middleware.Responder {
resp, err := GetReleaseListResponse(session, params)
if err != nil {
return release.NewListReleasesDefault(err.Code).WithPayload(err.APIError)
}
return release.NewListReleasesOK().WithPayload(resp)
})
}
func GetReleaseListResponse(_ *models.Principal, params release.ListReleasesParams) (*models.ReleaseListResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
repo := params.Repo
currentRelease := ""
if params.Current != nil {
currentRelease = *params.Current
}
search := ""
if params.Search != nil {
search = *params.Search
}
filter := ""
if params.Filter != nil {
filter = *params.Filter
}
ctx = context.WithValue(ctx, utils.ContextClientIP, getClientIP(params.HTTPRequest))
return releaseList(ctx, repo, currentRelease, search, filter)
}
func releaseList(ctx context.Context, repo, currentRelease, search, filter string) (*models.ReleaseListResponse, *CodedAPIError) {
serviceURL := getReleaseServiceURL()
clientIP := utils.ClientIPFromContext(ctx)
releases, err := getReleases(serviceURL, repo, currentRelease, search, filter, clientIP)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return releases, nil
}
func getReleaseServiceURL() string {
host := env.Get(releaseServiceHostEnvVar, defaultReleaseServiceHost)
return fmt.Sprintf("%s/releases", host)
}
func getReleases(endpoint, repo, currentRelease, search, filter, clientIP string) (*models.ReleaseListResponse, error) {
rl := &models.ReleaseListResponse{}
req, err := http.NewRequest(http.MethodGet, endpoint, nil)
if err != nil {
return nil, err
}
q := &url.Values{}
q.Add("repo", repo)
q.Add("search", search)
q.Add("filter", filter)
q.Add("current", currentRelease)
req.URL.RawQuery = q.Encode()
req.Header.Set("Content-Type", "application/json")
client := GetConsoleHTTPClient("", clientIP)
client.Timeout = time.Second * 5
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error getting releases: %s", resp.Status)
}
err = json.NewDecoder(resp.Body).Decode(&rl)
if err != nil {
return nil, err
}
return rl, nil
}

View File

@@ -1,104 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/minio/console/api/operations"
release "github.com/minio/console/api/operations/release"
"github.com/minio/console/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type ReleasesTestSuite struct {
suite.Suite
assert *assert.Assertions
currentServer string
isServerSet bool
getServer *httptest.Server
withError bool
}
func (suite *ReleasesTestSuite) SetupSuite() {
suite.assert = assert.New(suite.T())
suite.getServer = httptest.NewServer(http.HandlerFunc(suite.getHandler))
suite.currentServer, suite.isServerSet = os.LookupEnv(releaseServiceHostEnvVar)
os.Setenv(releaseServiceHostEnvVar, suite.getServer.URL)
}
func (suite *ReleasesTestSuite) TearDownSuite() {
if suite.isServerSet {
os.Setenv(releaseServiceHostEnvVar, suite.currentServer)
} else {
os.Unsetenv(releaseServiceHostEnvVar)
}
}
func (suite *ReleasesTestSuite) getHandler(
w http.ResponseWriter, _ *http.Request,
) {
if suite.withError {
w.WriteHeader(400)
} else {
w.WriteHeader(200)
response := &models.ReleaseListResponse{}
bytes, _ := json.Marshal(response)
fmt.Fprint(w, string(bytes))
}
}
func (suite *ReleasesTestSuite) TestRegisterReleasesHandlers() {
api := &operations.ConsoleAPI{}
suite.assert.Nil(api.ReleaseListReleasesHandler)
registerReleasesHandlers(api)
suite.assert.NotNil(api.ReleaseListReleasesHandler)
}
func (suite *ReleasesTestSuite) TestGetReleasesWithError() {
api := &operations.ConsoleAPI{}
current := "mock"
registerReleasesHandlers(api)
params := release.NewListReleasesParams()
params.Current = &current
params.HTTPRequest = &http.Request{}
suite.withError = true
response := api.ReleaseListReleasesHandler.Handle(params, &models.Principal{})
_, ok := response.(*release.ListReleasesDefault)
suite.assert.True(ok)
}
func (suite *ReleasesTestSuite) TestGetReleasesWithoutError() {
api := &operations.ConsoleAPI{}
registerReleasesHandlers(api)
params := release.NewListReleasesParams()
params.HTTPRequest = &http.Request{}
suite.withError = false
response := api.ReleaseListReleasesHandler.Handle(params, &models.Principal{})
_, ok := response.(*release.ListReleasesOK)
suite.assert.True(ok)
}
func TestReleases(t *testing.T) {
suite.Run(t, new(ReleasesTestSuite))
}

View File

@@ -1,386 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/minio/console/pkg/utils"
"github.com/go-openapi/swag"
"github.com/minio/console/api/operations"
bucketApi "github.com/minio/console/api/operations/bucket"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type RemoteBucketsTestSuite struct {
suite.Suite
assert *assert.Assertions
currentServer string
isServerSet bool
server *httptest.Server
adminClient AdminClientMock
minioClient minioClientMock
mockRemoteBucket *models.RemoteBucket
mockBucketTarget *madmin.BucketTarget
mockListBuckets *models.ListBucketsResponse
}
func (suite *RemoteBucketsTestSuite) SetupSuite() {
suite.assert = assert.New(suite.T())
suite.adminClient = AdminClientMock{}
suite.minioClient = minioClientMock{}
suite.mockObjects()
}
func (suite *RemoteBucketsTestSuite) mockObjects() {
suite.mockListBuckets = &models.ListBucketsResponse{
Buckets: []*models.Bucket{},
Total: 0,
}
suite.mockRemoteBucket = &models.RemoteBucket{
AccessKey: swag.String("accessKey"),
SecretKey: "secretKey",
RemoteARN: swag.String("remoteARN"),
Service: "replication",
SourceBucket: swag.String("sourceBucket"),
TargetBucket: "targetBucket",
TargetURL: "targetURL",
Status: "",
}
suite.mockBucketTarget = &madmin.BucketTarget{
Credentials: &madmin.Credentials{
AccessKey: *suite.mockRemoteBucket.AccessKey,
SecretKey: suite.mockRemoteBucket.SecretKey,
},
Arn: *suite.mockRemoteBucket.RemoteARN,
SourceBucket: *suite.mockRemoteBucket.SourceBucket,
TargetBucket: suite.mockRemoteBucket.TargetBucket,
Endpoint: suite.mockRemoteBucket.TargetURL,
}
}
func (suite *RemoteBucketsTestSuite) SetupTest() {
suite.server = httptest.NewServer(http.HandlerFunc(suite.serverHandler))
suite.currentServer, suite.isServerSet = os.LookupEnv(ConsoleMinIOServer)
os.Setenv(ConsoleMinIOServer, suite.server.URL)
}
func (suite *RemoteBucketsTestSuite) serverHandler(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(400)
}
func (suite *RemoteBucketsTestSuite) TearDownSuite() {
}
func (suite *RemoteBucketsTestSuite) TearDownTest() {
if suite.isServerSet {
os.Setenv(ConsoleMinIOServer, suite.currentServer)
} else {
os.Unsetenv(ConsoleMinIOServer)
}
}
func (suite *RemoteBucketsTestSuite) TestRegisterRemoteBucketsHandlers() {
api := &operations.ConsoleAPI{}
suite.assertHandlersAreNil(api)
registerAdminBucketRemoteHandlers(api)
suite.assertHandlersAreNotNil(api)
}
func (suite *RemoteBucketsTestSuite) assertHandlersAreNil(api *operations.ConsoleAPI) {
suite.assert.Nil(api.BucketListRemoteBucketsHandler)
suite.assert.Nil(api.BucketRemoteBucketDetailsHandler)
suite.assert.Nil(api.BucketDeleteRemoteBucketHandler)
suite.assert.Nil(api.BucketAddRemoteBucketHandler)
suite.assert.Nil(api.BucketSetMultiBucketReplicationHandler)
suite.assert.Nil(api.BucketListExternalBucketsHandler)
suite.assert.Nil(api.BucketDeleteBucketReplicationRuleHandler)
suite.assert.Nil(api.BucketDeleteAllReplicationRulesHandler)
suite.assert.Nil(api.BucketDeleteSelectedReplicationRulesHandler)
suite.assert.Nil(api.BucketUpdateMultiBucketReplicationHandler)
}
func (suite *RemoteBucketsTestSuite) assertHandlersAreNotNil(api *operations.ConsoleAPI) {
suite.assert.NotNil(api.BucketListRemoteBucketsHandler)
suite.assert.NotNil(api.BucketRemoteBucketDetailsHandler)
suite.assert.NotNil(api.BucketDeleteRemoteBucketHandler)
suite.assert.NotNil(api.BucketAddRemoteBucketHandler)
suite.assert.NotNil(api.BucketSetMultiBucketReplicationHandler)
suite.assert.NotNil(api.BucketListExternalBucketsHandler)
suite.assert.NotNil(api.BucketDeleteBucketReplicationRuleHandler)
suite.assert.NotNil(api.BucketDeleteAllReplicationRulesHandler)
suite.assert.NotNil(api.BucketDeleteSelectedReplicationRulesHandler)
suite.assert.NotNil(api.BucketUpdateMultiBucketReplicationHandler)
}
func (suite *RemoteBucketsTestSuite) TestListRemoteBucketsHandlerWithError() {
params, api := suite.initListRemoteBucketsRequest()
response := api.BucketListRemoteBucketsHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.ListRemoteBucketsDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initListRemoteBucketsRequest() (params bucketApi.ListRemoteBucketsParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestListRemoteBucketsWithoutError() {
ctx := context.Background()
minioListRemoteBucketsMock = func(_ context.Context, _, _ string) (targets []madmin.BucketTarget, err error) {
return []madmin.BucketTarget{{
Credentials: &madmin.Credentials{
AccessKey: "accessKey",
SecretKey: "secretKey",
},
}}, nil
}
res, err := listRemoteBuckets(ctx, &suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *RemoteBucketsTestSuite) TestRemoteBucketDetailsHandlerWithError() {
params, api := suite.initRemoteBucketDetailsRequest()
response := api.BucketRemoteBucketDetailsHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.RemoteBucketDetailsDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initRemoteBucketDetailsRequest() (params bucketApi.RemoteBucketDetailsParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestGetRemoteBucketWithoutError() {
ctx := context.Background()
minioGetRemoteBucketMock = func(_ context.Context, _, _ string) (targets *madmin.BucketTarget, err error) {
return suite.mockBucketTarget, nil
}
res, err := getRemoteBucket(ctx, &suite.adminClient, "bucketName")
suite.assert.Nil(err)
suite.assert.NotNil(res)
suite.assert.Equal(suite.mockRemoteBucket, res)
}
func (suite *RemoteBucketsTestSuite) TestDeleteRemoteBucketHandlerWithError() {
params, api := suite.initDeleteRemoteBucketRequest()
response := api.BucketDeleteRemoteBucketHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.DeleteRemoteBucketDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initDeleteRemoteBucketRequest() (params bucketApi.DeleteRemoteBucketParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestAddRemoteBucketHandlerWithError() {
params, api := suite.initAddRemoteBucketRequest()
response := api.BucketAddRemoteBucketHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.AddRemoteBucketDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initAddRemoteBucketRequest() (params bucketApi.AddRemoteBucketParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
url := "^&*&^%^"
accessKey := "accessKey"
secretKey := "secretKey"
params.HTTPRequest = &http.Request{}
params.Body = &models.CreateRemoteBucket{
TargetURL: &url,
AccessKey: &accessKey,
SecretKey: &secretKey,
}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestAddRemoteBucketWithoutError() {
ctx := context.Background()
minioAddRemoteBucketMock = func(_ context.Context, _ string, _ *madmin.BucketTarget) (string, error) {
return "bucketName", nil
}
url := "https://localhost"
accessKey := "accessKey"
secretKey := "secretKey"
targetBucket := "targetBucket"
syncMode := "async"
sourceBucket := "sourceBucket"
data := models.CreateRemoteBucket{
TargetURL: &url,
TargetBucket: &targetBucket,
AccessKey: &accessKey,
SecretKey: &secretKey,
SyncMode: &syncMode,
HealthCheckPeriod: 10,
SourceBucket: &sourceBucket,
}
res, err := addRemoteBucket(ctx, &suite.adminClient, data)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *RemoteBucketsTestSuite) TestSetMultiBucketReplicationHandlerWithError() {
params, api := suite.initSetMultiBucketReplicationRequest()
response := api.BucketSetMultiBucketReplicationHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.SetMultiBucketReplicationOK)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initSetMultiBucketReplicationRequest() (params bucketApi.SetMultiBucketReplicationParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
accessKey := "accessKey"
secretKey := "secretKey"
targetURL := "https://localhost"
syncMode := "async"
params.HTTPRequest = &http.Request{}
params.Body = &models.MultiBucketReplication{
BucketsRelation: []*models.MultiBucketsRelation{{}},
AccessKey: &accessKey,
SecretKey: &secretKey,
Region: "region",
TargetURL: &targetURL,
SyncMode: &syncMode,
Bandwidth: 10,
HealthCheckPeriod: 10,
}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestListExternalBucketsHandlerWithError() {
params, api := suite.initListExternalBucketsRequest()
response := api.BucketListExternalBucketsHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.ListExternalBucketsDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initListExternalBucketsRequest() (params bucketApi.ListExternalBucketsParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
url := "http://localhost:9000"
accessKey := "accessKey"
secretKey := "secretKey"
tls := false
params.HTTPRequest = &http.Request{}
params.Body = &models.ListExternalBucketsParams{
TargetURL: &url,
AccessKey: &accessKey,
SecretKey: &secretKey,
UseTLS: &tls,
}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestListExternalBucketsWithError() {
ctx := context.Background()
minioAccountInfoMock = func(_ context.Context) (madmin.AccountInfo, error) {
return madmin.AccountInfo{}, errors.New("error")
}
res, err := listExternalBuckets(ctx, &suite.adminClient)
suite.assert.NotNil(err)
suite.assert.Nil(res)
}
func (suite *RemoteBucketsTestSuite) TestListExternalBucketsWithoutError() {
ctx := context.Background()
minioAccountInfoMock = func(_ context.Context) (madmin.AccountInfo, error) {
return madmin.AccountInfo{
Buckets: []madmin.BucketAccessInfo{},
}, nil
}
res, err := listExternalBuckets(ctx, &suite.adminClient)
suite.assert.Nil(err)
suite.assert.NotNil(res)
suite.assert.Equal(suite.mockListBuckets, res)
}
func (suite *RemoteBucketsTestSuite) TestDeleteBucketReplicationRuleHandlerWithError() {
params, api := suite.initDeleteBucketReplicationRuleRequest()
response := api.BucketDeleteBucketReplicationRuleHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.DeleteBucketReplicationRuleDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initDeleteBucketReplicationRuleRequest() (params bucketApi.DeleteBucketReplicationRuleParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestDeleteAllReplicationRulesHandlerWithError() {
params, api := suite.initDeleteAllReplicationRulesRequest()
response := api.BucketDeleteAllReplicationRulesHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.DeleteAllReplicationRulesDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initDeleteAllReplicationRulesRequest() (params bucketApi.DeleteAllReplicationRulesParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestDeleteSelectedReplicationRulesHandlerWithError() {
params, api := suite.initDeleteSelectedReplicationRulesRequest()
response := api.BucketDeleteSelectedReplicationRulesHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.DeleteSelectedReplicationRulesDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initDeleteSelectedReplicationRulesRequest() (params bucketApi.DeleteSelectedReplicationRulesParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
params.BucketName = "bucketName"
params.Rules = &models.BucketReplicationRuleList{
Rules: []string{"rule1", "rule2"},
}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestUpdateMultiBucketReplicationHandlerWithError() {
params, api := suite.initUpdateMultiBucketReplicationRequest()
response := api.BucketUpdateMultiBucketReplicationHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.UpdateMultiBucketReplicationDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initUpdateMultiBucketReplicationRequest() (params bucketApi.UpdateMultiBucketReplicationParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
r := &http.Request{}
ctx := context.WithValue(context.Background(), utils.ContextClientIP, "127.0.0.1")
rc := r.WithContext(ctx)
params.HTTPRequest = rc
params.Body = &models.MultiBucketReplicationEdit{}
return params, api
}
func TestRemoteBuckets(t *testing.T) {
suite.Run(t, new(RemoteBucketsTestSuite))
}

View File

@@ -1,68 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"errors"
"testing"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
)
func TestServiceRestart(t *testing.T) {
assert := assert.New(t)
adminClient := AdminClientMock{}
ctx := context.Background()
function := "serviceRestart()"
// Test-1 : serviceRestart() restart services no errors
// mock function response from listGroups()
minioServiceRestartMock = func(_ context.Context) error {
return nil
}
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{}, nil
}
if err := serviceRestart(ctx, adminClient); err != nil {
t.Errorf("Failed on %s:, errors occurred: %s", function, err.Error())
}
// Test-2 : serviceRestart() returns errors on client.serviceRestart call
// and see that the errors is handled correctly and returned
minioServiceRestartMock = func(_ context.Context) error {
return errors.New("error")
}
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{}, nil
}
if err := serviceRestart(ctx, adminClient); assert.Error(err) {
assert.Equal("error", err.Error())
}
// Test-3 : serviceRestart() returns errors on client.serverInfo() call
// and see that the errors is handled correctly and returned
minioServiceRestartMock = func(_ context.Context) error {
return nil
}
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{}, errors.New("error on server info")
}
if err := serviceRestart(ctx, adminClient); assert.Error(err) {
assert.Equal("error on server info", err.Error())
}
}

View File

@@ -1,255 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// These tests are for AdminAPI Tag based on swagger-console.yml
package api
import (
"context"
"fmt"
"testing"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
)
func TestGetSiteReplicationInfo(t *testing.T) {
assert := assert.New(t)
// mock minIO client
adminClient := AdminClientMock{}
function := "getSiteReplicationInfo()"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
retValueMock := madmin.SiteReplicationInfo{
Enabled: true,
Name: "site1",
Sites: []madmin.PeerInfo{
{
Endpoint: "http://localhost:9000",
Name: "site1",
DeploymentID: "12345",
},
{
Endpoint: "http://localhost:9001",
Name: "site2",
DeploymentID: "123456",
},
},
ServiceAccountAccessKey: "test-key",
}
expValueMock := &madmin.SiteReplicationInfo{
Enabled: true,
Name: "site1",
Sites: []madmin.PeerInfo{
{
Endpoint: "http://localhost:9000",
Name: "site1",
DeploymentID: "12345",
},
{
Endpoint: "http://localhost:9001",
Name: "site2",
DeploymentID: "123456",
},
},
ServiceAccountAccessKey: "test-key",
}
getSiteReplicationInfo = func(_ context.Context) (info *madmin.SiteReplicationInfo, err error) {
return &retValueMock, nil
}
srInfo, err := adminClient.getSiteReplicationInfo(ctx)
assert.Nil(err)
assert.Equal(expValueMock, srInfo, fmt.Sprintf("Failed on %s: length of lists is not the same", function))
}
func TestAddSiteReplicationInfo(t *testing.T) {
assert := assert.New(t)
// mock minIO client
adminClient := AdminClientMock{}
function := "addSiteReplicationInfo()"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
retValueMock := &madmin.ReplicateAddStatus{
Success: true,
Status: "success",
ErrDetail: "",
InitialSyncErrorMessage: "",
}
expValueMock := &madmin.ReplicateAddStatus{
Success: true,
Status: "success",
ErrDetail: "",
InitialSyncErrorMessage: "",
}
addSiteReplicationInfo = func(_ context.Context, _ []madmin.PeerSite) (res *madmin.ReplicateAddStatus, err error) {
return retValueMock, nil
}
sites := []madmin.PeerSite{
{
Name: "site1",
Endpoint: "http://localhost:9000",
AccessKey: "test",
SecretKey: "test",
},
{
Name: "site2",
Endpoint: "http://localhost:9001",
AccessKey: "test",
SecretKey: "test",
},
}
srInfo, err := adminClient.addSiteReplicationInfo(ctx, sites, madmin.SRAddOptions{})
assert.Nil(err)
assert.Equal(expValueMock, srInfo, fmt.Sprintf("Failed on %s: length of lists is not the same", function))
}
func TestEditSiteReplicationInfo(t *testing.T) {
assert := assert.New(t)
// mock minIO client
adminClient := AdminClientMock{}
function := "editSiteReplicationInfo()"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
retValueMock := &madmin.ReplicateEditStatus{
Success: true,
Status: "success",
ErrDetail: "",
}
expValueMock := &madmin.ReplicateEditStatus{
Success: true,
Status: "success",
ErrDetail: "",
}
editSiteReplicationInfo = func(_ context.Context, _ madmin.PeerInfo) (res *madmin.ReplicateEditStatus, err error) {
return retValueMock, nil
}
site := madmin.PeerInfo{
Name: "",
Endpoint: "",
DeploymentID: "12345",
}
srInfo, err := adminClient.editSiteReplicationInfo(ctx, site, madmin.SREditOptions{})
assert.Nil(err)
assert.Equal(expValueMock, srInfo, fmt.Sprintf("Failed on %s: length of lists is not the same", function))
}
func TestDeleteSiteReplicationInfo(t *testing.T) {
assert := assert.New(t)
// mock minIO client
adminClient := AdminClientMock{}
function := "deleteSiteReplicationInfo()"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
retValueMock := &madmin.ReplicateRemoveStatus{
Status: "success",
ErrDetail: "",
}
expValueMock := &madmin.ReplicateRemoveStatus{
Status: "success",
ErrDetail: "",
}
deleteSiteReplicationInfoMock = func(_ context.Context, _ madmin.SRRemoveReq) (res *madmin.ReplicateRemoveStatus, err error) {
return retValueMock, nil
}
remReq := madmin.SRRemoveReq{
SiteNames: []string{
"test1",
},
RemoveAll: false,
}
srInfo, err := adminClient.deleteSiteReplicationInfo(ctx, remReq)
assert.Nil(err)
assert.Equal(expValueMock, srInfo, fmt.Sprintf("Failed on %s: length of lists is not the same", function))
}
func TestSiteReplicationStatus(t *testing.T) {
assert := assert.New(t)
// mock minIO client
adminClient := AdminClientMock{}
function := "getSiteReplicationStatus()"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
retValueMock := madmin.SRStatusInfo{
Enabled: true,
MaxBuckets: 0,
MaxUsers: 0,
MaxGroups: 0,
MaxPolicies: 0,
Sites: nil,
StatsSummary: nil,
BucketStats: nil,
PolicyStats: nil,
UserStats: nil,
GroupStats: nil,
}
expValueMock := &madmin.SRStatusInfo{
Enabled: true,
MaxBuckets: 0,
MaxUsers: 0,
MaxGroups: 0,
MaxPolicies: 0,
Sites: nil,
StatsSummary: nil,
BucketStats: nil,
PolicyStats: nil,
UserStats: nil,
GroupStats: nil,
}
getSiteReplicationStatus = func(_ context.Context, _ madmin.SRStatusOptions) (info *madmin.SRStatusInfo, err error) {
return &retValueMock, nil
}
reqValues := madmin.SRStatusOptions{
Buckets: true,
Policies: true,
Users: true,
Groups: true,
}
srInfo, err := adminClient.getSiteReplicationStatus(ctx, reqValues)
if err != nil {
assert.Error(err)
}
assert.Equal(expValueMock, srInfo, fmt.Sprintf("Failed on %s: expected result is not same", function))
}

View File

@@ -1,430 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package api
import (
"context"
"errors"
"fmt"
"net/http"
"net/url"
"os"
"github.com/minio/console/pkg/utils"
xhttp "github.com/minio/console/pkg/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
subnetApi "github.com/minio/console/api/operations/subnet"
"github.com/minio/console/models"
"github.com/minio/console/pkg/subnet"
"github.com/minio/madmin-go/v3"
)
func registerSubnetHandlers(api *operations.ConsoleAPI) {
// Get subnet login handler
api.SubnetSubnetLoginHandler = subnetApi.SubnetLoginHandlerFunc(func(params subnetApi.SubnetLoginParams, session *models.Principal) middleware.Responder {
resp, err := GetSubnetLoginResponse(session, params)
if err != nil {
return subnetApi.NewSubnetLoginDefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetLoginOK().WithPayload(resp)
})
// Get subnet login with MFA handler
api.SubnetSubnetLoginMFAHandler = subnetApi.SubnetLoginMFAHandlerFunc(func(params subnetApi.SubnetLoginMFAParams, session *models.Principal) middleware.Responder {
resp, err := GetSubnetLoginWithMFAResponse(session, params)
if err != nil {
return subnetApi.NewSubnetLoginMFADefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetLoginMFAOK().WithPayload(resp)
})
// Get subnet register
api.SubnetSubnetRegisterHandler = subnetApi.SubnetRegisterHandlerFunc(func(params subnetApi.SubnetRegisterParams, session *models.Principal) middleware.Responder {
err := GetSubnetRegisterResponse(session, params)
if err != nil {
return subnetApi.NewSubnetRegisterDefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetRegisterOK()
})
// Get subnet info
api.SubnetSubnetInfoHandler = subnetApi.SubnetInfoHandlerFunc(func(params subnetApi.SubnetInfoParams, session *models.Principal) middleware.Responder {
resp, err := GetSubnetInfoResponse(session, params)
if err != nil {
return subnetApi.NewSubnetInfoDefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetInfoOK().WithPayload(resp)
})
// Get subnet registration token
api.SubnetSubnetRegTokenHandler = subnetApi.SubnetRegTokenHandlerFunc(func(params subnetApi.SubnetRegTokenParams, session *models.Principal) middleware.Responder {
resp, err := GetSubnetRegTokenResponse(session, params)
if err != nil {
return subnetApi.NewSubnetRegTokenDefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetRegTokenOK().WithPayload(resp)
})
api.SubnetSubnetAPIKeyHandler = subnetApi.SubnetAPIKeyHandlerFunc(func(params subnetApi.SubnetAPIKeyParams, session *models.Principal) middleware.Responder {
resp, err := GetSubnetAPIKeyResponse(session, params)
if err != nil {
return subnetApi.NewSubnetAPIKeyDefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetAPIKeyOK().WithPayload(resp)
})
}
const EnvSubnetLicense = "CONSOLE_SUBNET_LICENSE"
func SubnetRegisterWithAPIKey(ctx context.Context, minioClient MinioAdmin, apiKey string) (bool, error) {
serverInfo, err := minioClient.serverInfo(ctx)
if err != nil {
return false, err
}
clientIP := utils.ClientIPFromContext(ctx)
registerResult, err := subnet.Register(GetConsoleHTTPClient("", clientIP), serverInfo, apiKey, "", "")
if err != nil {
return false, err
}
// Keep existing subnet proxy if exists
subnetKey, err := GetSubnetKeyFromMinIOConfig(ctx, minioClient)
if err != nil {
return false, err
}
configStr := fmt.Sprintf("subnet license=%s api_key=%s proxy=%s", registerResult.License, registerResult.APIKey, subnetKey.Proxy)
_, err = minioClient.setConfigKV(ctx, configStr)
if err != nil {
return false, err
}
// cluster registered correctly
return true, nil
}
func SubnetLogin(client xhttp.ClientI, username, password string) (string, string, error) {
tokens, err := subnet.Login(client, username, password)
if err != nil {
return "", "", err
}
if tokens.MfaToken != "" {
// user needs to complete login flow using mfa
return "", tokens.MfaToken, nil
}
if tokens.AccessToken != "" {
// register token to minio
return tokens.AccessToken, "", nil
}
return "", "", errors.New("something went wrong")
}
func GetSubnetLoginResponse(session *models.Principal, params subnetApi.SubnetLoginParams) (*models.SubnetLoginResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return subnetLoginResponse(ctx, AdminClient{Client: mAdmin}, params)
}
func subnetLoginResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetLoginParams) (*models.SubnetLoginResponse, *CodedAPIError) {
subnetHTTPClient, err := GetSubnetHTTPClient(ctx, minioClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
apiKey := params.Body.APIKey
if apiKey != "" {
registered, err := SubnetRegisterWithAPIKey(ctx, minioClient, apiKey)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.SubnetLoginResponse{
Registered: registered,
Organizations: []*models.SubnetOrganization{},
}, nil
}
username := params.Body.Username
password := params.Body.Password
if username != "" && password != "" {
token, mfa, err := SubnetLogin(subnetHTTPClient, username, password)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.SubnetLoginResponse{
MfaToken: mfa,
AccessToken: token,
Organizations: []*models.SubnetOrganization{},
}, nil
}
return nil, ErrorWithContext(ctx, ErrDefault)
}
type SubnetRegistration struct {
AccessToken string
MFAToken string
Organizations []models.SubnetOrganization
}
func SubnetLoginWithMFA(client xhttp.ClientI, username, mfaToken, otp string) (*models.SubnetLoginResponse, error) {
tokens, err := subnet.LoginWithMFA(client, username, mfaToken, otp)
if err != nil {
return nil, err
}
if tokens.AccessToken != "" {
organizations, errOrg := subnet.GetOrganizations(client, tokens.AccessToken)
if errOrg != nil {
return nil, errOrg
}
return &models.SubnetLoginResponse{
AccessToken: tokens.AccessToken,
Organizations: organizations,
}, nil
}
return nil, errors.New("something went wrong")
}
// GetSubnetHTTPClient will return a client with proxy if configured, otherwise will return the default console http client
func GetSubnetHTTPClient(ctx context.Context, minioClient MinioAdmin) (*xhttp.Client, error) {
clientIP := utils.ClientIPFromContext(ctx)
subnetHTTPClient := GetConsoleHTTPClient("", clientIP)
subnetKey, err := GetSubnetKeyFromMinIOConfig(ctx, minioClient)
if err != nil {
return nil, err
}
proxy := getSubnetProxy()
if subnetKey.Proxy != "" {
proxy = subnetKey.Proxy
}
if proxy != "" {
subnetProxyURL, err := url.Parse(proxy)
if err != nil {
return nil, err
}
subnetHTTPClient.Transport.(*ConsoleTransport).Transport.Proxy = http.ProxyURL(subnetProxyURL)
}
clientI := &xhttp.Client{
Client: subnetHTTPClient,
}
return clientI, nil
}
func GetSubnetLoginWithMFAResponse(session *models.Principal, params subnetApi.SubnetLoginMFAParams) (*models.SubnetLoginResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
minioClient := AdminClient{Client: mAdmin}
return subnetLoginWithMFAResponse(ctx, minioClient, params)
}
func subnetLoginWithMFAResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetLoginMFAParams) (*models.SubnetLoginResponse, *CodedAPIError) {
subnetHTTPClient, err := GetSubnetHTTPClient(ctx, minioClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
resp, err := SubnetLoginWithMFA(subnetHTTPClient, *params.Body.Username, *params.Body.MfaToken, *params.Body.Otp)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return resp, nil
}
func GetSubnetKeyFromMinIOConfig(ctx context.Context, minioClient MinioAdmin) (*subnet.LicenseTokenConfig, error) {
buf, err := minioClient.getConfigKV(ctx, madmin.SubnetSubSys)
if err != nil {
return nil, err
}
subSysConfigs, err := madmin.ParseServerConfigOutput(string(buf))
if err != nil {
return nil, err
}
for _, scfg := range subSysConfigs {
if scfg.Target == "" {
res := subnet.LicenseTokenConfig{}
res.APIKey, _ = scfg.Lookup("api_key")
res.License, _ = scfg.Lookup("license")
res.Proxy, _ = scfg.Lookup("proxy")
return &res, nil
}
}
return nil, errors.New("unable to find subnet configuration")
}
func GetSubnetRegister(ctx context.Context, minioClient MinioAdmin, httpClient xhttp.ClientI, params subnetApi.SubnetRegisterParams) error {
serverInfo, err := minioClient.serverInfo(ctx)
if err != nil {
return err
}
registerResult, err := subnet.Register(httpClient, serverInfo, "", *params.Body.Token, *params.Body.AccountID)
if err != nil {
return err
}
// Keep existing subnet proxy if exists
subnetKey, err := GetSubnetKeyFromMinIOConfig(ctx, minioClient)
if err != nil {
return err
}
configStr := fmt.Sprintf("subnet license=%s api_key=%s proxy=%s", registerResult.License, registerResult.APIKey, subnetKey.Proxy)
_, err = minioClient.setConfigKV(ctx, configStr)
if err != nil {
return err
}
return nil
}
func GetSubnetRegisterResponse(session *models.Principal, params subnetApi.SubnetRegisterParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
adminClient := AdminClient{Client: mAdmin}
return subnetRegisterResponse(ctx, adminClient, params)
}
func subnetRegisterResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetRegisterParams) *CodedAPIError {
subnetHTTPClient, err := GetSubnetHTTPClient(ctx, minioClient)
if err != nil {
return ErrorWithContext(ctx, err)
}
err = GetSubnetRegister(ctx, minioClient, subnetHTTPClient, params)
if err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
var ErrSubnetLicenseNotFound = errors.New("license not found")
func GetSubnetInfoResponse(session *models.Principal, params subnetApi.SubnetInfoParams) (*models.License, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
clientIP := utils.ClientIPFromContext(ctx)
client := &xhttp.Client{
Client: GetConsoleHTTPClient("", clientIP),
}
// license gets seeded to us by MinIO
seededLicense := os.Getenv(EnvSubnetLicense)
// if it's missing, we will gracefully fallback to attempt to fetch it from MinIO
if seededLicense == "" {
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
adminClient := AdminClient{Client: mAdmin}
configBytes, err := adminClient.getConfigKV(params.HTTPRequest.Context(), "subnet")
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
subSysConfigs, err := madmin.ParseServerConfigOutput(string(configBytes))
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// search for licese
for _, v := range subSysConfigs {
for _, sv := range v.KV {
if sv.Key == "license" {
seededLicense = sv.Value
}
}
}
}
// still empty means not found
if seededLicense == "" {
return nil, ErrorWithContext(ctx, ErrSubnetLicenseNotFound)
}
licenseInfo, err := getLicenseInfo(*client.Client, seededLicense)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
license := &models.License{
Email: licenseInfo.Email,
AccountID: licenseInfo.AccountID,
StorageCapacity: licenseInfo.StorageCapacity,
Plan: licenseInfo.Plan,
ExpiresAt: licenseInfo.ExpiresAt.String(),
Organization: licenseInfo.Organization,
}
return license, nil
}
func GetSubnetRegToken(ctx context.Context, minioClient MinioAdmin) (string, error) {
serverInfo, err := minioClient.serverInfo(ctx)
if err != nil {
return "", err
}
regInfo := subnet.GetClusterRegInfo(serverInfo)
regToken, err := subnet.GenerateRegToken(regInfo)
if err != nil {
return "", err
}
return regToken, nil
}
func GetSubnetRegTokenResponse(session *models.Principal, params subnetApi.SubnetRegTokenParams) (*models.SubnetRegTokenResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
adminClient := AdminClient{Client: mAdmin}
return subnetRegTokenResponse(ctx, adminClient)
}
func subnetRegTokenResponse(ctx context.Context, minioClient MinioAdmin) (*models.SubnetRegTokenResponse, *CodedAPIError) {
token, err := GetSubnetRegToken(ctx, minioClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.SubnetRegTokenResponse{
RegToken: token,
}, nil
}
func GetSubnetAPIKeyResponse(session *models.Principal, params subnetApi.SubnetAPIKeyParams) (*models.APIKey, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
adminClient := AdminClient{Client: mAdmin}
return subnetAPIKeyResponse(ctx, adminClient, params)
}
func subnetAPIKeyResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetAPIKeyParams) (*models.APIKey, *CodedAPIError) {
subnetHTTPClient, err := GetSubnetHTTPClient(ctx, minioClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
token := params.HTTPRequest.URL.Query().Get("token")
apiKey, err := subnet.GetAPIKey(subnetHTTPClient, token)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return &models.APIKey{APIKey: apiKey}, nil
}

View File

@@ -1,233 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"net/http"
"net/http/httptest"
"net/url"
"os"
"testing"
"github.com/minio/console/api/operations"
subnetApi "github.com/minio/console/api/operations/subnet"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type AdminSubnetTestSuite struct {
suite.Suite
assert *assert.Assertions
currentServer string
isServerSet bool
server *httptest.Server
adminClient AdminClientMock
}
func (suite *AdminSubnetTestSuite) SetupSuite() {
suite.assert = assert.New(suite.T())
suite.adminClient = AdminClientMock{}
minioGetConfigKVMock = func(_ string) ([]byte, error) {
return []byte("subnet license=mock api_key=mock proxy=http://mock.com"), nil
}
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{Servers: []madmin.ServerProperties{{}}}, nil
}
}
func (suite *AdminSubnetTestSuite) SetupTest() {
suite.server = httptest.NewServer(http.HandlerFunc(suite.serverHandler))
suite.currentServer, suite.isServerSet = os.LookupEnv(ConsoleMinIOServer)
os.Setenv(ConsoleMinIOServer, suite.server.URL)
}
func (suite *AdminSubnetTestSuite) serverHandler(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(400)
}
func (suite *AdminSubnetTestSuite) TearDownSuite() {
}
func (suite *AdminSubnetTestSuite) TearDownTest() {
if suite.isServerSet {
os.Setenv(ConsoleMinIOServer, suite.currentServer)
} else {
os.Unsetenv(ConsoleMinIOServer)
}
}
func (suite *AdminSubnetTestSuite) TestRegisterSubnetHandlers() {
api := &operations.ConsoleAPI{}
suite.assertHandlersAreNil(api)
registerSubnetHandlers(api)
suite.assertHandlersAreNotNil(api)
}
func (suite *AdminSubnetTestSuite) assertHandlersAreNil(api *operations.ConsoleAPI) {
suite.assert.Nil(api.SubnetSubnetLoginHandler)
suite.assert.Nil(api.SubnetSubnetLoginMFAHandler)
suite.assert.Nil(api.SubnetSubnetRegisterHandler)
suite.assert.Nil(api.SubnetSubnetInfoHandler)
suite.assert.Nil(api.SubnetSubnetRegTokenHandler)
suite.assert.Nil(api.SubnetSubnetAPIKeyHandler)
}
func (suite *AdminSubnetTestSuite) assertHandlersAreNotNil(api *operations.ConsoleAPI) {
suite.assert.NotNil(api.SubnetSubnetLoginHandler)
suite.assert.NotNil(api.SubnetSubnetLoginMFAHandler)
suite.assert.NotNil(api.SubnetSubnetRegisterHandler)
suite.assert.NotNil(api.SubnetSubnetInfoHandler)
suite.assert.NotNil(api.SubnetSubnetRegTokenHandler)
suite.assert.NotNil(api.SubnetSubnetAPIKeyHandler)
}
func (suite *AdminSubnetTestSuite) TestSubnetLoginWithSubnetClientError() {
params, api := suite.initSubnetLoginRequest("", "", "")
response := api.SubnetSubnetLoginHandler.Handle(params, &models.Principal{})
_, ok := response.(*subnetApi.SubnetLoginDefault)
suite.assert.True(ok)
}
func (suite *AdminSubnetTestSuite) TestSubnetLoginResponseWithApiKeyError() {
params, _ := suite.initSubnetLoginRequest("mock", "", "")
res, err := subnetLoginResponse(context.TODO(), suite.adminClient, params)
suite.assert.NotNil(err)
suite.assert.Nil(res)
}
func (suite *AdminSubnetTestSuite) TestSubnetLoginResponseWithCredentialsError() {
params, _ := suite.initSubnetLoginRequest("", "mock", "mock")
res, err := subnetLoginResponse(context.TODO(), suite.adminClient, params)
suite.assert.NotNil(err)
suite.assert.Nil(res)
}
func (suite *AdminSubnetTestSuite) initSubnetLoginRequest(apiKey, username, password string) (params subnetApi.SubnetLoginParams, api operations.ConsoleAPI) {
registerSubnetHandlers(&api)
params.HTTPRequest = &http.Request{}
params.Body = &models.SubnetLoginRequest{}
params.Body.APIKey = apiKey
params.Body.Username = username
params.Body.Password = password
return params, api
}
func (suite *AdminSubnetTestSuite) TestSubnetLoginMFAWithSubnetClientError() {
params, api := suite.initSubnetLoginMFARequest("", "", "")
response := api.SubnetSubnetLoginMFAHandler.Handle(params, &models.Principal{})
_, ok := response.(*subnetApi.SubnetLoginMFADefault)
suite.assert.True(ok)
}
func (suite *AdminSubnetTestSuite) TestSubnetLoginWithMFAResponseError() {
params, _ := suite.initSubnetLoginMFARequest("mock", "mock", "mock")
res, err := subnetLoginWithMFAResponse(context.TODO(), suite.adminClient, params)
suite.assert.NotNil(err)
suite.assert.Nil(res)
}
func (suite *AdminSubnetTestSuite) initSubnetLoginMFARequest(username, mfaToken, otp string) (params subnetApi.SubnetLoginMFAParams, api operations.ConsoleAPI) {
registerSubnetHandlers(&api)
params.HTTPRequest = &http.Request{}
params.Body = &models.SubnetLoginMFARequest{}
params.Body.Username = &username
params.Body.MfaToken = &mfaToken
params.Body.Otp = &otp
return params, api
}
func (suite *AdminSubnetTestSuite) TestSubnetRegisterClientError() {
params, api := suite.initSubnetRegisterRequest("", "")
response := api.SubnetSubnetRegisterHandler.Handle(params, &models.Principal{})
_, ok := response.(*subnetApi.SubnetRegisterDefault)
suite.assert.True(ok)
}
func (suite *AdminSubnetTestSuite) TestSubnetRegisterResponseError() {
params, _ := suite.initSubnetRegisterRequest("mock", "mock")
err := subnetRegisterResponse(context.TODO(), suite.adminClient, params)
suite.assert.NotNil(err)
}
func (suite *AdminSubnetTestSuite) initSubnetRegisterRequest(token, accountID string) (params subnetApi.SubnetRegisterParams, api operations.ConsoleAPI) {
registerSubnetHandlers(&api)
params.HTTPRequest = &http.Request{}
params.Body = &models.SubnetRegisterRequest{}
params.Body.Token = &token
params.Body.AccountID = &accountID
return params, api
}
func (suite *AdminSubnetTestSuite) TestSubnetInfoError() {
params, api := suite.initSubnetInfoRequest()
response := api.SubnetSubnetInfoHandler.Handle(params, &models.Principal{})
_, ok := response.(*subnetApi.SubnetInfoDefault)
suite.assert.True(ok)
}
func (suite *AdminSubnetTestSuite) initSubnetInfoRequest() (params subnetApi.SubnetInfoParams, api operations.ConsoleAPI) {
registerSubnetHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *AdminSubnetTestSuite) TestSubnetRegTokenError() {
params, api := suite.initSubnetRegTokenRequest()
response := api.SubnetSubnetRegTokenHandler.Handle(params, &models.Principal{})
_, ok := response.(*subnetApi.SubnetRegTokenDefault)
suite.assert.True(ok)
}
func (suite *AdminSubnetTestSuite) TestSubnetRegTokenResponse() {
res, err := subnetRegTokenResponse(context.TODO(), suite.adminClient)
suite.assert.Nil(err)
suite.assert.NotEqual("", res)
}
func (suite *AdminSubnetTestSuite) initSubnetRegTokenRequest() (params subnetApi.SubnetRegTokenParams, api operations.ConsoleAPI) {
registerSubnetHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *AdminSubnetTestSuite) TestSubnetAPIKeyWithClientError() {
params, api := suite.initSubnetAPIKeyRequest()
response := api.SubnetSubnetAPIKeyHandler.Handle(params, &models.Principal{})
_, ok := response.(*subnetApi.SubnetAPIKeyDefault)
suite.assert.True(ok)
}
func (suite *AdminSubnetTestSuite) TestSubnetAPIKeyResponseError() {
params, _ := suite.initSubnetAPIKeyRequest()
res, err := subnetAPIKeyResponse(context.TODO(), suite.adminClient, params)
suite.assert.NotNil(err)
suite.assert.Nil(res)
}
func (suite *AdminSubnetTestSuite) initSubnetAPIKeyRequest() (params subnetApi.SubnetAPIKeyParams, api operations.ConsoleAPI) {
registerSubnetHandlers(&api)
params.HTTPRequest = &http.Request{}
params.HTTPRequest.URL = &url.URL{}
return params, api
}
func TestAdminSubnet(t *testing.T) {
suite.Run(t, new(AdminSubnetTestSuite))
}

View File

@@ -1,411 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"encoding/base64"
"strconv"
"github.com/dustin/go-humanize"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
tieringApi "github.com/minio/console/api/operations/tiering"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
)
func registerAdminTiersHandlers(api *operations.ConsoleAPI) {
// return a list of notification endpoints
api.TieringTiersListHandler = tieringApi.TiersListHandlerFunc(func(params tieringApi.TiersListParams, session *models.Principal) middleware.Responder {
tierList, err := getTiersResponse(session, params)
if err != nil {
return tieringApi.NewTiersListDefault(err.Code).WithPayload(err.APIError)
}
return tieringApi.NewTiersListOK().WithPayload(tierList)
})
// add a new tiers
api.TieringAddTierHandler = tieringApi.AddTierHandlerFunc(func(params tieringApi.AddTierParams, session *models.Principal) middleware.Responder {
err := getAddTierResponse(session, params)
if err != nil {
return tieringApi.NewAddTierDefault(err.Code).WithPayload(err.APIError)
}
return tieringApi.NewAddTierCreated()
})
// get a tier
api.TieringGetTierHandler = tieringApi.GetTierHandlerFunc(func(params tieringApi.GetTierParams, session *models.Principal) middleware.Responder {
notifEndpoints, err := getGetTierResponse(session, params)
if err != nil {
return tieringApi.NewGetTierDefault(err.Code).WithPayload(err.APIError)
}
return tieringApi.NewGetTierOK().WithPayload(notifEndpoints)
})
// edit credentials for a tier
api.TieringEditTierCredentialsHandler = tieringApi.EditTierCredentialsHandlerFunc(func(params tieringApi.EditTierCredentialsParams, session *models.Principal) middleware.Responder {
err := getEditTierCredentialsResponse(session, params)
if err != nil {
return tieringApi.NewEditTierCredentialsDefault(err.Code).WithPayload(err.APIError)
}
return tieringApi.NewEditTierCredentialsOK()
})
}
// getNotificationEndpoints invokes admin info and returns a list of notification endpoints
func getTiers(ctx context.Context, client MinioAdmin) (*models.TierListResponse, error) {
tiers, err := client.listTiers(ctx)
if err != nil {
return nil, err
}
tiersInfo, err := client.tierStats(ctx)
if err != nil {
return nil, err
}
var tiersList []*models.Tier
for _, tierData := range tiers {
// Default Tier Stats
stats := madmin.TierStats{
NumObjects: 0,
NumVersions: 0,
TotalSize: 0,
}
// We look for the correct tier stats & set the values.
for _, stat := range tiersInfo {
if stat.Name == tierData.Name {
stats = stat.Stats
break
}
}
switch tierData.Type {
case madmin.S3:
tiersList = append(tiersList, &models.Tier{
Type: models.TierTypeS3,
S3: &models.TierS3{
Accesskey: tierData.S3.AccessKey,
Bucket: tierData.S3.Bucket,
Endpoint: tierData.S3.Endpoint,
Name: tierData.Name,
Prefix: tierData.S3.Prefix,
Region: tierData.S3.Region,
Secretkey: tierData.S3.SecretKey,
Storageclass: tierData.S3.StorageClass,
Usage: humanize.IBytes(stats.TotalSize),
Objects: strconv.Itoa(stats.NumObjects),
Versions: strconv.Itoa(stats.NumVersions),
},
Status: client.verifyTierStatus(ctx, tierData.Name) == nil,
})
case madmin.MinIO:
tiersList = append(tiersList, &models.Tier{
Type: models.TierTypeMinio,
Minio: &models.TierMinio{
Accesskey: tierData.MinIO.AccessKey,
Bucket: tierData.MinIO.Bucket,
Endpoint: tierData.MinIO.Endpoint,
Name: tierData.Name,
Prefix: tierData.MinIO.Prefix,
Region: tierData.MinIO.Region,
Secretkey: tierData.MinIO.SecretKey,
Usage: humanize.IBytes(stats.TotalSize),
Objects: strconv.Itoa(stats.NumObjects),
Versions: strconv.Itoa(stats.NumVersions),
},
Status: client.verifyTierStatus(ctx, tierData.Name) == nil,
})
case madmin.GCS:
tiersList = append(tiersList, &models.Tier{
Type: models.TierTypeGcs,
Gcs: &models.TierGcs{
Bucket: tierData.GCS.Bucket,
Creds: tierData.GCS.Creds,
Endpoint: tierData.GCS.Endpoint,
Name: tierData.Name,
Prefix: tierData.GCS.Prefix,
Region: tierData.GCS.Region,
Usage: humanize.IBytes(stats.TotalSize),
Objects: strconv.Itoa(stats.NumObjects),
Versions: strconv.Itoa(stats.NumVersions),
},
Status: client.verifyTierStatus(ctx, tierData.Name) == nil,
})
case madmin.Azure:
tiersList = append(tiersList, &models.Tier{
Type: models.TierTypeAzure,
Azure: &models.TierAzure{
Accountkey: tierData.Azure.AccountKey,
Accountname: tierData.Azure.AccountName,
Bucket: tierData.Azure.Bucket,
Endpoint: tierData.Azure.Endpoint,
Name: tierData.Name,
Prefix: tierData.Azure.Prefix,
Region: tierData.Azure.Region,
Usage: humanize.IBytes(stats.TotalSize),
Objects: strconv.Itoa(stats.NumObjects),
Versions: strconv.Itoa(stats.NumVersions),
},
Status: client.verifyTierStatus(ctx, tierData.Name) == nil,
})
case madmin.Unsupported:
tiersList = append(tiersList, &models.Tier{
Type: models.TierTypeUnsupported,
Status: client.verifyTierStatus(ctx, tierData.Name) == nil,
})
}
}
// build response
return &models.TierListResponse{
Items: tiersList,
}, nil
}
// getTiersResponse returns a response with a list of tiers
func getTiersResponse(session *models.Principal, params tieringApi.TiersListParams) (*models.TierListResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
// serialize output
tiersResp, err := getTiers(ctx, adminClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return tiersResp, nil
}
func addTier(ctx context.Context, client MinioAdmin, params *tieringApi.AddTierParams) error {
var cfg *madmin.TierConfig
var err error
switch params.Body.Type {
case models.TierTypeS3:
cfg, err = madmin.NewTierS3(
params.Body.S3.Name,
params.Body.S3.Accesskey,
params.Body.S3.Secretkey,
params.Body.S3.Bucket,
madmin.S3Region(params.Body.S3.Region),
madmin.S3Prefix(params.Body.S3.Prefix),
madmin.S3Endpoint(params.Body.S3.Endpoint),
madmin.S3StorageClass(params.Body.S3.Storageclass),
)
if err != nil {
return err
}
case models.TierTypeMinio:
cfg, err = madmin.NewTierMinIO(
params.Body.Minio.Name,
params.Body.Minio.Endpoint,
params.Body.Minio.Accesskey,
params.Body.Minio.Secretkey,
params.Body.Minio.Bucket,
madmin.MinIORegion(params.Body.Minio.Region),
madmin.MinIOPrefix(params.Body.Minio.Prefix),
)
if err != nil {
return err
}
case models.TierTypeGcs:
gcsOpts := []madmin.GCSOptions{}
prefix := params.Body.Gcs.Prefix
if prefix != "" {
gcsOpts = append(gcsOpts, madmin.GCSPrefix(prefix))
}
region := params.Body.Gcs.Region
if region != "" {
gcsOpts = append(gcsOpts, madmin.GCSRegion(region))
}
base64Text := make([]byte, base64.StdEncoding.EncodedLen(len(params.Body.Gcs.Creds)))
l, _ := base64.StdEncoding.Decode(base64Text, []byte(params.Body.Gcs.Creds))
cfg, err = madmin.NewTierGCS(
params.Body.Gcs.Name,
base64Text[:l],
params.Body.Gcs.Bucket,
gcsOpts...,
)
if err != nil {
return err
}
case models.TierTypeAzure:
cfg, err = madmin.NewTierAzure(
params.Body.Azure.Name,
params.Body.Azure.Accountname,
params.Body.Azure.Accountkey,
params.Body.Azure.Bucket,
madmin.AzurePrefix(params.Body.Azure.Prefix),
madmin.AzureEndpoint(params.Body.Azure.Endpoint),
madmin.AzureRegion(params.Body.Azure.Region),
)
if err != nil {
return err
}
case models.TierTypeUnsupported:
cfg = &madmin.TierConfig{
Type: madmin.Unsupported,
}
}
err = client.addTier(ctx, cfg)
if err != nil {
return err
}
return nil
}
// getAddTierResponse returns the response of admin tier
func getAddTierResponse(session *models.Principal, params tieringApi.AddTierParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
// serialize output
errTier := addTier(ctx, adminClient, &params)
if errTier != nil {
return ErrorWithContext(ctx, errTier)
}
return nil
}
func getTier(ctx context.Context, client MinioAdmin, params *tieringApi.GetTierParams) (*models.Tier, error) {
tiers, err := client.listTiers(ctx)
if err != nil {
return nil, err
}
for i := range tiers {
switch tiers[i].Type {
case madmin.S3:
if params.Type != models.TierTypeS3 || tiers[i].Name != params.Name {
continue
}
return &models.Tier{
Type: models.TierTypeS3,
S3: &models.TierS3{
Accesskey: tiers[i].S3.AccessKey,
Bucket: tiers[i].S3.Bucket,
Endpoint: tiers[i].S3.Endpoint,
Name: tiers[i].Name,
Prefix: tiers[i].S3.Prefix,
Region: tiers[i].S3.Region,
Secretkey: tiers[i].S3.SecretKey,
Storageclass: tiers[i].S3.StorageClass,
},
}, err
case madmin.GCS:
if params.Type != models.TierTypeGcs || tiers[i].Name != params.Name {
continue
}
return &models.Tier{
Type: models.TierTypeGcs,
Gcs: &models.TierGcs{
Bucket: tiers[i].GCS.Bucket,
Creds: tiers[i].GCS.Creds,
Endpoint: tiers[i].GCS.Endpoint,
Name: tiers[i].Name,
Prefix: tiers[i].GCS.Prefix,
Region: tiers[i].GCS.Region,
},
}, nil
case madmin.Azure:
if params.Type != models.TierTypeAzure || tiers[i].Name != params.Name {
continue
}
return &models.Tier{
Type: models.TierTypeAzure,
Azure: &models.TierAzure{
Accountkey: tiers[i].Azure.AccountKey,
Accountname: tiers[i].Azure.AccountName,
Bucket: tiers[i].Azure.Bucket,
Endpoint: tiers[i].Azure.Endpoint,
Name: tiers[i].Name,
Prefix: tiers[i].Azure.Prefix,
Region: tiers[i].Azure.Region,
},
}, nil
}
}
// build response
return nil, ErrNotFound
}
// getGetTierResponse returns a tier
func getGetTierResponse(session *models.Principal, params tieringApi.GetTierParams) (*models.Tier, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
// serialize output
addTierResp, err := getTier(ctx, adminClient, &params)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return addTierResp, nil
}
func editTierCredentials(ctx context.Context, client MinioAdmin, params *tieringApi.EditTierCredentialsParams) error {
base64Text := make([]byte, base64.StdEncoding.EncodedLen(len(params.Body.Creds)))
l, err := base64.StdEncoding.Decode(base64Text, []byte(params.Body.Creds))
if err != nil {
return err
}
creds := madmin.TierCreds{
AccessKey: params.Body.AccessKey,
SecretKey: params.Body.SecretKey,
CredsJSON: base64Text[:l],
}
return client.editTierCreds(ctx, params.Name, creds)
}
// getEditTierCredentialsResponse returns the result of editing credentials for a tier
func getEditTierCredentialsResponse(session *models.Principal, params tieringApi.EditTierCredentialsParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
// serialize output
err = editTierCredentials(ctx, adminClient, &params)
if err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}

View File

@@ -1,230 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"errors"
"fmt"
"testing"
tieringApi "github.com/minio/console/api/operations/tiering"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
)
func TestGetTiers(t *testing.T) {
assert := assert.New(t)
// mock minIO client
adminClient := AdminClientMock{}
function := "getTiers()"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Test-1 : getBucketLifecycle() get list of tiers
// mock lifecycle response from MinIO
returnListMock := []*madmin.TierConfig{
{
Version: "V1",
Type: madmin.TierType(0),
Name: "S3 Tier",
S3: &madmin.TierS3{
Endpoint: "https://s3tier.test.com/",
AccessKey: "Access Key",
SecretKey: "Secret Key",
Bucket: "buckets3",
Prefix: "pref1",
Region: "us-west-1",
StorageClass: "TT1",
},
},
}
returnStatsMock := []madmin.TierInfo{
{
Name: "STANDARD",
Type: "internal",
Stats: madmin.TierStats{NumObjects: 2, NumVersions: 2, TotalSize: 228915},
},
{
Name: "S3 Tier",
Type: "s3",
Stats: madmin.TierStats{NumObjects: 0, NumVersions: 0, TotalSize: 0},
},
}
expectedOutput := &models.TierListResponse{
Items: []*models.Tier{
{
Type: "S3",
S3: &models.TierS3{
Accesskey: "Access Key",
Secretkey: "Secret Key",
Bucket: "buckets3",
Endpoint: "https://s3tier.test.com/",
Name: "S3 Tier",
Prefix: "pref1",
Region: "us-west-1",
Storageclass: "TT1",
Usage: "0 B",
Objects: "0",
Versions: "0",
},
},
},
}
minioListTiersMock = func(_ context.Context) ([]*madmin.TierConfig, error) {
return returnListMock, nil
}
minioTierStatsMock = func(_ context.Context) ([]madmin.TierInfo, error) {
return returnStatsMock, nil
}
tiersList, err := getTiers(ctx, adminClient)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
// verify length of tiers list is correct
assert.Equal(len(tiersList.Items), len(returnListMock), fmt.Sprintf("Failed on %s: length of lists is not the same", function))
for i, conf := range returnListMock {
switch conf.Type {
case madmin.TierType(0):
// S3
assert.Equal(expectedOutput.Items[i].S3.Name, conf.Name)
assert.Equal(expectedOutput.Items[i].S3.Bucket, conf.S3.Bucket)
assert.Equal(expectedOutput.Items[i].S3.Prefix, conf.S3.Prefix)
assert.Equal(expectedOutput.Items[i].S3.Accesskey, conf.S3.AccessKey)
assert.Equal(expectedOutput.Items[i].S3.Secretkey, conf.S3.SecretKey)
assert.Equal(expectedOutput.Items[i].S3.Endpoint, conf.S3.Endpoint)
assert.Equal(expectedOutput.Items[i].S3.Region, conf.S3.Region)
assert.Equal(expectedOutput.Items[i].S3.Storageclass, conf.S3.StorageClass)
case madmin.TierType(1):
// Azure
assert.Equal(expectedOutput.Items[i].Azure.Name, conf.Name)
assert.Equal(expectedOutput.Items[i].Azure.Bucket, conf.Azure.Bucket)
assert.Equal(expectedOutput.Items[i].Azure.Prefix, conf.Azure.Prefix)
assert.Equal(expectedOutput.Items[i].Azure.Accountkey, conf.Azure.AccountKey)
assert.Equal(expectedOutput.Items[i].Azure.Accountname, conf.Azure.AccountName)
assert.Equal(expectedOutput.Items[i].Azure.Endpoint, conf.Azure.Endpoint)
assert.Equal(expectedOutput.Items[i].Azure.Region, conf.Azure.Region)
case madmin.TierType(2):
// GCS
assert.Equal(expectedOutput.Items[i].Gcs.Name, conf.Name)
assert.Equal(expectedOutput.Items[i].Gcs.Bucket, conf.GCS.Bucket)
assert.Equal(expectedOutput.Items[i].Gcs.Prefix, conf.GCS.Prefix)
assert.Equal(expectedOutput.Items[i].Gcs.Creds, conf.GCS.Creds)
assert.Equal(expectedOutput.Items[i].Gcs.Endpoint, conf.GCS.Endpoint)
assert.Equal(expectedOutput.Items[i].Gcs.Region, conf.GCS.Region)
}
}
// Test-2 : getBucketLifecycle() list is empty
returnListMockT2 := []*madmin.TierConfig{}
minioListTiersMock = func(_ context.Context) ([]*madmin.TierConfig, error) {
return returnListMockT2, nil
}
tiersListT2, err := getTiers(ctx, adminClient)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
if len(tiersListT2.Items) != 0 {
t.Errorf("Failed on %s:, returned list was not empty", function)
}
}
func TestAddTier(t *testing.T) {
assert := assert.New(t)
// mock minIO client
adminClient := AdminClientMock{}
function := "addTier()"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Test-1: addTier() add new Tier
minioAddTiersMock = func(_ context.Context, _ *madmin.TierConfig) error {
return nil
}
paramsToAdd := tieringApi.AddTierParams{
Body: &models.Tier{
Type: "S3",
S3: &models.TierS3{
Accesskey: "TestAK",
Bucket: "bucket1",
Endpoint: "https://test.com/",
Name: "TIERS3",
Prefix: "Pr1",
Region: "us-west-1",
Secretkey: "SecretK",
Storageclass: "STCLASS",
},
},
}
err := addTier(ctx, adminClient, &paramsToAdd)
assert.Equal(nil, err, fmt.Sprintf("Failed on %s: Error returned", function))
// Test-2: addTier() error adding Tier
minioAddTiersMock = func(_ context.Context, _ *madmin.TierConfig) error {
return errors.New("error setting new tier")
}
err2 := addTier(ctx, adminClient, &paramsToAdd)
assert.Equal(errors.New("error setting new tier"), err2, fmt.Sprintf("Failed on %s: Error returned", function))
}
func TestUpdateTierCreds(t *testing.T) {
assert := assert.New(t)
// mock minIO client
adminClient := AdminClientMock{}
function := "editTierCredentials()"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Test-1: editTierCredentials() update Tier configuration
minioEditTiersMock = func(_ context.Context, _ string, _ madmin.TierCreds) error {
return nil
}
params := &tieringApi.EditTierCredentialsParams{
Name: "TESTTIER",
Body: &models.TierCredentialsRequest{
AccessKey: "New Key",
SecretKey: "Secret Key",
},
}
err := editTierCredentials(ctx, adminClient, params)
assert.Equal(nil, err, fmt.Sprintf("Failed on %s: Error returned", function))
// Test-2: editTierCredentials() update Tier configuration failure
minioEditTiersMock = func(_ context.Context, _ string, _ madmin.TierCreds) error {
return errors.New("error message")
}
errT2 := editTierCredentials(ctx, adminClient, params)
assert.Equal(errors.New("error message"), errT2, fmt.Sprintf("Failed on %s: Error returned", function))
}

View File

@@ -1,703 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"bytes"
"context"
"encoding/json"
"io"
"net"
"net/http"
"net/url"
"strings"
"time"
"github.com/minio/console/pkg/utils"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
"github.com/minio/minio-go/v7/pkg/credentials"
iampolicy "github.com/minio/pkg/v2/policy"
)
const globalAppName = "MinIO Console"
// MinioAdmin interface with all functions to be implemented
// by mock when testing, it should include all MinioAdmin respective api calls
// that are used within this project.
type MinioAdmin interface {
listUsers(ctx context.Context) (map[string]madmin.UserInfo, error)
addUser(ctx context.Context, acessKey, SecretKey string) error
removeUser(ctx context.Context, accessKey string) error
getUserInfo(ctx context.Context, accessKey string) (madmin.UserInfo, error)
setUserStatus(ctx context.Context, accessKey string, status madmin.AccountStatus) error
listGroups(ctx context.Context) ([]string, error)
updateGroupMembers(ctx context.Context, greq madmin.GroupAddRemove) error
getGroupDescription(ctx context.Context, group string) (*madmin.GroupDesc, error)
setGroupStatus(ctx context.Context, group string, status madmin.GroupStatus) error
listPolicies(ctx context.Context) (map[string]*iampolicy.Policy, error)
getPolicy(ctx context.Context, name string) (*iampolicy.Policy, error)
removePolicy(ctx context.Context, name string) error
addPolicy(ctx context.Context, name string, policy *iampolicy.Policy) error
setPolicy(ctx context.Context, policyName, entityName string, isGroup bool) error
getConfigKV(ctx context.Context, key string) ([]byte, error)
helpConfigKV(ctx context.Context, subSys, key string, envOnly bool) (madmin.Help, error)
helpConfigKVGlobal(ctx context.Context, envOnly bool) (madmin.Help, error)
setConfigKV(ctx context.Context, kv string) (restart bool, err error)
delConfigKV(ctx context.Context, kv string) (err error)
serviceRestart(ctx context.Context) error
serverInfo(ctx context.Context) (madmin.InfoMessage, error)
startProfiling(ctx context.Context, profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error)
stopProfiling(ctx context.Context) (io.ReadCloser, error)
serviceTrace(ctx context.Context, threshold int64, s3, internal, storage, os, errTrace bool) <-chan madmin.ServiceTraceInfo
getLogs(ctx context.Context, node string, lineCnt int, logKind string) <-chan madmin.LogInfo
AccountInfo(ctx context.Context) (madmin.AccountInfo, error)
heal(ctx context.Context, bucket, prefix string, healOpts madmin.HealOpts, clientToken string,
forceStart, forceStop bool) (healStart madmin.HealStartSuccess, healTaskStatus madmin.HealTaskStatus, err error)
// Service Accounts
addServiceAccount(ctx context.Context, policy string, user string, accessKey string, secretKey string, name string, description string, expiry *time.Time, comment string) (madmin.Credentials, error)
listServiceAccounts(ctx context.Context, user string) (madmin.ListServiceAccountsResp, error)
deleteServiceAccount(ctx context.Context, serviceAccount string) error
infoServiceAccount(ctx context.Context, serviceAccount string) (madmin.InfoServiceAccountResp, error)
updateServiceAccount(ctx context.Context, serviceAccount string, opts madmin.UpdateServiceAccountReq) error
// Remote Buckets
listRemoteBuckets(ctx context.Context, bucket, arnType string) (targets []madmin.BucketTarget, err error)
getRemoteBucket(ctx context.Context, bucket, arnType string) (targets *madmin.BucketTarget, err error)
removeRemoteBucket(ctx context.Context, bucket, arn string) error
addRemoteBucket(ctx context.Context, bucket string, target *madmin.BucketTarget) (string, error)
// Account password management
changePassword(ctx context.Context, accessKey, secretKey string) error
serverHealthInfo(ctx context.Context, healthDataTypes []madmin.HealthDataType, deadline time.Duration) (interface{}, string, error)
// List Tiers
listTiers(ctx context.Context) ([]*madmin.TierConfig, error)
// Tier Info
tierStats(ctx context.Context) ([]madmin.TierInfo, error)
// Add Tier
addTier(ctx context.Context, tier *madmin.TierConfig) error
// Edit Tier Credentials
editTierCreds(ctx context.Context, tierName string, creds madmin.TierCreds) error
// verify Tier status
verifyTierStatus(ctx context.Context, tierName string) error
// Speedtest
speedtest(ctx context.Context, opts madmin.SpeedtestOpts) (chan madmin.SpeedTestResult, error)
// Site Relication
getSiteReplicationInfo(ctx context.Context) (*madmin.SiteReplicationInfo, error)
addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite, opts madmin.SRAddOptions) (*madmin.ReplicateAddStatus, error)
editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo, opts madmin.SREditOptions) (*madmin.ReplicateEditStatus, error)
deleteSiteReplicationInfo(ctx context.Context, removeReq madmin.SRRemoveReq) (*madmin.ReplicateRemoveStatus, error)
// Replication status
getSiteReplicationStatus(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error)
// KMS
kmsStatus(ctx context.Context) (madmin.KMSStatus, error)
kmsMetrics(ctx context.Context) (*madmin.KMSMetrics, error)
kmsAPIs(ctx context.Context) ([]madmin.KMSAPI, error)
kmsVersion(ctx context.Context) (*madmin.KMSVersion, error)
createKey(ctx context.Context, key string) error
importKey(ctx context.Context, key string, content []byte) error
listKeys(ctx context.Context, pattern string) ([]madmin.KMSKeyInfo, error)
keyStatus(ctx context.Context, key string) (*madmin.KMSKeyStatus, error)
deleteKey(ctx context.Context, key string) error
setKMSPolicy(ctx context.Context, policy string, content []byte) error
assignPolicy(ctx context.Context, policy string, content []byte) error
describePolicy(ctx context.Context, policy string) (*madmin.KMSDescribePolicy, error)
getKMSPolicy(ctx context.Context, policy string) (*madmin.KMSPolicy, error)
listKMSPolicies(ctx context.Context, pattern string) ([]madmin.KMSPolicyInfo, error)
deletePolicy(ctx context.Context, policy string) error
describeIdentity(ctx context.Context, identity string) (*madmin.KMSDescribeIdentity, error)
describeSelfIdentity(ctx context.Context) (*madmin.KMSDescribeSelfIdentity, error)
deleteIdentity(ctx context.Context, identity string) error
listIdentities(ctx context.Context, pattern string) ([]madmin.KMSIdentityInfo, error)
// IDP
addOrUpdateIDPConfig(ctx context.Context, idpType, cfgName, cfgData string, update bool) (restart bool, err error)
listIDPConfig(ctx context.Context, idpType string) ([]madmin.IDPListItem, error)
deleteIDPConfig(ctx context.Context, idpType, cfgName string) (restart bool, err error)
getIDPConfig(ctx context.Context, cfgType, cfgName string) (c madmin.IDPConfig, err error)
// LDAP
getLDAPPolicyEntities(ctx context.Context, query madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error)
}
// Interface implementation
//
// Define the structure of a minIO Client and define the functions that are actually used
// from minIO api.
type AdminClient struct {
Client *madmin.AdminClient
}
func (ac AdminClient) changePassword(ctx context.Context, accessKey, secretKey string) error {
return ac.Client.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled)
}
// implements madmin.ListUsers()
func (ac AdminClient) listUsers(ctx context.Context) (map[string]madmin.UserInfo, error) {
return ac.Client.ListUsers(ctx)
}
// implements madmin.AddUser()
func (ac AdminClient) addUser(ctx context.Context, accessKey, secretKey string) error {
return ac.Client.AddUser(ctx, accessKey, secretKey)
}
// implements madmin.RemoveUser()
func (ac AdminClient) removeUser(ctx context.Context, accessKey string) error {
return ac.Client.RemoveUser(ctx, accessKey)
}
// implements madmin.GetUserInfo()
func (ac AdminClient) getUserInfo(ctx context.Context, accessKey string) (madmin.UserInfo, error) {
return ac.Client.GetUserInfo(ctx, accessKey)
}
// implements madmin.SetUserStatus()
func (ac AdminClient) setUserStatus(ctx context.Context, accessKey string, status madmin.AccountStatus) error {
return ac.Client.SetUserStatus(ctx, accessKey, status)
}
// implements madmin.ListGroups()
func (ac AdminClient) listGroups(ctx context.Context) ([]string, error) {
return ac.Client.ListGroups(ctx)
}
// implements madmin.UpdateGroupMembers()
func (ac AdminClient) updateGroupMembers(ctx context.Context, greq madmin.GroupAddRemove) error {
return ac.Client.UpdateGroupMembers(ctx, greq)
}
// implements madmin.GetGroupDescription(group)
func (ac AdminClient) getGroupDescription(ctx context.Context, group string) (*madmin.GroupDesc, error) {
return ac.Client.GetGroupDescription(ctx, group)
}
// implements madmin.SetGroupStatus(group, status)
func (ac AdminClient) setGroupStatus(ctx context.Context, group string, status madmin.GroupStatus) error {
return ac.Client.SetGroupStatus(ctx, group, status)
}
// implements madmin.ListCannedPolicies()
func (ac AdminClient) listPolicies(ctx context.Context) (map[string]*iampolicy.Policy, error) {
policyMap, err := ac.Client.ListCannedPolicies(ctx)
if err != nil {
return nil, err
}
policies := make(map[string]*iampolicy.Policy, len(policyMap))
for k, v := range policyMap {
p, err := iampolicy.ParseConfig(bytes.NewReader(v))
if err != nil {
return nil, err
}
policies[k] = p
}
return policies, nil
}
// implements madmin.ListCannedPolicies()
func (ac AdminClient) getPolicy(ctx context.Context, name string) (*iampolicy.Policy, error) {
praw, err := ac.Client.InfoCannedPolicy(ctx, name)
if err != nil {
return nil, err
}
return iampolicy.ParseConfig(bytes.NewReader(praw))
}
// implements madmin.RemoveCannedPolicy()
func (ac AdminClient) removePolicy(ctx context.Context, name string) error {
return ac.Client.RemoveCannedPolicy(ctx, name)
}
// implements madmin.AddCannedPolicy()
func (ac AdminClient) addPolicy(ctx context.Context, name string, policy *iampolicy.Policy) error {
buf, err := json.Marshal(policy)
if err != nil {
return err
}
return ac.Client.AddCannedPolicy(ctx, name, buf)
}
// implements madmin.SetPolicy()
func (ac AdminClient) setPolicy(ctx context.Context, policyName, entityName string, isGroup bool) error {
return ac.Client.SetPolicy(ctx, policyName, entityName, isGroup)
}
// implements madmin.GetConfigKV()
func (ac AdminClient) getConfigKV(ctx context.Context, key string) ([]byte, error) {
return ac.Client.GetConfigKV(ctx, key)
}
// implements madmin.HelpConfigKV()
func (ac AdminClient) helpConfigKV(ctx context.Context, subSys, key string, envOnly bool) (madmin.Help, error) {
return ac.Client.HelpConfigKV(ctx, subSys, key, envOnly)
}
// implements madmin.helpConfigKVGlobal()
func (ac AdminClient) helpConfigKVGlobal(ctx context.Context, envOnly bool) (madmin.Help, error) {
return ac.Client.HelpConfigKV(ctx, "", "", envOnly)
}
// implements madmin.SetConfigKV()
func (ac AdminClient) setConfigKV(ctx context.Context, kv string) (restart bool, err error) {
return ac.Client.SetConfigKV(ctx, kv)
}
// implements madmin.DelConfigKV()
func (ac AdminClient) delConfigKV(ctx context.Context, kv string) (err error) {
_, err = ac.Client.DelConfigKV(ctx, kv)
return err
}
// implements madmin.ServiceRestart()
func (ac AdminClient) serviceRestart(ctx context.Context) (err error) {
return ac.Client.ServiceRestart(ctx)
}
// implements madmin.ServerInfo()
func (ac AdminClient) serverInfo(ctx context.Context) (madmin.InfoMessage, error) {
return ac.Client.ServerInfo(ctx)
}
// implements madmin.StartProfiling()
func (ac AdminClient) startProfiling(ctx context.Context, profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
return ac.Client.StartProfiling(ctx, profiler)
}
// implements madmin.DownloadProfilingData()
func (ac AdminClient) stopProfiling(ctx context.Context) (io.ReadCloser, error) {
return ac.Client.DownloadProfilingData(ctx)
}
// implements madmin.ServiceTrace()
func (ac AdminClient) serviceTrace(ctx context.Context, threshold int64, _, internal, storage, os, errTrace bool) <-chan madmin.ServiceTraceInfo {
thresholdT := time.Duration(threshold)
tracingOptions := madmin.ServiceTraceOpts{
S3: true,
OnlyErrors: errTrace,
Internal: internal,
Storage: storage,
OS: os,
Threshold: thresholdT,
}
return ac.Client.ServiceTrace(ctx, tracingOptions)
}
// implements madmin.GetLogs()
func (ac AdminClient) getLogs(ctx context.Context, node string, lineCnt int, logKind string) <-chan madmin.LogInfo {
return ac.Client.GetLogs(ctx, node, lineCnt, logKind)
}
// implements madmin.AddServiceAccount()
func (ac AdminClient) addServiceAccount(ctx context.Context, policy string, user string, accessKey string, secretKey string, name string, description string, expiry *time.Time, comment string) (madmin.Credentials, error) {
return ac.Client.AddServiceAccount(ctx, madmin.AddServiceAccountReq{
Policy: []byte(policy),
TargetUser: user,
AccessKey: accessKey,
SecretKey: secretKey,
Name: name,
Description: description,
Expiration: expiry,
Comment: comment,
})
}
// implements madmin.ListServiceAccounts()
func (ac AdminClient) listServiceAccounts(ctx context.Context, user string) (madmin.ListServiceAccountsResp, error) {
return ac.Client.ListServiceAccounts(ctx, user)
}
// implements madmin.DeleteServiceAccount()
func (ac AdminClient) deleteServiceAccount(ctx context.Context, serviceAccount string) error {
return ac.Client.DeleteServiceAccount(ctx, serviceAccount)
}
// implements madmin.InfoServiceAccount()
func (ac AdminClient) infoServiceAccount(ctx context.Context, serviceAccount string) (madmin.InfoServiceAccountResp, error) {
return ac.Client.InfoServiceAccount(ctx, serviceAccount)
}
// implements madmin.UpdateServiceAccount()
func (ac AdminClient) updateServiceAccount(ctx context.Context, serviceAccount string, opts madmin.UpdateServiceAccountReq) error {
return ac.Client.UpdateServiceAccount(ctx, serviceAccount, opts)
}
// AccountInfo implements madmin.AccountInfo()
func (ac AdminClient) AccountInfo(ctx context.Context) (madmin.AccountInfo, error) {
return ac.Client.AccountInfo(ctx, madmin.AccountOpts{})
}
func (ac AdminClient) heal(ctx context.Context, bucket, prefix string, healOpts madmin.HealOpts, clientToken string,
forceStart, forceStop bool,
) (healStart madmin.HealStartSuccess, healTaskStatus madmin.HealTaskStatus, err error) {
return ac.Client.Heal(ctx, bucket, prefix, healOpts, clientToken, forceStart, forceStop)
}
// listRemoteBuckets - return a list of remote buckets
func (ac AdminClient) listRemoteBuckets(ctx context.Context, bucket, arnType string) (targets []madmin.BucketTarget, err error) {
return ac.Client.ListRemoteTargets(ctx, bucket, arnType)
}
// getRemoteBucket - gets remote bucked based on a given bucket name
func (ac AdminClient) getRemoteBucket(ctx context.Context, bucket, arnType string) (*madmin.BucketTarget, error) {
targets, err := ac.Client.ListRemoteTargets(ctx, bucket, arnType)
if err != nil {
return nil, err
}
if len(targets) > 0 {
return &targets[0], nil
}
return nil, err
}
// removeRemoteBucket removes a remote target associated with particular ARN for this bucket
func (ac AdminClient) removeRemoteBucket(ctx context.Context, bucket, arn string) error {
return ac.Client.RemoveRemoteTarget(ctx, bucket, arn)
}
// addRemoteBucket sets up a remote target for this bucket
func (ac AdminClient) addRemoteBucket(ctx context.Context, bucket string, target *madmin.BucketTarget) (string, error) {
return ac.Client.SetRemoteTarget(ctx, bucket, target)
}
func (ac AdminClient) setBucketQuota(ctx context.Context, bucket string, quota *madmin.BucketQuota) error {
return ac.Client.SetBucketQuota(ctx, bucket, quota)
}
func (ac AdminClient) getBucketQuota(ctx context.Context, bucket string) (madmin.BucketQuota, error) {
return ac.Client.GetBucketQuota(ctx, bucket)
}
// serverHealthInfo implements mc.ServerHealthInfo - Connect to a minio server and call Health Info Management API
func (ac AdminClient) serverHealthInfo(ctx context.Context, healthDataTypes []madmin.HealthDataType, deadline time.Duration) (interface{}, string, error) {
info := madmin.HealthInfo{}
var healthInfo interface{}
var version string
var tryCount int
for info.Version == "" && tryCount < 10 {
resp, version, err := ac.Client.ServerHealthInfo(ctx, healthDataTypes, deadline, "")
if err != nil {
return nil, version, err
}
decoder := json.NewDecoder(resp.Body)
for {
if err = decoder.Decode(&info); err != nil {
break
}
}
tryCount++
time.Sleep(2 * time.Second)
}
if info.Version == "" {
return nil, "", ErrHealthReportFail
}
healthInfo = info
return healthInfo, version, nil
}
// implements madmin.listTiers()
func (ac AdminClient) listTiers(ctx context.Context) ([]*madmin.TierConfig, error) {
return ac.Client.ListTiers(ctx)
}
// implements madmin.tierStats()
func (ac AdminClient) tierStats(ctx context.Context) ([]madmin.TierInfo, error) {
return ac.Client.TierStats(ctx)
}
// implements madmin.AddTier()
func (ac AdminClient) addTier(ctx context.Context, cfg *madmin.TierConfig) error {
return ac.Client.AddTier(ctx, cfg)
}
// implements madmin.Inspect()
func (ac AdminClient) inspect(ctx context.Context, insOpts madmin.InspectOptions) ([]byte, io.ReadCloser, error) {
return ac.Client.Inspect(ctx, insOpts)
}
// implements madmin.EditTier()
func (ac AdminClient) editTierCreds(ctx context.Context, tierName string, creds madmin.TierCreds) error {
return ac.Client.EditTier(ctx, tierName, creds)
}
// implements madmin.VerifyTier()
func (ac AdminClient) verifyTierStatus(ctx context.Context, tierName string) error {
return ac.Client.VerifyTier(ctx, tierName)
}
func NewMinioAdminClient(ctx context.Context, sessionClaims *models.Principal) (*madmin.AdminClient, error) {
clientIP := utils.ClientIPFromContext(ctx)
adminClient, err := newAdminFromClaims(sessionClaims, clientIP)
if err != nil {
return nil, err
}
return adminClient, nil
}
// newAdminFromClaims creates a minio admin from Decrypted claims using Assume role credentials
func newAdminFromClaims(claims *models.Principal, clientIP string) (*madmin.AdminClient, error) {
tlsEnabled := getMinIOEndpointIsSecure()
endpoint := getMinIOEndpoint()
adminClient, err := madmin.NewWithOptions(endpoint, &madmin.Options{
Creds: credentials.NewStaticV4(claims.STSAccessKeyID, claims.STSSecretAccessKey, claims.STSSessionToken),
Secure: tlsEnabled,
})
if err != nil {
return nil, err
}
adminClient.SetCustomTransport(GetConsoleHTTPClient(getMinIOServer(), clientIP).Transport)
return adminClient, nil
}
// newAdminFromCreds Creates a minio client using custom credentials for connecting to a remote host
func newAdminFromCreds(accessKey, secretKey, endpoint string, tlsEnabled bool) (*madmin.AdminClient, error) {
minioClient, err := madmin.NewWithOptions(endpoint, &madmin.Options{
Creds: credentials.NewStaticV4(accessKey, secretKey, ""),
Secure: tlsEnabled,
})
if err != nil {
return nil, err
}
return minioClient, nil
}
// isLocalAddress returns true if the url contains an IPv4/IPv6 hostname
// that points to the local machine - FQDN are not supported
func isLocalIPEndpoint(addr string) bool {
u, err := url.Parse(addr)
if err != nil {
return false
}
return isLocalIPAddress(u.Hostname())
}
// isLocalAddress returns true if the url contains an IPv4/IPv6 hostname
// that points to the local machine - FQDN are not supported
func isLocalIPAddress(ipAddr string) bool {
if ipAddr == "" {
return false
}
ip := net.ParseIP(ipAddr)
return ip != nil && ip.IsLoopback()
}
// GetConsoleHTTPClient caches different http clients depending on the target endpoint while taking
// in consideration CA certs stored in ${HOME}/.console/certs/CAs and ${HOME}/.minio/certs/CAs
// If the target endpoint points to a loopback device, skip the TLS verification.
func GetConsoleHTTPClient(address string, clientIP string) *http.Client {
u, err := url.Parse(address)
if err == nil {
address = u.Hostname()
}
client := PrepareConsoleHTTPClient(isLocalIPAddress(address), clientIP)
return client
}
func getClientIP(r *http.Request) string {
// Try to get the IP address from the X-Real-IP header
// If the X-Real-IP header is not present, then it will return an empty string
xRealIP := r.Header.Get("X-Real-IP")
if xRealIP != "" {
return xRealIP
}
// Try to get the IP address from the X-Forwarded-For header
// If the X-Forwarded-For header is not present, then it will return an empty string
xForwardedFor := r.Header.Get("X-Forwarded-For")
if xForwardedFor != "" {
// X-Forwarded-For can contain multiple addresses, we return the first one
split := strings.Split(xForwardedFor, ",")
if len(split) > 0 {
return strings.TrimSpace(split[0])
}
}
// If neither header is present (or they were empty), then fall back to the connection's remote address
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
// In case there's an error, return an empty string
return ""
}
return ip
}
func (ac AdminClient) speedtest(ctx context.Context, opts madmin.SpeedtestOpts) (chan madmin.SpeedTestResult, error) {
return ac.Client.Speedtest(ctx, opts)
}
// Site Replication
func (ac AdminClient) getSiteReplicationInfo(ctx context.Context) (*madmin.SiteReplicationInfo, error) {
res, err := ac.Client.SiteReplicationInfo(ctx)
if err != nil {
return nil, err
}
return &madmin.SiteReplicationInfo{
Enabled: res.Enabled,
Name: res.Name,
Sites: res.Sites,
ServiceAccountAccessKey: res.ServiceAccountAccessKey,
}, nil
}
func (ac AdminClient) addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite, opts madmin.SRAddOptions) (*madmin.ReplicateAddStatus, error) {
res, err := ac.Client.SiteReplicationAdd(ctx, sites, opts)
if err != nil {
return nil, err
}
return &madmin.ReplicateAddStatus{
Success: res.Success,
Status: res.Status,
ErrDetail: res.ErrDetail,
InitialSyncErrorMessage: res.InitialSyncErrorMessage,
}, nil
}
func (ac AdminClient) editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo, opts madmin.SREditOptions) (*madmin.ReplicateEditStatus, error) {
res, err := ac.Client.SiteReplicationEdit(ctx, site, opts)
if err != nil {
return nil, err
}
return &madmin.ReplicateEditStatus{
Success: res.Success,
Status: res.Status,
ErrDetail: res.ErrDetail,
}, nil
}
func (ac AdminClient) deleteSiteReplicationInfo(ctx context.Context, removeReq madmin.SRRemoveReq) (*madmin.ReplicateRemoveStatus, error) {
res, err := ac.Client.SiteReplicationRemove(ctx, removeReq)
if err != nil {
return nil, err
}
return &madmin.ReplicateRemoveStatus{
Status: res.Status,
ErrDetail: res.ErrDetail,
}, nil
}
func (ac AdminClient) getSiteReplicationStatus(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error) {
res, err := ac.Client.SRStatusInfo(ctx, params)
if err != nil {
return nil, err
}
return &res, nil
}
func (ac AdminClient) kmsStatus(ctx context.Context) (madmin.KMSStatus, error) {
return ac.Client.KMSStatus(ctx)
}
func (ac AdminClient) kmsMetrics(ctx context.Context) (*madmin.KMSMetrics, error) {
return ac.Client.KMSMetrics(ctx)
}
func (ac AdminClient) kmsAPIs(ctx context.Context) ([]madmin.KMSAPI, error) {
return ac.Client.KMSAPIs(ctx)
}
func (ac AdminClient) kmsVersion(ctx context.Context) (*madmin.KMSVersion, error) {
return ac.Client.KMSVersion(ctx)
}
func (ac AdminClient) createKey(ctx context.Context, key string) error {
return ac.Client.CreateKey(ctx, key)
}
func (ac AdminClient) importKey(ctx context.Context, key string, content []byte) error {
return ac.Client.ImportKey(ctx, key, content)
}
func (ac AdminClient) listKeys(ctx context.Context, pattern string) ([]madmin.KMSKeyInfo, error) {
return ac.Client.ListKeys(ctx, pattern)
}
func (ac AdminClient) keyStatus(ctx context.Context, key string) (*madmin.KMSKeyStatus, error) {
return ac.Client.GetKeyStatus(ctx, key)
}
func (ac AdminClient) deleteKey(ctx context.Context, key string) error {
return ac.Client.DeleteKey(ctx, key)
}
func (ac AdminClient) setKMSPolicy(ctx context.Context, policy string, content []byte) error {
return ac.Client.SetKMSPolicy(ctx, policy, content)
}
func (ac AdminClient) assignPolicy(ctx context.Context, policy string, content []byte) error {
return ac.Client.AssignPolicy(ctx, policy, content)
}
func (ac AdminClient) describePolicy(ctx context.Context, policy string) (*madmin.KMSDescribePolicy, error) {
return ac.Client.DescribePolicy(ctx, policy)
}
func (ac AdminClient) getKMSPolicy(ctx context.Context, policy string) (*madmin.KMSPolicy, error) {
return ac.Client.GetPolicy(ctx, policy)
}
func (ac AdminClient) listKMSPolicies(ctx context.Context, pattern string) ([]madmin.KMSPolicyInfo, error) {
return ac.Client.ListPolicies(ctx, pattern)
}
func (ac AdminClient) deletePolicy(ctx context.Context, policy string) error {
return ac.Client.DeletePolicy(ctx, policy)
}
func (ac AdminClient) describeIdentity(ctx context.Context, identity string) (*madmin.KMSDescribeIdentity, error) {
return ac.Client.DescribeIdentity(ctx, identity)
}
func (ac AdminClient) describeSelfIdentity(ctx context.Context) (*madmin.KMSDescribeSelfIdentity, error) {
return ac.Client.DescribeSelfIdentity(ctx)
}
func (ac AdminClient) deleteIdentity(ctx context.Context, identity string) error {
return ac.Client.DeleteIdentity(ctx, identity)
}
func (ac AdminClient) listIdentities(ctx context.Context, pattern string) ([]madmin.KMSIdentityInfo, error) {
return ac.Client.ListIdentities(ctx, pattern)
}
func (ac AdminClient) addOrUpdateIDPConfig(ctx context.Context, idpType, cfgName, cfgData string, update bool) (restart bool, err error) {
return ac.Client.AddOrUpdateIDPConfig(ctx, idpType, cfgName, cfgData, update)
}
func (ac AdminClient) listIDPConfig(ctx context.Context, idpType string) ([]madmin.IDPListItem, error) {
return ac.Client.ListIDPConfig(ctx, idpType)
}
func (ac AdminClient) deleteIDPConfig(ctx context.Context, idpType, cfgName string) (restart bool, err error) {
return ac.Client.DeleteIDPConfig(ctx, idpType, cfgName)
}
func (ac AdminClient) getIDPConfig(ctx context.Context, idpType, cfgName string) (c madmin.IDPConfig, err error) {
return ac.Client.GetIDPConfig(ctx, idpType, cfgName)
}
func (ac AdminClient) getLDAPPolicyEntities(ctx context.Context, query madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error) {
return ac.Client.GetLDAPPolicyEntities(ctx, query)
}

View File

@@ -1,277 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"crypto/x509"
"net"
"strconv"
"strings"
"github.com/minio/console/pkg/auth/idp/oauth2"
xcerts "github.com/minio/pkg/v2/certs"
"github.com/minio/pkg/v2/env"
xnet "github.com/minio/pkg/v2/net"
)
var (
// Port console default port
Port = "9090"
// Hostname console hostname
// avoid listening on 0.0.0.0 by default
// instead listen on all IPv4 and IPv6
// - Hostname should be empty.
Hostname = ""
// TLSPort console tls port
TLSPort = "9443"
// TLSRedirect console tls redirect rule
TLSRedirect = "on"
ConsoleResourceName = "console-ui"
)
var (
// GlobalRootCAs is CA root certificates, a nil value means system certs pool will be used
GlobalRootCAs *x509.CertPool
// GlobalPublicCerts has certificates Console will use to serve clients
GlobalPublicCerts []*x509.Certificate
// GlobalTLSCertsManager custom TLS Manager for SNI support
GlobalTLSCertsManager *xcerts.Manager
)
// MinIOConfig represents application configuration passed in from the MinIO
// server to the console.
type MinIOConfig struct {
OpenIDProviders oauth2.OpenIDPCfg
}
// GlobalMinIOConfig is the global application configuration passed in from the
// MinIO server.
var GlobalMinIOConfig MinIOConfig
func getMinIOServer() string {
return strings.TrimSpace(env.Get(ConsoleMinIOServer, "http://localhost:9000"))
}
func getSubnetProxy() string {
return strings.TrimSpace(env.Get(ConsoleSubnetProxy, ""))
}
func GetMinIORegion() string {
return strings.TrimSpace(env.Get(ConsoleMinIORegion, ""))
}
func getMinIOEndpoint() string {
u, err := xnet.ParseHTTPURL(getMinIOServer())
if err != nil {
panic(err)
}
return u.Host
}
func getMinIOEndpointIsSecure() bool {
u, err := xnet.ParseHTTPURL(getMinIOServer())
if err != nil {
panic(err)
}
return u.Scheme == "https"
}
// GetHostname gets console hostname set on env variable,
// default one or defined on run command
func GetHostname() string {
return strings.ToLower(env.Get(ConsoleHostname, Hostname))
}
// GetPort gets console por set on env variable
// or default one
func GetPort() int {
port, err := strconv.Atoi(env.Get(ConsolePort, Port))
if err != nil {
port = 9090
}
return port
}
// GetTLSPort gets console tls port set on env variable
// or default one
func GetTLSPort() int {
port, err := strconv.Atoi(env.Get(ConsoleTLSPort, TLSPort))
if err != nil {
port = 9443
}
return port
}
// If GetTLSRedirect is set to true, then only allow HTTPS requests. Default is true.
func GetTLSRedirect() string {
return strings.ToLower(env.Get(ConsoleSecureTLSRedirect, TLSRedirect))
}
// Get secure middleware env variable configurations
func GetSecureAllowedHosts() []string {
allowedHosts := env.Get(ConsoleSecureAllowedHosts, "")
if allowedHosts != "" {
return strings.Split(allowedHosts, ",")
}
return []string{}
}
// AllowedHostsAreRegex determines, if the provided AllowedHosts slice contains valid regular expressions. Default is false.
func GetSecureAllowedHostsAreRegex() bool {
return strings.ToLower(env.Get(ConsoleSecureAllowedHostsAreRegex, "off")) == "on"
}
// If FrameDeny is set to true, adds the X-Frame-Options header with the value of `DENY`. Default is true.
func GetSecureFrameDeny() bool {
return strings.ToLower(env.Get(ConsoleSecureFrameDeny, "on")) == "on"
}
// If ContentTypeNosniff is true, adds the X-Content-Type-Options header with the value `nosniff`. Default is true.
func GetSecureContentTypeNonSniff() bool {
return strings.ToLower(env.Get(ConsoleSecureContentTypeNoSniff, "on")) == "on"
}
// If BrowserXssFilter is true, adds the X-XSS-Protection header with the value `1; mode=block`. Default is true.
func GetSecureBrowserXSSFilter() bool {
return strings.ToLower(env.Get(ConsoleSecureBrowserXSSFilter, "on")) == "on"
}
// ContentSecurityPolicy allows the Content-Security-Policy header value to be set with a custom value. Default is "".
// Passing a template string will replace `$NONCE` with a dynamic nonce value of 16 bytes for each request which can be
// later retrieved using the Nonce function.
func GetSecureContentSecurityPolicy() string {
return env.Get(ConsoleSecureContentSecurityPolicy, "")
}
// ContentSecurityPolicyReportOnly allows the Content-Security-Policy-Report-Only header value to be set with a custom value. Default is "".
func GetSecureContentSecurityPolicyReportOnly() string {
return env.Get(ConsoleSecureContentSecurityPolicyReportOnly, "")
}
// HostsProxyHeaders is a set of header keys that may hold a proxied hostname value for the request.
func GetSecureHostsProxyHeaders() []string {
allowedHosts := env.Get(ConsoleSecureHostsProxyHeaders, "")
if allowedHosts != "" {
return strings.Split(allowedHosts, ",")
}
return []string{}
}
// TLSHost is the host name that is used to redirect HTTP requests to HTTPS. Default is "", which indicates to use the same host.
func GetSecureTLSHost() string {
tlsHost := env.Get(ConsoleSecureTLSHost, "")
if tlsHost == "" && Hostname != "" {
return net.JoinHostPort(Hostname, TLSPort)
}
return ""
}
// STSSeconds is the max-age of the Strict-Transport-Security header. Default is 0, which would NOT include the header.
func GetSecureSTSSeconds() int64 {
seconds, err := strconv.Atoi(env.Get(ConsoleSecureSTSSeconds, "0"))
if err != nil {
seconds = 0
}
return int64(seconds)
}
// If STSIncludeSubdomains is set to true, the `includeSubdomains` will be appended to the Strict-Transport-Security header. Default is false.
func GetSecureSTSIncludeSubdomains() bool {
return strings.ToLower(env.Get(ConsoleSecureSTSIncludeSubdomains, "off")) == "on"
}
// If STSPreload is set to true, the `preload` flag will be appended to the Strict-Transport-Security header. Default is false.
func GetSecureSTSPreload() bool {
return strings.ToLower(env.Get(ConsoleSecureSTSPreload, "off")) == "on"
}
// If TLSTemporaryRedirect is true, the a 302 will be used while redirecting. Default is false (301).
func GetSecureTLSTemporaryRedirect() bool {
return strings.ToLower(env.Get(ConsoleSecureTLSTemporaryRedirect, "off")) == "on"
}
// STS header is only included when the connection is HTTPS.
func GetSecureForceSTSHeader() bool {
return strings.ToLower(env.Get(ConsoleSecureForceSTSHeader, "off")) == "on"
}
// ReferrerPolicy allows the Referrer-Policy header with the value to be set with a custom value. Default is "".
func GetSecureReferrerPolicy() string {
return env.Get(ConsoleSecureReferrerPolicy, "")
}
// FeaturePolicy allows the Feature-Policy header with the value to be set with a custom value. Default is "".
func GetSecureFeaturePolicy() string {
return env.Get(ConsoleSecureFeaturePolicy, "")
}
func getLogSearchAPIToken() string {
if v := env.Get(ConsoleLogQueryAuthToken, ""); v != "" {
return v
}
return env.Get(LogSearchQueryAuthToken, "")
}
func getLogSearchURL() string {
return env.Get(ConsoleLogQueryURL, "")
}
func getPrometheusURL() string {
return env.Get(PrometheusURL, "")
}
func getPrometheusAuthToken() string {
return env.Get(PrometheusAuthToken, "")
}
func getPrometheusJobID() string {
return env.Get(PrometheusJobID, "minio-job")
}
func getPrometheusExtraLabels() string {
return env.Get(PrometheusExtraLabels, "")
}
func getMaxConcurrentUploadsLimit() int64 {
cu, err := strconv.ParseInt(env.Get(ConsoleMaxConcurrentUploads, "10"), 10, 64)
if err != nil {
return 10
}
return cu
}
func getMaxConcurrentDownloadsLimit() int64 {
cu, err := strconv.ParseInt(env.Get(ConsoleMaxConcurrentDownloads, "20"), 10, 64)
if err != nil {
return 20
}
return cu
}
func getConsoleDevMode() bool {
return strings.ToLower(env.Get(ConsoleDevMode, "off")) == "on"
}
func getConsoleAnimatedLogin() bool {
return strings.ToLower(env.Get(ConsoleAnimatedLogin, "on")) == "on"
}

View File

@@ -1,393 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetHostname(t *testing.T) {
os.Setenv(ConsoleHostname, "x")
defer os.Unsetenv(ConsoleHostname)
assert.Equalf(t, "x", GetHostname(), "GetHostname()")
}
func TestGetPort(t *testing.T) {
type args struct {
env string
}
tests := []struct {
name string
args args
want int
}{
{
name: "valid port",
args: args{
env: "9091",
},
want: 9091,
},
{
name: "invalid port",
args: args{
env: "duck",
},
want: 9090,
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsolePort, tt.args.env)
assert.Equalf(t, tt.want, GetPort(), "GetPort()")
os.Unsetenv(ConsolePort)
})
}
}
func TestGetTLSPort(t *testing.T) {
type args struct {
env string
}
tests := []struct {
name string
args args
want int
}{
{
name: "valid port",
args: args{
env: "9444",
},
want: 9444,
},
{
name: "invalid port",
args: args{
env: "duck",
},
want: 9443,
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleTLSPort, tt.args.env)
assert.Equalf(t, tt.want, GetTLSPort(), "GetTLSPort()")
os.Unsetenv(ConsoleTLSPort)
})
}
}
func TestGetSecureAllowedHosts(t *testing.T) {
type args struct {
env string
}
tests := []struct {
name string
args args
want []string
}{
{
name: "valid hosts",
args: args{
env: "host1,host2",
},
want: []string{"host1", "host2"},
},
{
name: "empty hosts",
args: args{
env: "",
},
want: []string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleSecureAllowedHosts, tt.args.env)
assert.Equalf(t, tt.want, GetSecureAllowedHosts(), "GetSecureAllowedHosts()")
os.Unsetenv(ConsoleSecureAllowedHosts)
})
}
}
func TestGetSecureHostsProxyHeaders(t *testing.T) {
type args struct {
env string
}
tests := []struct {
name string
args args
want []string
}{
{
name: "valid headers",
args: args{
env: "header1,header2",
},
want: []string{"header1", "header2"},
},
{
name: "empty headers",
args: args{
env: "",
},
want: []string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleSecureHostsProxyHeaders, tt.args.env)
assert.Equalf(t, tt.want, GetSecureHostsProxyHeaders(), "GetSecureHostsProxyHeaders()")
os.Unsetenv(ConsoleSecureHostsProxyHeaders)
})
}
}
func TestGetSecureSTSSeconds(t *testing.T) {
type args struct {
env string
}
tests := []struct {
name string
args args
want int64
}{
{
name: "valid",
args: args{
env: "1",
},
want: 1,
},
{
name: "invalid",
args: args{
env: "duck",
},
want: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleSecureSTSSeconds, tt.args.env)
assert.Equalf(t, tt.want, GetSecureSTSSeconds(), "GetSecureSTSSeconds()")
os.Unsetenv(ConsoleSecureSTSSeconds)
})
}
}
func Test_getLogSearchAPIToken(t *testing.T) {
type args struct {
env string
}
tests := []struct {
name string
args args
want string
}{
{
name: "env set",
args: args{
env: "value",
},
want: "value",
},
{
name: "env not set",
args: args{
env: "",
},
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleLogQueryAuthToken, tt.args.env)
assert.Equalf(t, tt.want, getLogSearchAPIToken(), "getLogSearchAPIToken()")
os.Setenv(ConsoleLogQueryAuthToken, tt.args.env)
})
}
}
func Test_getPrometheusURL(t *testing.T) {
type args struct {
env string
}
tests := []struct {
name string
args args
want string
}{
{
name: "env set",
args: args{
env: "value",
},
want: "value",
},
{
name: "env not set",
args: args{
env: "",
},
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(PrometheusURL, tt.args.env)
assert.Equalf(t, tt.want, getPrometheusURL(), "getPrometheusURL()")
os.Setenv(PrometheusURL, tt.args.env)
})
}
}
func Test_getPrometheusJobID(t *testing.T) {
type args struct {
env string
}
tests := []struct {
name string
args args
want string
}{
{
name: "env set",
args: args{
env: "value",
},
want: "value",
},
{
name: "env not set",
args: args{
env: "",
},
want: "minio-job",
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(PrometheusJobID, tt.args.env)
assert.Equalf(t, tt.want, getPrometheusJobID(), "getPrometheusJobID()")
os.Setenv(PrometheusJobID, tt.args.env)
})
}
}
func Test_getMaxConcurrentUploadsLimit(t *testing.T) {
type args struct {
env string
}
tests := []struct {
name string
args args
want int64
}{
{
name: "valid",
args: args{
env: "1",
},
want: 1,
},
{
name: "invalid",
args: args{
env: "duck",
},
want: 10,
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleMaxConcurrentUploads, tt.args.env)
assert.Equalf(t, tt.want, getMaxConcurrentUploadsLimit(), "getMaxConcurrentUploadsLimit()")
os.Unsetenv(ConsoleMaxConcurrentUploads)
})
}
}
func Test_getMaxConcurrentDownloadsLimit(t *testing.T) {
type args struct {
env string
}
tests := []struct {
name string
args args
want int64
}{
{
name: "valid",
args: args{
env: "1",
},
want: 1,
},
{
name: "invalid",
args: args{
env: "duck",
},
want: 20,
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleMaxConcurrentDownloads, tt.args.env)
assert.Equalf(t, tt.want, getMaxConcurrentDownloadsLimit(), "getMaxConcurrentDownloadsLimit()")
os.Unsetenv(ConsoleMaxConcurrentDownloads)
})
}
}
func Test_getConsoleDevMode(t *testing.T) {
type args struct {
env string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "value set",
args: args{
env: "on",
},
want: true,
},
{
name: "value not set",
args: args{
env: "",
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleDevMode, tt.args.env)
assert.Equalf(t, tt.want, getConsoleDevMode(), "getConsoleDevMode()")
os.Unsetenv(ConsoleDevMode)
})
}
}

View File

@@ -1,62 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
// list of all console environment constants
const (
// Constants for common configuration
ConsoleMinIOServer = "CONSOLE_MINIO_SERVER"
ConsoleSubnetProxy = "CONSOLE_SUBNET_PROXY"
ConsoleMinIORegion = "CONSOLE_MINIO_REGION"
ConsoleHostname = "CONSOLE_HOSTNAME"
ConsolePort = "CONSOLE_PORT"
ConsoleTLSPort = "CONSOLE_TLS_PORT"
// Constants for Secure middleware
ConsoleSecureAllowedHosts = "CONSOLE_SECURE_ALLOWED_HOSTS"
ConsoleSecureAllowedHostsAreRegex = "CONSOLE_SECURE_ALLOWED_HOSTS_ARE_REGEX"
ConsoleSecureFrameDeny = "CONSOLE_SECURE_FRAME_DENY"
ConsoleSecureContentTypeNoSniff = "CONSOLE_SECURE_CONTENT_TYPE_NO_SNIFF"
ConsoleSecureBrowserXSSFilter = "CONSOLE_SECURE_BROWSER_XSS_FILTER"
ConsoleSecureContentSecurityPolicy = "CONSOLE_SECURE_CONTENT_SECURITY_POLICY"
ConsoleSecureContentSecurityPolicyReportOnly = "CONSOLE_SECURE_CONTENT_SECURITY_POLICY_REPORT_ONLY"
ConsoleSecureHostsProxyHeaders = "CONSOLE_SECURE_HOSTS_PROXY_HEADERS"
ConsoleSecureSTSSeconds = "CONSOLE_SECURE_STS_SECONDS"
ConsoleSecureSTSIncludeSubdomains = "CONSOLE_SECURE_STS_INCLUDE_SUB_DOMAINS"
ConsoleSecureSTSPreload = "CONSOLE_SECURE_STS_PRELOAD"
ConsoleSecureTLSRedirect = "CONSOLE_SECURE_TLS_REDIRECT"
ConsoleSecureTLSHost = "CONSOLE_SECURE_TLS_HOST"
ConsoleSecureTLSTemporaryRedirect = "CONSOLE_SECURE_TLS_TEMPORARY_REDIRECT"
ConsoleSecureForceSTSHeader = "CONSOLE_SECURE_FORCE_STS_HEADER"
ConsoleSecurePublicKey = "CONSOLE_SECURE_PUBLIC_KEY"
ConsoleSecureReferrerPolicy = "CONSOLE_SECURE_REFERRER_POLICY"
ConsoleSecureFeaturePolicy = "CONSOLE_SECURE_FEATURE_POLICY"
ConsoleSecureExpectCTHeader = "CONSOLE_SECURE_EXPECT_CT_HEADER"
PrometheusURL = "CONSOLE_PROMETHEUS_URL"
PrometheusAuthToken = "CONSOLE_PROMETHEUS_AUTH_TOKEN"
PrometheusJobID = "CONSOLE_PROMETHEUS_JOB_ID"
PrometheusExtraLabels = "CONSOLE_PROMETHEUS_EXTRA_LABELS"
ConsoleLogQueryURL = "CONSOLE_LOG_QUERY_URL"
ConsoleLogQueryAuthToken = "CONSOLE_LOG_QUERY_AUTH_TOKEN"
ConsoleMaxConcurrentUploads = "CONSOLE_MAX_CONCURRENT_UPLOADS"
ConsoleMaxConcurrentDownloads = "CONSOLE_MAX_CONCURRENT_DOWNLOADS"
ConsoleDevMode = "CONSOLE_DEV_MODE"
ConsoleAnimatedLogin = "CONSOLE_ANIMATED_LOGIN"
LogSearchQueryAuthToken = "LOGSEARCH_QUERY_AUTH_TOKEN"
SlashSeparator = "/"
LocalAddress = "127.0.0.1"
)

View File

@@ -1,556 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package api
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"log"
"net"
"net/http"
"os"
"os/signal"
"strconv"
"sync"
"sync/atomic"
"syscall"
"time"
"github.com/go-openapi/runtime/flagext"
"github.com/go-openapi/swag"
flags "github.com/jessevdk/go-flags"
"golang.org/x/net/netutil"
"github.com/minio/console/api/operations"
)
const (
schemeHTTP = "http"
schemeHTTPS = "https"
schemeUnix = "unix"
)
var defaultSchemes []string
func init() {
defaultSchemes = []string{
schemeHTTP,
}
}
// NewServer creates a new api console server but does not configure it
func NewServer(api *operations.ConsoleAPI) *Server {
s := new(Server)
s.shutdown = make(chan struct{})
s.api = api
s.interrupt = make(chan os.Signal, 1)
return s
}
// ConfigureAPI configures the API and handlers.
func (s *Server) ConfigureAPI() {
if s.api != nil {
s.handler = configureAPI(s.api)
}
}
// ConfigureFlags configures the additional flags defined by the handlers. Needs to be called before the parser.Parse
func (s *Server) ConfigureFlags() {
if s.api != nil {
configureFlags(s.api)
}
}
// Server for the console API
type Server struct {
EnabledListeners []string `long:"scheme" description:"the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec"`
CleanupTimeout time.Duration `long:"cleanup-timeout" description:"grace period for which to wait before killing idle connections" default:"10s"`
GracefulTimeout time.Duration `long:"graceful-timeout" description:"grace period for which to wait before shutting down the server" default:"15s"`
MaxHeaderSize flagext.ByteSize `long:"max-header-size" description:"controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line. It does not limit the size of the request body." default:"1MiB"`
SocketPath flags.Filename `long:"socket-path" description:"the unix socket to listen on" default:"/var/run/console.sock"`
domainSocketL net.Listener
Host string `long:"host" description:"the IP to listen on" default:"localhost" env:"HOST"`
Port int `long:"port" description:"the port to listen on for insecure connections, defaults to a random value" env:"PORT"`
ListenLimit int `long:"listen-limit" description:"limit the number of outstanding requests"`
KeepAlive time.Duration `long:"keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)" default:"3m"`
ReadTimeout time.Duration `long:"read-timeout" description:"maximum duration before timing out read of the request" default:"30s"`
WriteTimeout time.Duration `long:"write-timeout" description:"maximum duration before timing out write of the response" default:"60s"`
httpServerL []net.Listener
TLSHost string `long:"tls-host" description:"the IP to listen on for tls, when not specified it's the same as --host" env:"TLS_HOST"`
TLSPort int `long:"tls-port" description:"the port to listen on for secure connections, defaults to a random value" env:"TLS_PORT"`
TLSCertificate flags.Filename `long:"tls-certificate" description:"the certificate to use for secure connections" env:"TLS_CERTIFICATE"`
TLSCertificateKey flags.Filename `long:"tls-key" description:"the private key to use for secure connections" env:"TLS_PRIVATE_KEY"`
TLSCACertificate flags.Filename `long:"tls-ca" description:"the certificate authority file to be used with mutual tls auth" env:"TLS_CA_CERTIFICATE"`
TLSListenLimit int `long:"tls-listen-limit" description:"limit the number of outstanding requests"`
TLSKeepAlive time.Duration `long:"tls-keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)"`
TLSReadTimeout time.Duration `long:"tls-read-timeout" description:"maximum duration before timing out read of the request"`
TLSWriteTimeout time.Duration `long:"tls-write-timeout" description:"maximum duration before timing out write of the response"`
httpsServerL []net.Listener
api *operations.ConsoleAPI
handler http.Handler
hasListeners bool
shutdown chan struct{}
shuttingDown int32
interrupted bool
interrupt chan os.Signal
}
// Logf logs message either via defined user logger or via system one if no user logger is defined.
func (s *Server) Logf(f string, args ...interface{}) {
if s.api != nil && s.api.Logger != nil {
s.api.Logger(f, args...)
} else {
log.Printf(f, args...)
}
}
// Fatalf logs message either via defined user logger or via system one if no user logger is defined.
// Exits with non-zero status after printing
func (s *Server) Fatalf(f string, args ...interface{}) {
if s.api != nil && s.api.Logger != nil {
s.api.Logger(f, args...)
os.Exit(1)
}
log.Fatalf(f, args...)
}
// SetAPI configures the server with the specified API. Needs to be called before Serve
func (s *Server) SetAPI(api *operations.ConsoleAPI) {
if api == nil {
s.api = nil
s.handler = nil
return
}
s.api = api
s.handler = configureAPI(api)
}
func (s *Server) hasScheme(scheme string) bool {
schemes := s.EnabledListeners
if len(schemes) == 0 {
schemes = defaultSchemes
}
for _, v := range schemes {
if v == scheme {
return true
}
}
return false
}
// Serve the api
func (s *Server) Serve() (err error) {
if !s.hasListeners {
if err = s.Listen(); err != nil {
return err
}
}
// set default handler, if none is set
if s.handler == nil {
if s.api == nil {
return errors.New("can't create the default handler, as no api is set")
}
s.SetHandler(s.api.Serve(nil))
}
wg := new(sync.WaitGroup)
once := new(sync.Once)
signalNotify(s.interrupt)
go handleInterrupt(once, s)
servers := []*http.Server{}
if s.hasScheme(schemeUnix) {
domainSocket := new(http.Server)
domainSocket.MaxHeaderBytes = int(s.MaxHeaderSize)
domainSocket.Handler = s.handler
if int64(s.CleanupTimeout) > 0 {
domainSocket.IdleTimeout = s.CleanupTimeout
}
configureServer(domainSocket, "unix", string(s.SocketPath))
servers = append(servers, domainSocket)
wg.Add(1)
s.Logf("Serving console at unix://%s", s.SocketPath)
go func(l net.Listener) {
defer wg.Done()
if err := domainSocket.Serve(l); err != nil && err != http.ErrServerClosed {
s.Fatalf("%v", err)
}
s.Logf("Stopped serving console at unix://%s", s.SocketPath)
}(s.domainSocketL)
}
if s.hasScheme(schemeHTTP) {
httpServer := new(http.Server)
httpServer.MaxHeaderBytes = int(s.MaxHeaderSize)
httpServer.ReadTimeout = s.ReadTimeout
httpServer.WriteTimeout = s.WriteTimeout
httpServer.SetKeepAlivesEnabled(int64(s.KeepAlive) > 0)
if s.ListenLimit > 0 {
for i := range s.httpServerL {
s.httpServerL[i] = netutil.LimitListener(s.httpServerL[i], s.ListenLimit)
}
}
if int64(s.CleanupTimeout) > 0 {
httpServer.IdleTimeout = s.CleanupTimeout
}
httpServer.Handler = s.handler
configureServer(httpServer, "http", s.httpServerL[0].Addr().String())
servers = append(servers, httpServer)
s.Logf("Serving console at http://%s", s.httpServerL[0].Addr())
for i := range s.httpServerL {
wg.Add(1)
go func(l net.Listener) {
defer wg.Done()
if err := httpServer.Serve(l); err != nil && err != http.ErrServerClosed {
s.Fatalf("%v", err)
}
s.Logf("Stopped serving console at http://%s", l.Addr())
}(s.httpServerL[i])
}
}
if s.hasScheme(schemeHTTPS) {
httpsServer := new(http.Server)
httpsServer.MaxHeaderBytes = int(s.MaxHeaderSize)
httpsServer.ReadTimeout = s.TLSReadTimeout
httpsServer.WriteTimeout = s.TLSWriteTimeout
httpsServer.SetKeepAlivesEnabled(int64(s.TLSKeepAlive) > 0)
if s.TLSListenLimit > 0 {
for i := range s.httpsServerL {
s.httpsServerL[i] = netutil.LimitListener(s.httpsServerL[i], s.TLSListenLimit)
}
}
if int64(s.CleanupTimeout) > 0 {
httpsServer.IdleTimeout = s.CleanupTimeout
}
httpsServer.Handler = s.handler
// Inspired by https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go
httpsServer.TLSConfig = &tls.Config{
// Causes servers to use Go's default ciphersuite preferences,
// which are tuned to avoid attacks. Does nothing on clients.
PreferServerCipherSuites: true,
// Only use curves which have assembly implementations
// https://github.com/golang/go/tree/master/src/crypto/elliptic
CurvePreferences: []tls.CurveID{tls.CurveP256},
// Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
NextProtos: []string{"h2", "http/1.1"},
// https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols
MinVersion: tls.VersionTLS12,
// These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
},
}
// build standard config from server options
if s.TLSCertificate != "" && s.TLSCertificateKey != "" {
httpsServer.TLSConfig.Certificates = make([]tls.Certificate, 1)
httpsServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(string(s.TLSCertificate), string(s.TLSCertificateKey))
if err != nil {
return err
}
}
if s.TLSCACertificate != "" {
// include specified CA certificate
caCert, caCertErr := os.ReadFile(string(s.TLSCACertificate))
if caCertErr != nil {
return caCertErr
}
caCertPool := x509.NewCertPool()
ok := caCertPool.AppendCertsFromPEM(caCert)
if !ok {
return fmt.Errorf("cannot parse CA certificate")
}
httpsServer.TLSConfig.ClientCAs = caCertPool
httpsServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
}
// call custom TLS configurator
configureTLS(httpsServer.TLSConfig)
if len(httpsServer.TLSConfig.Certificates) == 0 && httpsServer.TLSConfig.GetCertificate == nil {
// after standard and custom config are passed, this ends up with no certificate
if s.TLSCertificate == "" {
if s.TLSCertificateKey == "" {
s.Fatalf("the required flags `--tls-certificate` and `--tls-key` were not specified")
}
s.Fatalf("the required flag `--tls-certificate` was not specified")
}
if s.TLSCertificateKey == "" {
s.Fatalf("the required flag `--tls-key` was not specified")
}
// this happens with a wrong custom TLS configurator
s.Fatalf("no certificate was configured for TLS")
}
configureServer(httpsServer, "https", s.httpsServerL[0].Addr().String())
servers = append(servers, httpsServer)
s.Logf("Serving console at https://%s", s.httpsServerL[0].Addr())
for i := range s.httpsServerL {
wg.Add(1)
go func(l net.Listener) {
defer wg.Done()
if err := httpsServer.Serve(l); err != nil && err != http.ErrServerClosed {
s.Fatalf("%v", err)
}
s.Logf("Stopped serving console at https://%s", l.Addr())
}(tls.NewListener(s.httpsServerL[i], httpsServer.TLSConfig))
}
}
wg.Add(1)
go s.handleShutdown(wg, &servers)
wg.Wait()
return nil
}
// Listen creates the listeners for the server
func (s *Server) Listen() error {
if s.hasListeners { // already done this
return nil
}
if s.hasScheme(schemeHTTPS) {
// Use http host if https host wasn't defined
if s.TLSHost == "" {
s.TLSHost = s.Host
}
// Use http listen limit if https listen limit wasn't defined
if s.TLSListenLimit == 0 {
s.TLSListenLimit = s.ListenLimit
}
// Use http tcp keep alive if https tcp keep alive wasn't defined
if int64(s.TLSKeepAlive) == 0 {
s.TLSKeepAlive = s.KeepAlive
}
// Use http read timeout if https read timeout wasn't defined
if int64(s.TLSReadTimeout) == 0 {
s.TLSReadTimeout = s.ReadTimeout
}
// Use http write timeout if https write timeout wasn't defined
if int64(s.TLSWriteTimeout) == 0 {
s.TLSWriteTimeout = s.WriteTimeout
}
}
if s.hasScheme(schemeUnix) {
domSockListener, err := net.Listen("unix", string(s.SocketPath))
if err != nil {
return err
}
s.domainSocketL = domSockListener
}
lookup := func(addr string) []net.IP {
ips, err := net.LookupIP(addr)
if err == nil {
return ips
}
return []net.IP{net.ParseIP(addr)}
}
convert := func(ip net.IP) (string, string) {
if ip == nil {
return "", "tcp"
}
proto := "tcp4"
if ip.To4() == nil {
proto = "tcp6"
}
return ip.String(), proto
}
if s.hasScheme(schemeHTTP) {
for _, ip := range lookup(s.Host) {
host, proto := convert(ip)
listener, err := net.Listen(proto, net.JoinHostPort(host, strconv.Itoa(s.Port)))
if err != nil {
return err
}
if s.Host == "" || s.Port == 0 {
h, p, err := swag.SplitHostPort(listener.Addr().String())
if err != nil {
return err
}
s.Host = h
s.Port = p
}
s.httpServerL = append(s.httpServerL, listener)
}
}
if s.hasScheme(schemeHTTPS) {
for _, ip := range lookup(s.TLSHost) {
host, proto := convert(ip)
tlsListener, err := net.Listen(proto, net.JoinHostPort(host, strconv.Itoa(s.TLSPort)))
if err != nil {
return err
}
if s.TLSHost == "" || s.TLSPort == 0 {
sh, sp, err := swag.SplitHostPort(tlsListener.Addr().String())
if err != nil {
return err
}
s.TLSHost = sh
s.TLSPort = sp
}
s.httpsServerL = append(s.httpsServerL, tlsListener)
}
}
s.hasListeners = true
return nil
}
// Shutdown server and clean up resources
func (s *Server) Shutdown() error {
if atomic.CompareAndSwapInt32(&s.shuttingDown, 0, 1) {
close(s.shutdown)
}
return nil
}
func (s *Server) handleShutdown(wg *sync.WaitGroup, serversPtr *[]*http.Server) {
// wg.Done must occur last, after s.api.ServerShutdown()
// (to preserve old behavior)
defer wg.Done()
<-s.shutdown
servers := *serversPtr
ctx, cancel := context.WithTimeout(context.TODO(), s.GracefulTimeout)
defer cancel()
// first execute the pre-shutdown hook
s.api.PreServerShutdown()
shutdownChan := make(chan bool)
for i := range servers {
server := servers[i]
go func() {
var success bool
defer func() {
shutdownChan <- success
}()
if err := server.Shutdown(ctx); err != nil {
// Error from closing listeners, or context timeout:
s.Logf("HTTP server Shutdown: %v", err)
} else {
success = true
}
}()
}
// Wait until all listeners have successfully shut down before calling ServerShutdown
success := true
for range servers {
success = success && <-shutdownChan
}
if success {
s.api.ServerShutdown()
}
}
// GetHandler returns a handler useful for testing
func (s *Server) GetHandler() http.Handler {
return s.handler
}
// SetHandler allows for setting a http handler on this server
func (s *Server) SetHandler(handler http.Handler) {
s.handler = handler
}
// UnixListener returns the domain socket listener
func (s *Server) UnixListener() (net.Listener, error) {
if !s.hasListeners {
if err := s.Listen(); err != nil {
return nil, err
}
}
return s.domainSocketL, nil
}
// HTTPListener returns the http listener
func (s *Server) HTTPListener() ([]net.Listener, error) {
if !s.hasListeners {
if err := s.Listen(); err != nil {
return nil, err
}
}
return s.httpServerL, nil
}
// TLSListener returns the https listener
func (s *Server) TLSListener() ([]net.Listener, error) {
if !s.hasListeners {
if err := s.Listen(); err != nil {
return nil, err
}
}
return s.httpsServerL, nil
}
func handleInterrupt(once *sync.Once, s *Server) {
once.Do(func() {
for range s.interrupt {
if s.interrupted {
s.Logf("Server already shutting down")
continue
}
s.interrupted = true
s.Logf("Shutting down... ")
if err := s.Shutdown(); err != nil {
s.Logf("HTTP server Shutdown: %v", err)
}
}
})
}
func signalNotify(interrupt chan<- os.Signal) {
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
}

View File

@@ -1,38 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// Package api MinIO Console Server
//
// Schemes:
// http
// ws
// Host: localhost
// BasePath: /api/v1
// Version: 0.1.0
//
// Consumes:
// - application/json
// - multipart/form-data
//
// Produces:
// - application/zip
// - application/octet-stream
// - application/json
//
// swagger:meta
package api

File diff suppressed because it is too large Load Diff

View File

@@ -1,159 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"context"
"fmt"
"testing"
"github.com/minio/console/models"
"github.com/stretchr/testify/assert"
)
func TestError(t *testing.T) {
type args struct {
err []interface{}
}
type testError struct {
name string
args args
want *CodedAPIError
}
var tests []testError
type expectedError struct {
err error
code int
}
appErrors := map[string]expectedError{
"ErrDefault": {code: 500, err: ErrDefault},
"ErrForbidden": {code: 403, err: ErrForbidden},
"ErrFileTooLarge": {code: 413, err: ErrFileTooLarge},
"ErrInvalidSession": {code: 401, err: ErrInvalidSession},
"ErrNotFound": {code: 404, err: ErrNotFound},
"ErrGroupAlreadyExists": {code: 400, err: ErrGroupAlreadyExists},
"ErrInvalidErasureCodingValue": {code: 400, err: ErrInvalidErasureCodingValue},
"ErrBucketBodyNotInRequest": {code: 400, err: ErrBucketBodyNotInRequest},
"ErrBucketNameNotInRequest": {code: 400, err: ErrBucketNameNotInRequest},
"ErrGroupBodyNotInRequest": {code: 400, err: ErrGroupBodyNotInRequest},
"ErrGroupNameNotInRequest": {code: 400, err: ErrGroupNameNotInRequest},
"ErrPolicyNameNotInRequest": {code: 400, err: ErrPolicyNameNotInRequest},
"ErrPolicyBodyNotInRequest": {code: 400, err: ErrPolicyBodyNotInRequest},
"ErrInvalidEncryptionAlgorithm": {code: 500, err: ErrInvalidEncryptionAlgorithm},
"ErrSSENotConfigured": {code: 404, err: ErrSSENotConfigured},
"ErrBucketLifeCycleNotConfigured": {code: 404, err: ErrBucketLifeCycleNotConfigured},
"ErrChangePassword": {code: 403, err: ErrChangePassword},
"ErrInvalidLicense": {code: 404, err: ErrInvalidLicense},
"ErrLicenseNotFound": {code: 404, err: ErrLicenseNotFound},
"ErrAvoidSelfAccountDelete": {code: 403, err: ErrAvoidSelfAccountDelete},
"ErrNonUniqueAccessKey": {code: 500, err: ErrNonUniqueAccessKey},
"ErrRemoteTierExists": {code: 400, err: ErrRemoteTierExists},
"ErrRemoteTierNotFound": {code: 400, err: ErrRemoteTierNotFound},
"ErrRemoteTierUppercase": {code: 400, err: ErrRemoteTierUppercase},
"ErrRemoteTierBucketNotFound": {code: 400, err: ErrRemoteTierBucketNotFound},
"ErrRemoteInvalidCredentials": {code: 403, err: ErrRemoteInvalidCredentials},
"ErrTooFewNodes": {code: 500, err: ErrTooFewNodes},
"ErrUnableToGetTenantUsage": {code: 500, err: ErrUnableToGetTenantUsage},
"ErrTooManyNodes": {code: 500, err: ErrTooManyNodes},
"ErrAccessDenied": {code: 403, err: ErrAccessDenied},
"ErrTooFewAvailableNodes": {code: 500, err: ErrTooFewAvailableNodes},
"ErrFewerThanFourNodes": {code: 500, err: ErrFewerThanFourNodes},
"ErrUnableToGetTenantLogs": {code: 500, err: ErrUnableToGetTenantLogs},
"ErrUnableToUpdateTenantCertificates": {code: 500, err: ErrUnableToUpdateTenantCertificates},
"ErrUpdatingEncryptionConfig": {code: 500, err: ErrUpdatingEncryptionConfig},
"ErrDeletingEncryptionConfig": {code: 500, err: ErrDeletingEncryptionConfig},
"ErrEncryptionConfigNotFound": {code: 404, err: ErrEncryptionConfigNotFound},
}
for k, e := range appErrors {
tests = append(tests, testError{
name: fmt.Sprintf("%s error", k),
args: args{
err: []interface{}{e.err},
},
want: &CodedAPIError{
Code: e.code,
APIError: &models.APIError{Message: e.err.Error(), DetailedMessage: e.err.Error()},
},
})
}
tests = append(tests,
testError{
name: "passing multiple errors but ErrInvalidLogin is last",
args: args{
err: []interface{}{ErrDefault, ErrInvalidLogin},
},
want: &CodedAPIError{
Code: int(401),
APIError: &models.APIError{Message: ErrDefault.Error(), DetailedMessage: ""},
},
})
tests = append(tests,
testError{
name: "login error omits detailedMessage",
args: args{
err: []interface{}{ErrInvalidLogin},
},
want: &CodedAPIError{
Code: int(401),
APIError: &models.APIError{Message: ErrInvalidLogin.Error(), DetailedMessage: ""},
},
})
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
got := Error(tt.args.err...)
assert.Equalf(t, tt.want.Code, got.Code, "Error(%v) Got (%v)", tt.want.Code, got.Code)
assert.Equalf(t, tt.want.APIError.DetailedMessage, got.APIError.DetailedMessage, "Error(%s) Got (%s)", tt.want.APIError.DetailedMessage, got.APIError.DetailedMessage)
})
}
}
func TestErrorWithContext(t *testing.T) {
type args struct {
ctx context.Context
err []interface{}
}
tests := []struct {
name string
args args
want *CodedAPIError
}{
{
name: "default error",
args: args{
ctx: context.Background(),
err: []interface{}{ErrDefault},
},
want: &CodedAPIError{
Code: 500, APIError: &models.APIError{Message: ErrDefault.Error(), DetailedMessage: ErrDefault.Error()},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
assert.Equalf(t, tt.want, ErrorWithContext(tt.args.ctx, tt.args.err...), "ErrorWithContext(%v, %v)", tt.args.ctx, tt.args.err)
})
}
}

View File

@@ -1,71 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"net/http"
"os"
"github.com/minio/pkg/v2/licverifier"
"github.com/minio/pkg/v2/subnet"
)
type SubnetPlan int
const (
PlanAGPL SubnetPlan = iota
PlanStandard
PlanEnterprise
)
func (sp SubnetPlan) String() string {
switch sp {
case PlanStandard:
return "standard"
case PlanEnterprise:
return "enterprise"
default:
return "agpl"
}
}
var InstanceLicensePlan = PlanAGPL
func getLicenseInfo(client http.Client, license string) (*licverifier.LicenseInfo, error) {
lv := subnet.LicenseValidator{
Client: client,
ExpiryGracePeriod: 0,
}
lv.Init(getConsoleDevMode())
return lv.ParseLicense(license)
}
func fetchLicensePlan() {
client := GetConsoleHTTPClient("", "127.0.0.1")
licenseInfo, err := getLicenseInfo(*client, os.Getenv(EnvSubnetLicense))
if err != nil {
return
}
switch licenseInfo.Plan {
case "STANDARD":
InstanceLicensePlan = PlanStandard
case "ENTERPRISE":
InstanceLicensePlan = PlanEnterprise
default:
InstanceLicensePlan = PlanAGPL
}
}

View File

@@ -1,83 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package api
import (
"context"
"errors"
"log"
"os"
"github.com/minio/cli"
)
var (
infoLog = log.New(os.Stdout, "I: ", log.LstdFlags)
errorLog = log.New(os.Stdout, "E: ", log.LstdFlags)
)
func logInfo(msg string, data ...interface{}) {
infoLog.Printf(msg+"\n", data...)
}
func logError(msg string, data ...interface{}) {
errorLog.Printf(msg+"\n", data...)
}
func logIf(_ context.Context, _ error, _ ...interface{}) {
}
// globally changeable logger styles
var (
LogInfo = logInfo
LogError = logError
LogIf = logIf
)
// Context captures all command line flags values
type Context struct {
Host string
HTTPPort, HTTPSPort int
TLSRedirect string
// Legacy options, TODO: remove in future
TLSCertificate, TLSKey, TLSca string
}
// Load loads api Context from command line context.
func (c *Context) Load(ctx *cli.Context) error {
*c = Context{
Host: ctx.String("host"),
HTTPPort: ctx.Int("port"),
HTTPSPort: ctx.Int("tls-port"),
TLSRedirect: ctx.String("tls-redirect"),
// Legacy options to be removed.
TLSCertificate: ctx.String("tls-certificate"),
TLSKey: ctx.String("tls-key"),
TLSca: ctx.String("tls-ca"),
}
if c.HTTPPort > 65535 {
return errors.New("invalid argument --port out of range - ports can range from 1-65535")
}
if c.HTTPSPort > 65535 {
return errors.New("invalid argument --tls-port out of range - ports can range from 1-65535")
}
if c.TLSRedirect != "on" && c.TLSRedirect != "off" {
return errors.New("invalid argument --tls-redirect only accepts either 'on' or 'off'")
}
return nil
}

View File

@@ -1,110 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"flag"
"fmt"
"testing"
"github.com/minio/cli"
"github.com/stretchr/testify/assert"
)
func TestContext_Load(t *testing.T) {
type fields struct {
Host string
HTTPPort int
HTTPSPort int
TLSRedirect string
TLSCertificate string
TLSKey string
TLSca string
}
type args struct {
values map[string]string
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
name: "valid args",
args: args{
values: map[string]string{
"tls-redirect": "on",
},
},
wantErr: false,
},
{
name: "invalid args",
args: args{
values: map[string]string{
"tls-redirect": "aaaa",
},
},
wantErr: true,
},
{
name: "invalid port http",
args: args{
values: map[string]string{
"tls-redirect": "on",
"port": "65536",
},
},
wantErr: true,
},
{
name: "invalid port https",
args: args{
values: map[string]string{
"tls-redirect": "on",
"port": "65534",
"tls-port": "65536",
},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(_ *testing.T) {
c := &Context{}
fs := flag.NewFlagSet("flags", flag.ContinueOnError)
for k, v := range tt.args.values {
fs.String(k, v, "ok")
}
ctx := cli.NewContext(nil, fs, &cli.Context{})
err := c.Load(ctx)
if tt.wantErr {
assert.NotNilf(t, err, fmt.Sprintf("Load(%v)", err))
} else {
assert.Nilf(t, err, fmt.Sprintf("Load(%v)", err))
}
})
}
}
func Test_logInfo(_ *testing.T) {
logInfo("message", nil)
}

View File

@@ -1,73 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
)
// LoginHandlerFunc turns a function with the right signature into a login handler
type LoginHandlerFunc func(LoginParams) middleware.Responder
// Handle executing the request and returning a response
func (fn LoginHandlerFunc) Handle(params LoginParams) middleware.Responder {
return fn(params)
}
// LoginHandler interface for that can handle valid login params
type LoginHandler interface {
Handle(LoginParams) middleware.Responder
}
// NewLogin creates a new http.Handler for the login operation
func NewLogin(ctx *middleware.Context, handler LoginHandler) *Login {
return &Login{Context: ctx, Handler: handler}
}
/*
Login swagger:route POST /login Auth login
Login to Console
*/
type Login struct {
Context *middleware.Context
Handler LoginHandler
}
func (o *Login) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewLoginParams()
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -1,73 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
)
// LoginDetailHandlerFunc turns a function with the right signature into a login detail handler
type LoginDetailHandlerFunc func(LoginDetailParams) middleware.Responder
// Handle executing the request and returning a response
func (fn LoginDetailHandlerFunc) Handle(params LoginDetailParams) middleware.Responder {
return fn(params)
}
// LoginDetailHandler interface for that can handle valid login detail params
type LoginDetailHandler interface {
Handle(LoginDetailParams) middleware.Responder
}
// NewLoginDetail creates a new http.Handler for the login detail operation
func NewLoginDetail(ctx *middleware.Context, handler LoginDetailHandler) *LoginDetail {
return &LoginDetail{Context: ctx, Handler: handler}
}
/*
LoginDetail swagger:route GET /login Auth loginDetail
Returns login strategy, form or sso.
*/
type LoginDetail struct {
Context *middleware.Context
Handler LoginDetailHandler
}
func (o *LoginDetail) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewLoginDetailParams()
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -1,63 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
)
// NewLoginDetailParams creates a new LoginDetailParams object
//
// There are no default values defined in the spec.
func NewLoginDetailParams() LoginDetailParams {
return LoginDetailParams{}
}
// LoginDetailParams contains all the bound params for the login detail operation
// typically these are obtained from a http.Request
//
// swagger:parameters LoginDetail
type LoginDetailParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewLoginDetailParams() beforehand.
func (o *LoginDetailParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -1,135 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// LoginDetailOKCode is the HTTP code returned for type LoginDetailOK
const LoginDetailOKCode int = 200
/*
LoginDetailOK A successful response.
swagger:response loginDetailOK
*/
type LoginDetailOK struct {
/*
In: Body
*/
Payload *models.LoginDetails `json:"body,omitempty"`
}
// NewLoginDetailOK creates LoginDetailOK with default headers values
func NewLoginDetailOK() *LoginDetailOK {
return &LoginDetailOK{}
}
// WithPayload adds the payload to the login detail o k response
func (o *LoginDetailOK) WithPayload(payload *models.LoginDetails) *LoginDetailOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the login detail o k response
func (o *LoginDetailOK) SetPayload(payload *models.LoginDetails) {
o.Payload = payload
}
// WriteResponse to the client
func (o *LoginDetailOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
/*
LoginDetailDefault Generic error response.
swagger:response loginDetailDefault
*/
type LoginDetailDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.APIError `json:"body,omitempty"`
}
// NewLoginDetailDefault creates LoginDetailDefault with default headers values
func NewLoginDetailDefault(code int) *LoginDetailDefault {
if code <= 0 {
code = 500
}
return &LoginDetailDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the login detail default response
func (o *LoginDetailDefault) WithStatusCode(code int) *LoginDetailDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the login detail default response
func (o *LoginDetailDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the login detail default response
func (o *LoginDetailDefault) WithPayload(payload *models.APIError) *LoginDetailDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the login detail default response
func (o *LoginDetailDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}
// WriteResponse to the client
func (o *LoginDetailDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -1,104 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
)
// LoginDetailURL generates an URL for the login detail operation
type LoginDetailURL struct {
_basePath string
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *LoginDetailURL) WithBasePath(bp string) *LoginDetailURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *LoginDetailURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *LoginDetailURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/login"
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *LoginDetailURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *LoginDetailURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *LoginDetailURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on LoginDetailURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on LoginDetailURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *LoginDetailURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -1,73 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
)
// LoginOauth2AuthHandlerFunc turns a function with the right signature into a login oauth2 auth handler
type LoginOauth2AuthHandlerFunc func(LoginOauth2AuthParams) middleware.Responder
// Handle executing the request and returning a response
func (fn LoginOauth2AuthHandlerFunc) Handle(params LoginOauth2AuthParams) middleware.Responder {
return fn(params)
}
// LoginOauth2AuthHandler interface for that can handle valid login oauth2 auth params
type LoginOauth2AuthHandler interface {
Handle(LoginOauth2AuthParams) middleware.Responder
}
// NewLoginOauth2Auth creates a new http.Handler for the login oauth2 auth operation
func NewLoginOauth2Auth(ctx *middleware.Context, handler LoginOauth2AuthHandler) *LoginOauth2Auth {
return &LoginOauth2Auth{Context: ctx, Handler: handler}
}
/*
LoginOauth2Auth swagger:route POST /login/oauth2/auth Auth loginOauth2Auth
Identity Provider oauth2 callback endpoint.
*/
type LoginOauth2Auth struct {
Context *middleware.Context
Handler LoginOauth2AuthHandler
}
func (o *LoginOauth2Auth) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewLoginOauth2AuthParams()
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -1,101 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"io"
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/validate"
"github.com/minio/console/models"
)
// NewLoginOauth2AuthParams creates a new LoginOauth2AuthParams object
//
// There are no default values defined in the spec.
func NewLoginOauth2AuthParams() LoginOauth2AuthParams {
return LoginOauth2AuthParams{}
}
// LoginOauth2AuthParams contains all the bound params for the login oauth2 auth operation
// typically these are obtained from a http.Request
//
// swagger:parameters LoginOauth2Auth
type LoginOauth2AuthParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: body
*/
Body *models.LoginOauth2AuthRequest
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewLoginOauth2AuthParams() beforehand.
func (o *LoginOauth2AuthParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if runtime.HasBody(r) {
defer r.Body.Close()
var body models.LoginOauth2AuthRequest
if err := route.Consumer.Consume(r.Body, &body); err != nil {
if err == io.EOF {
res = append(res, errors.Required("body", "body", ""))
} else {
res = append(res, errors.NewParseError("body", "body", "", err))
}
} else {
// validate body object
if err := body.Validate(route.Formats); err != nil {
res = append(res, err)
}
ctx := validate.WithOperationRequest(r.Context())
if err := body.ContextValidate(ctx, route.Formats); err != nil {
res = append(res, err)
}
if len(res) == 0 {
o.Body = &body
}
}
} else {
res = append(res, errors.Required("body", "body", ""))
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -1,115 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// LoginOauth2AuthNoContentCode is the HTTP code returned for type LoginOauth2AuthNoContent
const LoginOauth2AuthNoContentCode int = 204
/*
LoginOauth2AuthNoContent A successful login.
swagger:response loginOauth2AuthNoContent
*/
type LoginOauth2AuthNoContent struct {
}
// NewLoginOauth2AuthNoContent creates LoginOauth2AuthNoContent with default headers values
func NewLoginOauth2AuthNoContent() *LoginOauth2AuthNoContent {
return &LoginOauth2AuthNoContent{}
}
// WriteResponse to the client
func (o *LoginOauth2AuthNoContent) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
rw.WriteHeader(204)
}
/*
LoginOauth2AuthDefault Generic error response.
swagger:response loginOauth2AuthDefault
*/
type LoginOauth2AuthDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.APIError `json:"body,omitempty"`
}
// NewLoginOauth2AuthDefault creates LoginOauth2AuthDefault with default headers values
func NewLoginOauth2AuthDefault(code int) *LoginOauth2AuthDefault {
if code <= 0 {
code = 500
}
return &LoginOauth2AuthDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the login oauth2 auth default response
func (o *LoginOauth2AuthDefault) WithStatusCode(code int) *LoginOauth2AuthDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the login oauth2 auth default response
func (o *LoginOauth2AuthDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the login oauth2 auth default response
func (o *LoginOauth2AuthDefault) WithPayload(payload *models.APIError) *LoginOauth2AuthDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the login oauth2 auth default response
func (o *LoginOauth2AuthDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}
// WriteResponse to the client
func (o *LoginOauth2AuthDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -1,104 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
)
// LoginOauth2AuthURL generates an URL for the login oauth2 auth operation
type LoginOauth2AuthURL struct {
_basePath string
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *LoginOauth2AuthURL) WithBasePath(bp string) *LoginOauth2AuthURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *LoginOauth2AuthURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *LoginOauth2AuthURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/login/oauth2/auth"
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *LoginOauth2AuthURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *LoginOauth2AuthURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *LoginOauth2AuthURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on LoginOauth2AuthURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on LoginOauth2AuthURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *LoginOauth2AuthURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -1,88 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// LogoutHandlerFunc turns a function with the right signature into a logout handler
type LogoutHandlerFunc func(LogoutParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn LogoutHandlerFunc) Handle(params LogoutParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// LogoutHandler interface for that can handle valid logout params
type LogoutHandler interface {
Handle(LogoutParams, *models.Principal) middleware.Responder
}
// NewLogout creates a new http.Handler for the logout operation
func NewLogout(ctx *middleware.Context, handler LogoutHandler) *Logout {
return &Logout{Context: ctx, Handler: handler}
}
/*
Logout swagger:route POST /logout Auth logout
Logout from Console.
*/
type Logout struct {
Context *middleware.Context
Handler LogoutHandler
}
func (o *Logout) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewLogoutParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -1,101 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"io"
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/validate"
"github.com/minio/console/models"
)
// NewLogoutParams creates a new LogoutParams object
//
// There are no default values defined in the spec.
func NewLogoutParams() LogoutParams {
return LogoutParams{}
}
// LogoutParams contains all the bound params for the logout operation
// typically these are obtained from a http.Request
//
// swagger:parameters Logout
type LogoutParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: body
*/
Body *models.LogoutRequest
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewLogoutParams() beforehand.
func (o *LogoutParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if runtime.HasBody(r) {
defer r.Body.Close()
var body models.LogoutRequest
if err := route.Consumer.Consume(r.Body, &body); err != nil {
if err == io.EOF {
res = append(res, errors.Required("body", "body", ""))
} else {
res = append(res, errors.NewParseError("body", "body", "", err))
}
} else {
// validate body object
if err := body.Validate(route.Formats); err != nil {
res = append(res, err)
}
ctx := validate.WithOperationRequest(r.Context())
if err := body.ContextValidate(ctx, route.Formats); err != nil {
res = append(res, err)
}
if len(res) == 0 {
o.Body = &body
}
}
} else {
res = append(res, errors.Required("body", "body", ""))
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -1,115 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// LogoutOKCode is the HTTP code returned for type LogoutOK
const LogoutOKCode int = 200
/*
LogoutOK A successful response.
swagger:response logoutOK
*/
type LogoutOK struct {
}
// NewLogoutOK creates LogoutOK with default headers values
func NewLogoutOK() *LogoutOK {
return &LogoutOK{}
}
// WriteResponse to the client
func (o *LogoutOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
rw.WriteHeader(200)
}
/*
LogoutDefault Generic error response.
swagger:response logoutDefault
*/
type LogoutDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.APIError `json:"body,omitempty"`
}
// NewLogoutDefault creates LogoutDefault with default headers values
func NewLogoutDefault(code int) *LogoutDefault {
if code <= 0 {
code = 500
}
return &LogoutDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the logout default response
func (o *LogoutDefault) WithStatusCode(code int) *LogoutDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the logout default response
func (o *LogoutDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the logout default response
func (o *LogoutDefault) WithPayload(payload *models.APIError) *LogoutDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the logout default response
func (o *LogoutDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}
// WriteResponse to the client
func (o *LogoutDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -1,104 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
)
// LogoutURL generates an URL for the logout operation
type LogoutURL struct {
_basePath string
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *LogoutURL) WithBasePath(bp string) *LogoutURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *LogoutURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *LogoutURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/logout"
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *LogoutURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *LogoutURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *LogoutURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on LogoutURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on LogoutURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *LogoutURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -1,88 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// SessionCheckHandlerFunc turns a function with the right signature into a session check handler
type SessionCheckHandlerFunc func(SessionCheckParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn SessionCheckHandlerFunc) Handle(params SessionCheckParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// SessionCheckHandler interface for that can handle valid session check params
type SessionCheckHandler interface {
Handle(SessionCheckParams, *models.Principal) middleware.Responder
}
// NewSessionCheck creates a new http.Handler for the session check operation
func NewSessionCheck(ctx *middleware.Context, handler SessionCheckHandler) *SessionCheck {
return &SessionCheck{Context: ctx, Handler: handler}
}
/*
SessionCheck swagger:route GET /session Auth sessionCheck
Endpoint to check if your session is still valid
*/
type SessionCheck struct {
Context *middleware.Context
Handler SessionCheckHandler
}
func (o *SessionCheck) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewSessionCheckParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -1,63 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
)
// NewSessionCheckParams creates a new SessionCheckParams object
//
// There are no default values defined in the spec.
func NewSessionCheckParams() SessionCheckParams {
return SessionCheckParams{}
}
// SessionCheckParams contains all the bound params for the session check operation
// typically these are obtained from a http.Request
//
// swagger:parameters SessionCheck
type SessionCheckParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewSessionCheckParams() beforehand.
func (o *SessionCheckParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -1,135 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// SessionCheckOKCode is the HTTP code returned for type SessionCheckOK
const SessionCheckOKCode int = 200
/*
SessionCheckOK A successful response.
swagger:response sessionCheckOK
*/
type SessionCheckOK struct {
/*
In: Body
*/
Payload *models.SessionResponse `json:"body,omitempty"`
}
// NewSessionCheckOK creates SessionCheckOK with default headers values
func NewSessionCheckOK() *SessionCheckOK {
return &SessionCheckOK{}
}
// WithPayload adds the payload to the session check o k response
func (o *SessionCheckOK) WithPayload(payload *models.SessionResponse) *SessionCheckOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the session check o k response
func (o *SessionCheckOK) SetPayload(payload *models.SessionResponse) {
o.Payload = payload
}
// WriteResponse to the client
func (o *SessionCheckOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
/*
SessionCheckDefault Generic error response.
swagger:response sessionCheckDefault
*/
type SessionCheckDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.APIError `json:"body,omitempty"`
}
// NewSessionCheckDefault creates SessionCheckDefault with default headers values
func NewSessionCheckDefault(code int) *SessionCheckDefault {
if code <= 0 {
code = 500
}
return &SessionCheckDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the session check default response
func (o *SessionCheckDefault) WithStatusCode(code int) *SessionCheckDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the session check default response
func (o *SessionCheckDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the session check default response
func (o *SessionCheckDefault) WithPayload(payload *models.APIError) *SessionCheckDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the session check default response
func (o *SessionCheckDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}
// WriteResponse to the client
func (o *SessionCheckDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -1,104 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package auth
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
)
// SessionCheckURL generates an URL for the session check operation
type SessionCheckURL struct {
_basePath string
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *SessionCheckURL) WithBasePath(bp string) *SessionCheckURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *SessionCheckURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *SessionCheckURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/session"
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *SessionCheckURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *SessionCheckURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *SessionCheckURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on SessionCheckURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on SessionCheckURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *SessionCheckURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -1,88 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package bucket
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// GetMaxShareLinkExpHandlerFunc turns a function with the right signature into a get max share link exp handler
type GetMaxShareLinkExpHandlerFunc func(GetMaxShareLinkExpParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn GetMaxShareLinkExpHandlerFunc) Handle(params GetMaxShareLinkExpParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// GetMaxShareLinkExpHandler interface for that can handle valid get max share link exp params
type GetMaxShareLinkExpHandler interface {
Handle(GetMaxShareLinkExpParams, *models.Principal) middleware.Responder
}
// NewGetMaxShareLinkExp creates a new http.Handler for the get max share link exp operation
func NewGetMaxShareLinkExp(ctx *middleware.Context, handler GetMaxShareLinkExpHandler) *GetMaxShareLinkExp {
return &GetMaxShareLinkExp{Context: ctx, Handler: handler}
}
/*
GetMaxShareLinkExp swagger:route GET /buckets/max-share-exp Bucket getMaxShareLinkExp
Get max expiration time for share link in seconds
*/
type GetMaxShareLinkExp struct {
Context *middleware.Context
Handler GetMaxShareLinkExpHandler
}
func (o *GetMaxShareLinkExp) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewGetMaxShareLinkExpParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -1,63 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package bucket
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
)
// NewGetMaxShareLinkExpParams creates a new GetMaxShareLinkExpParams object
//
// There are no default values defined in the spec.
func NewGetMaxShareLinkExpParams() GetMaxShareLinkExpParams {
return GetMaxShareLinkExpParams{}
}
// GetMaxShareLinkExpParams contains all the bound params for the get max share link exp operation
// typically these are obtained from a http.Request
//
// swagger:parameters GetMaxShareLinkExp
type GetMaxShareLinkExpParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewGetMaxShareLinkExpParams() beforehand.
func (o *GetMaxShareLinkExpParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -1,135 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package bucket
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// GetMaxShareLinkExpOKCode is the HTTP code returned for type GetMaxShareLinkExpOK
const GetMaxShareLinkExpOKCode int = 200
/*
GetMaxShareLinkExpOK A successful response.
swagger:response getMaxShareLinkExpOK
*/
type GetMaxShareLinkExpOK struct {
/*
In: Body
*/
Payload *models.MaxShareLinkExpResponse `json:"body,omitempty"`
}
// NewGetMaxShareLinkExpOK creates GetMaxShareLinkExpOK with default headers values
func NewGetMaxShareLinkExpOK() *GetMaxShareLinkExpOK {
return &GetMaxShareLinkExpOK{}
}
// WithPayload adds the payload to the get max share link exp o k response
func (o *GetMaxShareLinkExpOK) WithPayload(payload *models.MaxShareLinkExpResponse) *GetMaxShareLinkExpOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get max share link exp o k response
func (o *GetMaxShareLinkExpOK) SetPayload(payload *models.MaxShareLinkExpResponse) {
o.Payload = payload
}
// WriteResponse to the client
func (o *GetMaxShareLinkExpOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
/*
GetMaxShareLinkExpDefault Generic error response.
swagger:response getMaxShareLinkExpDefault
*/
type GetMaxShareLinkExpDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.APIError `json:"body,omitempty"`
}
// NewGetMaxShareLinkExpDefault creates GetMaxShareLinkExpDefault with default headers values
func NewGetMaxShareLinkExpDefault(code int) *GetMaxShareLinkExpDefault {
if code <= 0 {
code = 500
}
return &GetMaxShareLinkExpDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the get max share link exp default response
func (o *GetMaxShareLinkExpDefault) WithStatusCode(code int) *GetMaxShareLinkExpDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the get max share link exp default response
func (o *GetMaxShareLinkExpDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the get max share link exp default response
func (o *GetMaxShareLinkExpDefault) WithPayload(payload *models.APIError) *GetMaxShareLinkExpDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get max share link exp default response
func (o *GetMaxShareLinkExpDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}
// WriteResponse to the client
func (o *GetMaxShareLinkExpDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -1,104 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package bucket
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
)
// GetMaxShareLinkExpURL generates an URL for the get max share link exp operation
type GetMaxShareLinkExpURL struct {
_basePath string
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *GetMaxShareLinkExpURL) WithBasePath(bp string) *GetMaxShareLinkExpURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *GetMaxShareLinkExpURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *GetMaxShareLinkExpURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/buckets/max-share-exp"
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *GetMaxShareLinkExpURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *GetMaxShareLinkExpURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *GetMaxShareLinkExpURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on GetMaxShareLinkExpURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on GetMaxShareLinkExpURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *GetMaxShareLinkExpURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -1,135 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package bucket
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// MakeBucketOKCode is the HTTP code returned for type MakeBucketOK
const MakeBucketOKCode int = 200
/*
MakeBucketOK A successful response.
swagger:response makeBucketOK
*/
type MakeBucketOK struct {
/*
In: Body
*/
Payload *models.MakeBucketsResponse `json:"body,omitempty"`
}
// NewMakeBucketOK creates MakeBucketOK with default headers values
func NewMakeBucketOK() *MakeBucketOK {
return &MakeBucketOK{}
}
// WithPayload adds the payload to the make bucket o k response
func (o *MakeBucketOK) WithPayload(payload *models.MakeBucketsResponse) *MakeBucketOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the make bucket o k response
func (o *MakeBucketOK) SetPayload(payload *models.MakeBucketsResponse) {
o.Payload = payload
}
// WriteResponse to the client
func (o *MakeBucketOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
/*
MakeBucketDefault Generic error response.
swagger:response makeBucketDefault
*/
type MakeBucketDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.APIError `json:"body,omitempty"`
}
// NewMakeBucketDefault creates MakeBucketDefault with default headers values
func NewMakeBucketDefault(code int) *MakeBucketDefault {
if code <= 0 {
code = 500
}
return &MakeBucketDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the make bucket default response
func (o *MakeBucketDefault) WithStatusCode(code int) *MakeBucketDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the make bucket default response
func (o *MakeBucketDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the make bucket default response
func (o *MakeBucketDefault) WithPayload(payload *models.APIError) *MakeBucketDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the make bucket default response
func (o *MakeBucketDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}
// WriteResponse to the client
func (o *MakeBucketDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -1,88 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package configuration
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// ExportConfigHandlerFunc turns a function with the right signature into a export config handler
type ExportConfigHandlerFunc func(ExportConfigParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn ExportConfigHandlerFunc) Handle(params ExportConfigParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// ExportConfigHandler interface for that can handle valid export config params
type ExportConfigHandler interface {
Handle(ExportConfigParams, *models.Principal) middleware.Responder
}
// NewExportConfig creates a new http.Handler for the export config operation
func NewExportConfig(ctx *middleware.Context, handler ExportConfigHandler) *ExportConfig {
return &ExportConfig{Context: ctx, Handler: handler}
}
/*
ExportConfig swagger:route GET /configs/export Configuration exportConfig
Export the current config from MinIO server
*/
type ExportConfig struct {
Context *middleware.Context
Handler ExportConfigHandler
}
func (o *ExportConfig) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewExportConfigParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -1,63 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package configuration
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
)
// NewExportConfigParams creates a new ExportConfigParams object
//
// There are no default values defined in the spec.
func NewExportConfigParams() ExportConfigParams {
return ExportConfigParams{}
}
// ExportConfigParams contains all the bound params for the export config operation
// typically these are obtained from a http.Request
//
// swagger:parameters ExportConfig
type ExportConfigParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewExportConfigParams() beforehand.
func (o *ExportConfigParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -1,135 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package configuration
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// ExportConfigOKCode is the HTTP code returned for type ExportConfigOK
const ExportConfigOKCode int = 200
/*
ExportConfigOK A successful response.
swagger:response exportConfigOK
*/
type ExportConfigOK struct {
/*
In: Body
*/
Payload *models.ConfigExportResponse `json:"body,omitempty"`
}
// NewExportConfigOK creates ExportConfigOK with default headers values
func NewExportConfigOK() *ExportConfigOK {
return &ExportConfigOK{}
}
// WithPayload adds the payload to the export config o k response
func (o *ExportConfigOK) WithPayload(payload *models.ConfigExportResponse) *ExportConfigOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the export config o k response
func (o *ExportConfigOK) SetPayload(payload *models.ConfigExportResponse) {
o.Payload = payload
}
// WriteResponse to the client
func (o *ExportConfigOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
/*
ExportConfigDefault Generic error response.
swagger:response exportConfigDefault
*/
type ExportConfigDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.APIError `json:"body,omitempty"`
}
// NewExportConfigDefault creates ExportConfigDefault with default headers values
func NewExportConfigDefault(code int) *ExportConfigDefault {
if code <= 0 {
code = 500
}
return &ExportConfigDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the export config default response
func (o *ExportConfigDefault) WithStatusCode(code int) *ExportConfigDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the export config default response
func (o *ExportConfigDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the export config default response
func (o *ExportConfigDefault) WithPayload(payload *models.APIError) *ExportConfigDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the export config default response
func (o *ExportConfigDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}
// WriteResponse to the client
func (o *ExportConfigDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -1,104 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package configuration
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
)
// ExportConfigURL generates an URL for the export config operation
type ExportConfigURL struct {
_basePath string
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *ExportConfigURL) WithBasePath(bp string) *ExportConfigURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *ExportConfigURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *ExportConfigURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/configs/export"
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *ExportConfigURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *ExportConfigURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *ExportConfigURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on ExportConfigURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on ExportConfigURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *ExportConfigURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -1,88 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package configuration
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// PostConfigsImportHandlerFunc turns a function with the right signature into a post configs import handler
type PostConfigsImportHandlerFunc func(PostConfigsImportParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn PostConfigsImportHandlerFunc) Handle(params PostConfigsImportParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// PostConfigsImportHandler interface for that can handle valid post configs import params
type PostConfigsImportHandler interface {
Handle(PostConfigsImportParams, *models.Principal) middleware.Responder
}
// NewPostConfigsImport creates a new http.Handler for the post configs import operation
func NewPostConfigsImport(ctx *middleware.Context, handler PostConfigsImportHandler) *PostConfigsImport {
return &PostConfigsImport{Context: ctx, Handler: handler}
}
/*
PostConfigsImport swagger:route POST /configs/import Configuration postConfigsImport
Uploads a file to import MinIO server config.
*/
type PostConfigsImport struct {
Context *middleware.Context
Handler PostConfigsImportHandler
}
func (o *PostConfigsImport) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewPostConfigsImportParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -1,103 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package configuration
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"io"
"mime/multipart"
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
)
// PostConfigsImportMaxParseMemory sets the maximum size in bytes for
// the multipart form parser for this operation.
//
// The default value is 32 MB.
// The multipart parser stores up to this + 10MB.
var PostConfigsImportMaxParseMemory int64 = 32 << 20
// NewPostConfigsImportParams creates a new PostConfigsImportParams object
//
// There are no default values defined in the spec.
func NewPostConfigsImportParams() PostConfigsImportParams {
return PostConfigsImportParams{}
}
// PostConfigsImportParams contains all the bound params for the post configs import operation
// typically these are obtained from a http.Request
//
// swagger:parameters PostConfigsImport
type PostConfigsImportParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: formData
*/
File io.ReadCloser
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewPostConfigsImportParams() beforehand.
func (o *PostConfigsImportParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if err := r.ParseMultipartForm(PostConfigsImportMaxParseMemory); err != nil {
if err != http.ErrNotMultipart {
return errors.New(400, "%v", err)
} else if err := r.ParseForm(); err != nil {
return errors.New(400, "%v", err)
}
}
file, fileHeader, err := r.FormFile("file")
if err != nil {
res = append(res, errors.New(400, "reading file %q failed: %v", "file", err))
} else if err := o.bindFile(file, fileHeader); err != nil {
// Required: true
res = append(res, err)
} else {
o.File = &runtime.File{Data: file, Header: fileHeader}
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindFile binds file parameter File.
//
// The only supported validations on files are MinLength and MaxLength
func (o *PostConfigsImportParams) bindFile(file multipart.File, header *multipart.FileHeader) error {
return nil
}

View File

@@ -1,115 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package configuration
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// PostConfigsImportOKCode is the HTTP code returned for type PostConfigsImportOK
const PostConfigsImportOKCode int = 200
/*
PostConfigsImportOK A successful response.
swagger:response postConfigsImportOK
*/
type PostConfigsImportOK struct {
}
// NewPostConfigsImportOK creates PostConfigsImportOK with default headers values
func NewPostConfigsImportOK() *PostConfigsImportOK {
return &PostConfigsImportOK{}
}
// WriteResponse to the client
func (o *PostConfigsImportOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
rw.WriteHeader(200)
}
/*
PostConfigsImportDefault Generic error response.
swagger:response postConfigsImportDefault
*/
type PostConfigsImportDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.APIError `json:"body,omitempty"`
}
// NewPostConfigsImportDefault creates PostConfigsImportDefault with default headers values
func NewPostConfigsImportDefault(code int) *PostConfigsImportDefault {
if code <= 0 {
code = 500
}
return &PostConfigsImportDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the post configs import default response
func (o *PostConfigsImportDefault) WithStatusCode(code int) *PostConfigsImportDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the post configs import default response
func (o *PostConfigsImportDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the post configs import default response
func (o *PostConfigsImportDefault) WithPayload(payload *models.APIError) *PostConfigsImportDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the post configs import default response
func (o *PostConfigsImportDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}
// WriteResponse to the client
func (o *PostConfigsImportDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -1,104 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package configuration
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
)
// PostConfigsImportURL generates an URL for the post configs import operation
type PostConfigsImportURL struct {
_basePath string
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *PostConfigsImportURL) WithBasePath(bp string) *PostConfigsImportURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *PostConfigsImportURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *PostConfigsImportURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/configs/import"
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *PostConfigsImportURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *PostConfigsImportURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *PostConfigsImportURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on PostConfigsImportURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on PostConfigsImportURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *PostConfigsImportURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -1,88 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package idp
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// CreateConfigurationHandlerFunc turns a function with the right signature into a create configuration handler
type CreateConfigurationHandlerFunc func(CreateConfigurationParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn CreateConfigurationHandlerFunc) Handle(params CreateConfigurationParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// CreateConfigurationHandler interface for that can handle valid create configuration params
type CreateConfigurationHandler interface {
Handle(CreateConfigurationParams, *models.Principal) middleware.Responder
}
// NewCreateConfiguration creates a new http.Handler for the create configuration operation
func NewCreateConfiguration(ctx *middleware.Context, handler CreateConfigurationHandler) *CreateConfiguration {
return &CreateConfiguration{Context: ctx, Handler: handler}
}
/*
CreateConfiguration swagger:route POST /idp/{type} idp createConfiguration
Create IDP Configuration
*/
type CreateConfiguration struct {
Context *middleware.Context
Handler CreateConfigurationHandler
}
func (o *CreateConfiguration) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewCreateConfigurationParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -1,126 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package idp
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"io"
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"
"github.com/minio/console/models"
)
// NewCreateConfigurationParams creates a new CreateConfigurationParams object
//
// There are no default values defined in the spec.
func NewCreateConfigurationParams() CreateConfigurationParams {
return CreateConfigurationParams{}
}
// CreateConfigurationParams contains all the bound params for the create configuration operation
// typically these are obtained from a http.Request
//
// swagger:parameters CreateConfiguration
type CreateConfigurationParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: body
*/
Body *models.IdpServerConfiguration
/*IDP Configuration Type
Required: true
In: path
*/
Type string
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewCreateConfigurationParams() beforehand.
func (o *CreateConfigurationParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if runtime.HasBody(r) {
defer r.Body.Close()
var body models.IdpServerConfiguration
if err := route.Consumer.Consume(r.Body, &body); err != nil {
if err == io.EOF {
res = append(res, errors.Required("body", "body", ""))
} else {
res = append(res, errors.NewParseError("body", "body", "", err))
}
} else {
// validate body object
if err := body.Validate(route.Formats); err != nil {
res = append(res, err)
}
ctx := validate.WithOperationRequest(r.Context())
if err := body.ContextValidate(ctx, route.Formats); err != nil {
res = append(res, err)
}
if len(res) == 0 {
o.Body = &body
}
}
} else {
res = append(res, errors.Required("body", "body", ""))
}
rType, rhkType, _ := route.Params.GetOK("type")
if err := o.bindType(rType, rhkType, route.Formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindType binds and validates parameter Type from path.
func (o *CreateConfigurationParams) bindType(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Type = raw
return nil
}

View File

@@ -1,135 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package idp
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// CreateConfigurationCreatedCode is the HTTP code returned for type CreateConfigurationCreated
const CreateConfigurationCreatedCode int = 201
/*
CreateConfigurationCreated A successful response.
swagger:response createConfigurationCreated
*/
type CreateConfigurationCreated struct {
/*
In: Body
*/
Payload *models.SetIDPResponse `json:"body,omitempty"`
}
// NewCreateConfigurationCreated creates CreateConfigurationCreated with default headers values
func NewCreateConfigurationCreated() *CreateConfigurationCreated {
return &CreateConfigurationCreated{}
}
// WithPayload adds the payload to the create configuration created response
func (o *CreateConfigurationCreated) WithPayload(payload *models.SetIDPResponse) *CreateConfigurationCreated {
o.Payload = payload
return o
}
// SetPayload sets the payload to the create configuration created response
func (o *CreateConfigurationCreated) SetPayload(payload *models.SetIDPResponse) {
o.Payload = payload
}
// WriteResponse to the client
func (o *CreateConfigurationCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(201)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
/*
CreateConfigurationDefault Generic error response.
swagger:response createConfigurationDefault
*/
type CreateConfigurationDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.APIError `json:"body,omitempty"`
}
// NewCreateConfigurationDefault creates CreateConfigurationDefault with default headers values
func NewCreateConfigurationDefault(code int) *CreateConfigurationDefault {
if code <= 0 {
code = 500
}
return &CreateConfigurationDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the create configuration default response
func (o *CreateConfigurationDefault) WithStatusCode(code int) *CreateConfigurationDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the create configuration default response
func (o *CreateConfigurationDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the create configuration default response
func (o *CreateConfigurationDefault) WithPayload(payload *models.APIError) *CreateConfigurationDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the create configuration default response
func (o *CreateConfigurationDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}
// WriteResponse to the client
func (o *CreateConfigurationDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -1,116 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package idp
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
"strings"
)
// CreateConfigurationURL generates an URL for the create configuration operation
type CreateConfigurationURL struct {
Type string
_basePath string
// avoid unkeyed usage
_ struct{}
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *CreateConfigurationURL) WithBasePath(bp string) *CreateConfigurationURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *CreateConfigurationURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *CreateConfigurationURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/idp/{type}"
typeVar := o.Type
if typeVar != "" {
_path = strings.Replace(_path, "{type}", typeVar, -1)
} else {
return nil, errors.New("type is required on CreateConfigurationURL")
}
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *CreateConfigurationURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *CreateConfigurationURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *CreateConfigurationURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on CreateConfigurationURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on CreateConfigurationURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *CreateConfigurationURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -1,88 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package idp
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// DeleteConfigurationHandlerFunc turns a function with the right signature into a delete configuration handler
type DeleteConfigurationHandlerFunc func(DeleteConfigurationParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn DeleteConfigurationHandlerFunc) Handle(params DeleteConfigurationParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// DeleteConfigurationHandler interface for that can handle valid delete configuration params
type DeleteConfigurationHandler interface {
Handle(DeleteConfigurationParams, *models.Principal) middleware.Responder
}
// NewDeleteConfiguration creates a new http.Handler for the delete configuration operation
func NewDeleteConfiguration(ctx *middleware.Context, handler DeleteConfigurationHandler) *DeleteConfiguration {
return &DeleteConfiguration{Context: ctx, Handler: handler}
}
/*
DeleteConfiguration swagger:route DELETE /idp/{type}/{name} idp deleteConfiguration
Delete IDP Configuration
*/
type DeleteConfiguration struct {
Context *middleware.Context
Handler DeleteConfigurationHandler
}
func (o *DeleteConfiguration) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewDeleteConfigurationParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -1,112 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package idp
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
)
// NewDeleteConfigurationParams creates a new DeleteConfigurationParams object
//
// There are no default values defined in the spec.
func NewDeleteConfigurationParams() DeleteConfigurationParams {
return DeleteConfigurationParams{}
}
// DeleteConfigurationParams contains all the bound params for the delete configuration operation
// typically these are obtained from a http.Request
//
// swagger:parameters DeleteConfiguration
type DeleteConfigurationParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*IDP Configuration Name
Required: true
In: path
*/
Name string
/*IDP Configuration Type
Required: true
In: path
*/
Type string
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewDeleteConfigurationParams() beforehand.
func (o *DeleteConfigurationParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
rName, rhkName, _ := route.Params.GetOK("name")
if err := o.bindName(rName, rhkName, route.Formats); err != nil {
res = append(res, err)
}
rType, rhkType, _ := route.Params.GetOK("type")
if err := o.bindType(rType, rhkType, route.Formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindName binds and validates parameter Name from path.
func (o *DeleteConfigurationParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Name = raw
return nil
}
// bindType binds and validates parameter Type from path.
func (o *DeleteConfigurationParams) bindType(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Type = raw
return nil
}

View File

@@ -1,135 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package idp
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// DeleteConfigurationOKCode is the HTTP code returned for type DeleteConfigurationOK
const DeleteConfigurationOKCode int = 200
/*
DeleteConfigurationOK A successful response.
swagger:response deleteConfigurationOK
*/
type DeleteConfigurationOK struct {
/*
In: Body
*/
Payload *models.SetIDPResponse `json:"body,omitempty"`
}
// NewDeleteConfigurationOK creates DeleteConfigurationOK with default headers values
func NewDeleteConfigurationOK() *DeleteConfigurationOK {
return &DeleteConfigurationOK{}
}
// WithPayload adds the payload to the delete configuration o k response
func (o *DeleteConfigurationOK) WithPayload(payload *models.SetIDPResponse) *DeleteConfigurationOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the delete configuration o k response
func (o *DeleteConfigurationOK) SetPayload(payload *models.SetIDPResponse) {
o.Payload = payload
}
// WriteResponse to the client
func (o *DeleteConfigurationOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
/*
DeleteConfigurationDefault Generic error response.
swagger:response deleteConfigurationDefault
*/
type DeleteConfigurationDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.APIError `json:"body,omitempty"`
}
// NewDeleteConfigurationDefault creates DeleteConfigurationDefault with default headers values
func NewDeleteConfigurationDefault(code int) *DeleteConfigurationDefault {
if code <= 0 {
code = 500
}
return &DeleteConfigurationDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the delete configuration default response
func (o *DeleteConfigurationDefault) WithStatusCode(code int) *DeleteConfigurationDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the delete configuration default response
func (o *DeleteConfigurationDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the delete configuration default response
func (o *DeleteConfigurationDefault) WithPayload(payload *models.APIError) *DeleteConfigurationDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the delete configuration default response
func (o *DeleteConfigurationDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}
// WriteResponse to the client
func (o *DeleteConfigurationDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -1,124 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package idp
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
"strings"
)
// DeleteConfigurationURL generates an URL for the delete configuration operation
type DeleteConfigurationURL struct {
Name string
Type string
_basePath string
// avoid unkeyed usage
_ struct{}
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *DeleteConfigurationURL) WithBasePath(bp string) *DeleteConfigurationURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *DeleteConfigurationURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *DeleteConfigurationURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/idp/{type}/{name}"
name := o.Name
if name != "" {
_path = strings.Replace(_path, "{name}", name, -1)
} else {
return nil, errors.New("name is required on DeleteConfigurationURL")
}
typeVar := o.Type
if typeVar != "" {
_path = strings.Replace(_path, "{type}", typeVar, -1)
} else {
return nil, errors.New("type is required on DeleteConfigurationURL")
}
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *DeleteConfigurationURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *DeleteConfigurationURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *DeleteConfigurationURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on DeleteConfigurationURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on DeleteConfigurationURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *DeleteConfigurationURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -1,88 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package idp
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// GetConfigurationHandlerFunc turns a function with the right signature into a get configuration handler
type GetConfigurationHandlerFunc func(GetConfigurationParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn GetConfigurationHandlerFunc) Handle(params GetConfigurationParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// GetConfigurationHandler interface for that can handle valid get configuration params
type GetConfigurationHandler interface {
Handle(GetConfigurationParams, *models.Principal) middleware.Responder
}
// NewGetConfiguration creates a new http.Handler for the get configuration operation
func NewGetConfiguration(ctx *middleware.Context, handler GetConfigurationHandler) *GetConfiguration {
return &GetConfiguration{Context: ctx, Handler: handler}
}
/*
GetConfiguration swagger:route GET /idp/{type}/{name} idp getConfiguration
Get IDP Configuration
*/
type GetConfiguration struct {
Context *middleware.Context
Handler GetConfigurationHandler
}
func (o *GetConfiguration) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewGetConfigurationParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

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