MCS service account authentication with Mkube (#166)
`MCS` will authenticate against `Mkube`using bearer tokens via HTTP `Authorization` header. The user will provide this token once in the login form, MCS will validate it against Mkube (list tenants) and if valid will generate and return a new MCS sessions with encrypted claims (the user Service account token will be inside the JWT in the data field) Kubernetes The provided `JWT token` corresponds to the `Kubernetes service account` that `Mkube` will use to run tasks on behalf of the user, ie: list, create, edit, delete tenants, storage class, etc. Development If you are running mcs in your local environment and wish to make request to `Mkube` you can set `MCS_M3_HOSTNAME`, if the environment variable is not present by default `MCS` will use `"http://m3:8787"`, additionally you will need to set the `MCS_MKUBE_ADMIN_ONLY=on` variable to make MCS display the Mkube UI Extract the Service account token and use it with MCS For local development you can use the jwt associated to the `m3-sa` service account, you can get the token running the following command in your terminal: ``` kubectl get secret $(kubectl get serviceaccount m3-sa -o jsonpath="{.secrets[0].name}") -o jsonpath="{.data.token}" | base64 --decode ``` Then run the mcs server ``` MCS_M3_HOSTNAME=http://localhost:8787 MCS_MKUBE_ADMIN_ONLY=on ./mcs server ``` Self-signed certificates and Custom certificate authority for Mkube If Mkube uses TLS with a self-signed certificate, or a certificate issued by a custom certificate authority you can add those certificates usinng the `MCS_M3_SERVER_TLS_CA_CERTIFICATE` env variable ```` MCS_M3_SERVER_TLS_CA_CERTIFICATE=cert1.pem,cert2.pem,cert3.pem ./mcs server ````
This commit is contained in:
40
docs/mcs_service_account_mkube.md
Normal file
40
docs/mcs_service_account_mkube.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# MCS service account authentication with Mkube
|
||||||
|
|
||||||
|
`MCS` will authenticate against `Mkube`using bearer tokens via HTTP `Authorization` header. The user will provide this token once
|
||||||
|
in the login form, MCS will validate it against Mkube (list tenants) and if valid will generate and return a new MCS sessions
|
||||||
|
with encrypted claims (the user Service account token will be inside the JWT in the data field)
|
||||||
|
|
||||||
|
# Kubernetes
|
||||||
|
|
||||||
|
The provided `JWT token` corresponds to the `Kubernetes service account` that `Mkube` will use to run tasks on behalf of the
|
||||||
|
user, ie: list, create, edit, delete tenants, storage class, etc.
|
||||||
|
|
||||||
|
# Development
|
||||||
|
|
||||||
|
If you are running mcs in your local environment and wish to make request to `Mkube` you can set `MCS_M3_HOSTNAME`, if
|
||||||
|
the environment variable is not present by default `MCS` will use `"http://m3:8787"`, additionally you will need to set the
|
||||||
|
`MCS_MKUBE_ADMIN_ONLY=on` variable to make MCS display the Mkube UI
|
||||||
|
|
||||||
|
## Extract the Service account token and use it with MCS
|
||||||
|
|
||||||
|
For local development you can use the jwt associated to the `m3-sa` service account, you can get the token running
|
||||||
|
the following command in your terminal:
|
||||||
|
|
||||||
|
```
|
||||||
|
kubectl get secret $(kubectl get serviceaccount m3-sa -o jsonpath="{.secrets[0].name}") -o jsonpath="{.data.token}" | base64 --decode
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run the mcs server
|
||||||
|
|
||||||
|
```
|
||||||
|
MCS_M3_HOSTNAME=http://localhost:8787 MCS_MKUBE_ADMIN_ONLY=on ./mcs server
|
||||||
|
```
|
||||||
|
|
||||||
|
# Self-signed certificates and Custom certificate authority for Mkube
|
||||||
|
|
||||||
|
If Mkube uses TLS with a self-signed certificate, or a certificate issued by a custom certificate authority you can add those
|
||||||
|
certificates usinng the `MCS_M3_SERVER_TLS_CA_CERTIFICATE` env variable
|
||||||
|
|
||||||
|
````
|
||||||
|
MCS_M3_SERVER_TLS_CA_CERTIFICATE=cert1.pem,cert2.pem,cert3.pem ./mcs server
|
||||||
|
````
|
||||||
4
go.mod
4
go.mod
@@ -18,8 +18,8 @@ require (
|
|||||||
github.com/json-iterator/go v1.1.9
|
github.com/json-iterator/go v1.1.9
|
||||||
github.com/minio/cli v1.22.0
|
github.com/minio/cli v1.22.0
|
||||||
github.com/minio/mc v0.0.0-20200515235434-3b479cf92ed6
|
github.com/minio/mc v0.0.0-20200515235434-3b479cf92ed6
|
||||||
github.com/minio/minio v0.0.0-20200516011754-9cac385aecdb
|
github.com/minio/minio v0.0.0-20200603201854-5686a7e27319
|
||||||
github.com/minio/minio-go/v6 v6.0.56-0.20200502013257-a81c8c13cc3f
|
github.com/minio/minio-go/v6 v6.0.56
|
||||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/stretchr/testify v1.5.1
|
github.com/stretchr/testify v1.5.1
|
||||||
|
|||||||
50
go.sum
50
go.sum
@@ -15,6 +15,7 @@ github.com/Azure/go-autorest v11.7.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSW
|
|||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
@@ -47,10 +48,14 @@ github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
|
|||||||
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4=
|
github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cheggaaa/pb v1.0.28 h1:kWGpdAcSp3MxMU9CCHOwz/8V0kCHN4+9yQm2MzWuI98=
|
github.com/cheggaaa/pb v1.0.28 h1:kWGpdAcSp3MxMU9CCHOwz/8V0kCHN4+9yQm2MzWuI98=
|
||||||
@@ -60,6 +65,8 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp
|
|||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
|
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
|
||||||
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
||||||
|
github.com/colinmarc/hdfs/v2 v2.1.1 h1:x0hw/m+o3UE20Scso/KCkvYNc9Di39TBlCfGMkJ1/a0=
|
||||||
|
github.com/colinmarc/hdfs/v2 v2.1.1/go.mod h1:M3x+k8UKKmxtFu++uAZ0OtDU8jR3jnaZIAc6yK4Ue0c=
|
||||||
github.com/coredns/coredns v1.4.0 h1:RubBkYmkByUqZWWkjRHvNLnUHgkRVqAWgSMmRFvpE1A=
|
github.com/coredns/coredns v1.4.0 h1:RubBkYmkByUqZWWkjRHvNLnUHgkRVqAWgSMmRFvpE1A=
|
||||||
github.com/coredns/coredns v1.4.0/go.mod h1:zASH/MVDgR6XZTbxvOnsZfffS+31vg6Ackf/wo1+AM0=
|
github.com/coredns/coredns v1.4.0/go.mod h1:zASH/MVDgR6XZTbxvOnsZfffS+31vg6Ackf/wo1+AM0=
|
||||||
github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=
|
github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=
|
||||||
@@ -74,11 +81,13 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9
|
|||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/djherbis/atime v1.0.0 h1:ySLvBAM0EvOGaX7TI4dAM5lWj+RdJUCKtGSEHN8SGBg=
|
github.com/djherbis/atime v1.0.0 h1:ySLvBAM0EvOGaX7TI4dAM5lWj+RdJUCKtGSEHN8SGBg=
|
||||||
github.com/djherbis/atime v1.0.0/go.mod h1:5W+KBIuTwVGcqjIfaTwt+KSYX1o6uep8dtevevQP/f8=
|
github.com/djherbis/atime v1.0.0/go.mod h1:5W+KBIuTwVGcqjIfaTwt+KSYX1o6uep8dtevevQP/f8=
|
||||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
@@ -116,6 +125,7 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
|||||||
github.com/go-ldap/ldap v3.0.2+incompatible h1:kD5HQcAzlQ7yrhfn+h+MSABeAy/jAJhvIJ/QDllP44g=
|
github.com/go-ldap/ldap v3.0.2+incompatible h1:kD5HQcAzlQ7yrhfn+h+MSABeAy/jAJhvIJ/QDllP44g=
|
||||||
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||||
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
||||||
@@ -232,6 +242,8 @@ github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNu
|
|||||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||||
@@ -291,6 +303,7 @@ github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+0
|
|||||||
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||||
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
||||||
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
||||||
|
github.com/hashicorp/go-uuid v0.0.0-20180228145832-27454136f036/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
@@ -312,6 +325,7 @@ github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKe
|
|||||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8=
|
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8=
|
||||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
|
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/jcmturner/gofork v0.0.0-20180107083740-2aebee971930/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||||
github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03 h1:FUwcHNlEqkqLjLBdCp5PRlCFijNjvcYANOZXzCfXwCM=
|
github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03 h1:FUwcHNlEqkqLjLBdCp5PRlCFijNjvcYANOZXzCfXwCM=
|
||||||
github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||||
@@ -359,6 +373,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kurin/blazer v0.5.4-0.20200327014341-8f90a40f8af7 h1:smZXPopqRVVywwzou4WYWvUbJvSAzIDFizfWElpmAqY=
|
github.com/kurin/blazer v0.5.4-0.20200327014341-8f90a40f8af7 h1:smZXPopqRVVywwzou4WYWvUbJvSAzIDFizfWElpmAqY=
|
||||||
github.com/kurin/blazer v0.5.4-0.20200327014341-8f90a40f8af7/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
|
github.com/kurin/blazer v0.5.4-0.20200327014341-8f90a40f8af7/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
|
||||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||||
@@ -407,13 +423,14 @@ github.com/minio/lsync v1.0.1/go.mod h1:tCFzfo0dlvdGl70IT4IAK/5Wtgb0/BrTmo/jE8pA
|
|||||||
github.com/minio/mc v0.0.0-20200515235434-3b479cf92ed6 h1:2SrKe2vLDLwvnYkYrJelrzyGW8t/8HCbr9yDsw+8XSI=
|
github.com/minio/mc v0.0.0-20200515235434-3b479cf92ed6 h1:2SrKe2vLDLwvnYkYrJelrzyGW8t/8HCbr9yDsw+8XSI=
|
||||||
github.com/minio/mc v0.0.0-20200515235434-3b479cf92ed6/go.mod h1:U3Jgk0bcSjn+QPUMisrS6nxCWOoQ6rYWSvLCB30apuU=
|
github.com/minio/mc v0.0.0-20200515235434-3b479cf92ed6/go.mod h1:U3Jgk0bcSjn+QPUMisrS6nxCWOoQ6rYWSvLCB30apuU=
|
||||||
github.com/minio/minio v0.0.0-20200421050159-282c9f790a03/go.mod h1:zBua5AiljGs1Irdl2XEyiJjvZVCVDIG8gjozzRBcVlw=
|
github.com/minio/minio v0.0.0-20200421050159-282c9f790a03/go.mod h1:zBua5AiljGs1Irdl2XEyiJjvZVCVDIG8gjozzRBcVlw=
|
||||||
github.com/minio/minio v0.0.0-20200516011754-9cac385aecdb h1:CQC7D3UDnUycuxhwImcVhMSLet/RbShosAnYcvMtEB8=
|
github.com/minio/minio v0.0.0-20200603201854-5686a7e27319 h1:Vh7ATrN/BDjUx9XBKg5fpqSn2LPV/9BKKdldu31+2HY=
|
||||||
github.com/minio/minio v0.0.0-20200516011754-9cac385aecdb/go.mod h1:wymaytM/HELuwdz7BGZHmQ3XKq2SxPsLeGxyOCaCLiA=
|
github.com/minio/minio v0.0.0-20200603201854-5686a7e27319/go.mod h1:hW3OqYRO05rdeeuHHTif+B7WYxtDB3/hZb7eKfHXy1Y=
|
||||||
github.com/minio/minio-go/v6 v6.0.53 h1:8jzpwiOzZ5Iz7/goFWqNZRICbyWYShbb5rARjrnSCNI=
|
github.com/minio/minio-go/v6 v6.0.53 h1:8jzpwiOzZ5Iz7/goFWqNZRICbyWYShbb5rARjrnSCNI=
|
||||||
github.com/minio/minio-go/v6 v6.0.53/go.mod h1:DIvC/IApeHX8q1BAMVCXSXwpmrmM+I+iBvhvztQorfI=
|
github.com/minio/minio-go/v6 v6.0.53/go.mod h1:DIvC/IApeHX8q1BAMVCXSXwpmrmM+I+iBvhvztQorfI=
|
||||||
github.com/minio/minio-go/v6 v6.0.55-0.20200425081427-89eebdef2af0/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI=
|
|
||||||
github.com/minio/minio-go/v6 v6.0.56-0.20200502013257-a81c8c13cc3f h1:ifHrI8+exqLi5RztIWWKS5k+Wu+W7DJisVXwNaCH2zs=
|
github.com/minio/minio-go/v6 v6.0.56-0.20200502013257-a81c8c13cc3f h1:ifHrI8+exqLi5RztIWWKS5k+Wu+W7DJisVXwNaCH2zs=
|
||||||
github.com/minio/minio-go/v6 v6.0.56-0.20200502013257-a81c8c13cc3f/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI=
|
github.com/minio/minio-go/v6 v6.0.56-0.20200502013257-a81c8c13cc3f/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI=
|
||||||
|
github.com/minio/minio-go/v6 v6.0.56 h1:H4+v6UFV1V7VkEf1HjL15W9OvTL1Gy8EbMmjQZHqEbg=
|
||||||
|
github.com/minio/minio-go/v6 v6.0.56/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI=
|
||||||
github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61 h1:pUSI/WKPdd77gcuoJkSzhJ4wdS8OMDOsOu99MtpXEQA=
|
github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61 h1:pUSI/WKPdd77gcuoJkSzhJ4wdS8OMDOsOu99MtpXEQA=
|
||||||
github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61/go.mod h1:4trzEJ7N1nBTd5Tt7OCZT5SEin+WiAXpdJ/WgPkESA8=
|
github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61/go.mod h1:4trzEJ7N1nBTd5Tt7OCZT5SEin+WiAXpdJ/WgPkESA8=
|
||||||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
||||||
@@ -470,9 +487,12 @@ github.com/nats-io/stan.go v0.4.5 h1:lPZ9y1jVGiXcTaUc1SnEIWPYfh0avuEiHBePNJYgpPk
|
|||||||
github.com/nats-io/stan.go v0.4.5/go.mod h1:Ji7mK6gRZJSH1nc3ZJH6vi7zn/QnZhpR9Arm4iuzsUQ=
|
github.com/nats-io/stan.go v0.4.5/go.mod h1:Ji7mK6gRZJSH1nc3ZJH6vi7zn/QnZhpR9Arm4iuzsUQ=
|
||||||
github.com/ncw/directio v1.0.5 h1:JSUBhdjEvVaJvOoyPAbcW0fnd0tvRXD76wEfZ1KcQz4=
|
github.com/ncw/directio v1.0.5 h1:JSUBhdjEvVaJvOoyPAbcW0fnd0tvRXD76wEfZ1KcQz4=
|
||||||
github.com/ncw/directio v1.0.5/go.mod h1:rX/pKEYkOXBGOggmcyJeJGloCkleSvphPx2eV3t6ROk=
|
github.com/ncw/directio v1.0.5/go.mod h1:rX/pKEYkOXBGOggmcyJeJGloCkleSvphPx2eV3t6ROk=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/nsqio/go-nsq v1.0.7 h1:O0pIZJYTf+x7cZBA0UMY8WxFG79lYTURmWzAAh48ljY=
|
github.com/nsqio/go-nsq v1.0.7 h1:O0pIZJYTf+x7cZBA0UMY8WxFG79lYTURmWzAAh48ljY=
|
||||||
github.com/nsqio/go-nsq v1.0.7/go.mod h1:XP5zaUs3pqf+Q71EqUJs3HYfBIqfK6G83WQMdNN+Ito=
|
github.com/nsqio/go-nsq v1.0.7/go.mod h1:XP5zaUs3pqf+Q71EqUJs3HYfBIqfK6G83WQMdNN+Ito=
|
||||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||||
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
@@ -503,17 +523,25 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
|
|||||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA=
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA=
|
||||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
|
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
|
||||||
|
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
|
github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
|
||||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
|
||||||
|
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20190704165056-9c2d0518ed81 h1:zQTtDd7fQiF9e80lbl+ShnD9/5NSq5r1EhcS8955ECg=
|
github.com/rcrowley/go-metrics v0.0.0-20190704165056-9c2d0518ed81 h1:zQTtDd7fQiF9e80lbl+ShnD9/5NSq5r1EhcS8955ECg=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20190704165056-9c2d0518ed81/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20190704165056-9c2d0518ed81/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
@@ -548,8 +576,11 @@ github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3/go.mod h1
|
|||||||
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
|
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
|
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
@@ -627,6 +658,7 @@ go.uber.org/zap v1.11.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|||||||
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
||||||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
||||||
|
golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
@@ -739,8 +771,9 @@ golang.org/x/tools v0.0.0-20190914235951-31e00f45c22e/go.mod h1:b+2E5dAYhXwXZwtn
|
|||||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32 h1:Xvf3ZQTm5bjXPxhI7g+dwqsCqadK1rcNtwtszuatetk=
|
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770 h1:M9Fif0OxNji8w+HvmhVQ8KJtiZOsjU9RgslJGhn95XE=
|
||||||
|
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
@@ -770,6 +803,8 @@ gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUy
|
|||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
|
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
@@ -778,6 +813,7 @@ gopkg.in/h2non/filetype.v1 v1.0.5/go.mod h1:M0yem4rwSX5lLVrkEuRRp2/NinFMD5vgJ4Dl
|
|||||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.48.0 h1:URjZc+8ugRY5mL5uUeQH/a63JcHwdX9xZaWvmNWD7z8=
|
gopkg.in/ini.v1 v1.48.0 h1:URjZc+8ugRY5mL5uUeQH/a63JcHwdX9xZaWvmNWD7z8=
|
||||||
gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
||||||
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw=
|
gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw=
|
||||||
@@ -788,6 +824,8 @@ gopkg.in/jcmturner/goidentity.v3 v3.0.0 h1:1duIyWiTaYvVx3YX2CYtpJbUFd7/UuPYCfgXt
|
|||||||
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
|
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
|
||||||
gopkg.in/jcmturner/gokrb5.v7 v7.2.3 h1:hHMV/yKPwMnJhPuPx7pH2Uw/3Qyf+thJYlisUc44010=
|
gopkg.in/jcmturner/gokrb5.v7 v7.2.3 h1:hHMV/yKPwMnJhPuPx7pH2Uw/3Qyf+thJYlisUc44010=
|
||||||
gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=
|
gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=
|
||||||
|
gopkg.in/jcmturner/gokrb5.v7 v7.3.0 h1:0709Jtq/6QXEuWRfAm260XqlpcwL1vxtO1tUE2qK8Z4=
|
||||||
|
gopkg.in/jcmturner/gokrb5.v7 v7.3.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=
|
||||||
gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU=
|
gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU=
|
||||||
gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
|
gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
|
||||||
gopkg.in/ldap.v3 v3.0.3 h1:YKRHW/2sIl05JsCtx/5ZuUueFuJyoj/6+DGXe3wp6ro=
|
gopkg.in/ldap.v3 v3.0.3 h1:YKRHW/2sIl05JsCtx/5ZuUueFuJyoj/6+DGXe3wp6ro=
|
||||||
@@ -809,4 +847,6 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import (
|
|||||||
type LoginDetails struct {
|
type LoginDetails struct {
|
||||||
|
|
||||||
// login strategy
|
// login strategy
|
||||||
// Enum: [form redirect]
|
// Enum: [form redirect service-account]
|
||||||
LoginStrategy string `json:"loginStrategy,omitempty"`
|
LoginStrategy string `json:"loginStrategy,omitempty"`
|
||||||
|
|
||||||
// redirect
|
// redirect
|
||||||
@@ -62,7 +62,7 @@ var loginDetailsTypeLoginStrategyPropEnum []interface{}
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var res []string
|
var res []string
|
||||||
if err := json.Unmarshal([]byte(`["form","redirect"]`), &res); err != nil {
|
if err := json.Unmarshal([]byte(`["form","redirect","service-account"]`), &res); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
for _, v := range res {
|
for _, v := range res {
|
||||||
@@ -77,6 +77,9 @@ const (
|
|||||||
|
|
||||||
// LoginDetailsLoginStrategyRedirect captures enum value "redirect"
|
// LoginDetailsLoginStrategyRedirect captures enum value "redirect"
|
||||||
LoginDetailsLoginStrategyRedirect string = "redirect"
|
LoginDetailsLoginStrategyRedirect string = "redirect"
|
||||||
|
|
||||||
|
// LoginDetailsLoginStrategyServiceAccount captures enum value "service-account"
|
||||||
|
LoginDetailsLoginStrategyServiceAccount string = "service-account"
|
||||||
)
|
)
|
||||||
|
|
||||||
// prop value enum
|
// prop value enum
|
||||||
|
|||||||
81
models/login_mkube_request.go
Normal file
81
models/login_mkube_request.go
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 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 models
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-openapi/errors"
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
"github.com/go-openapi/validate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoginMkubeRequest login mkube request
|
||||||
|
//
|
||||||
|
// swagger:model loginMkubeRequest
|
||||||
|
type LoginMkubeRequest struct {
|
||||||
|
|
||||||
|
// jwt
|
||||||
|
// Required: true
|
||||||
|
Jwt *string `json:"jwt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates this login mkube request
|
||||||
|
func (m *LoginMkubeRequest) Validate(formats strfmt.Registry) error {
|
||||||
|
var res []error
|
||||||
|
|
||||||
|
if err := m.validateJwt(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
return errors.CompositeValidationError(res...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LoginMkubeRequest) validateJwt(formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if err := validate.Required("jwt", "body", m.Jwt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary interface implementation
|
||||||
|
func (m *LoginMkubeRequest) MarshalBinary() ([]byte, error) {
|
||||||
|
if m == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return swag.WriteJSON(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary interface implementation
|
||||||
|
func (m *LoginMkubeRequest) UnmarshalBinary(b []byte) error {
|
||||||
|
var res LoginMkubeRequest
|
||||||
|
if err := swag.ReadJSON(b, &res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*m = res
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -22,8 +22,8 @@ import (
|
|||||||
"github.com/minio/minio/pkg/env"
|
"github.com/minio/minio/pkg/env"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetOperatorOnly gets mcs operator mode status set on env variable
|
// GetOperatorOnly gets MCS mkube admin mode status set on env variable
|
||||||
//or default one
|
// or default one
|
||||||
func GetOperatorOnly() string {
|
func GetOperatorOnly() bool {
|
||||||
return strings.ToLower(env.Get(McsOperatorOnly, "off"))
|
return strings.ToLower(env.Get(McsmKubeAdminOnly, "off")) == "on"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,5 +17,5 @@
|
|||||||
package acl
|
package acl
|
||||||
|
|
||||||
const (
|
const (
|
||||||
McsOperatorOnly = "MCS_OPERATOR_ONLY"
|
McsmKubeAdminOnly = "MCS_MKUBE_ADMIN_ONLY"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ func actionsStringToActionSet(actions []string) iampolicy.ActionSet {
|
|||||||
func GetAuthorizedEndpoints(actions []string) []string {
|
func GetAuthorizedEndpoints(actions []string) []string {
|
||||||
rangeTake := endpointRules
|
rangeTake := endpointRules
|
||||||
|
|
||||||
if operatorOnly == "on" {
|
if operatorOnly {
|
||||||
rangeTake = operatorRules
|
rangeTake = operatorRules
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOperatorOnlyEndpoints(t *testing.T) {
|
func TestOperatorOnlyEndpoints(t *testing.T) {
|
||||||
operatorOnly = "on"
|
operatorOnly = true
|
||||||
|
|
||||||
tests := []endpoint{
|
tests := []endpoint{
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
jwtgo "github.com/dgrijalva/jwt-go"
|
jwtgo "github.com/dgrijalva/jwt-go"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
xjwt "github.com/minio/mcs/pkg/auth/jwt"
|
xjwt "github.com/minio/mcs/pkg/auth/jwt"
|
||||||
"github.com/minio/minio-go/v6/pkg/credentials"
|
"github.com/minio/minio-go/v6/pkg/credentials"
|
||||||
"github.com/minio/minio/cmd"
|
"github.com/minio/minio/cmd"
|
||||||
@@ -182,3 +184,42 @@ func decrypt(data []byte) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
return plaintext, nil
|
return plaintext, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTokenFromRequest returns a token from a http Request
|
||||||
|
// either defined on a cookie `token` or on Authorization header.
|
||||||
|
//
|
||||||
|
// Authorization Header needs to be like "Authorization Bearer <jwt_token>"
|
||||||
|
func GetTokenFromRequest(r *http.Request) (*string, error) {
|
||||||
|
// Get Auth token
|
||||||
|
var reqToken string
|
||||||
|
|
||||||
|
// Token might come either as a Cookie or as a Header
|
||||||
|
// if not set in cookie, check if it is set on Header.
|
||||||
|
tokenCookie, err := r.Cookie("token")
|
||||||
|
if err != nil {
|
||||||
|
headerToken := r.Header.Get("Authorization")
|
||||||
|
// reqToken should come as "Bearer <token>"
|
||||||
|
splitHeaderToken := strings.Split(headerToken, "Bearer")
|
||||||
|
if len(splitHeaderToken) <= 1 {
|
||||||
|
return nil, errNoAuthToken
|
||||||
|
}
|
||||||
|
reqToken = strings.TrimSpace(splitHeaderToken[1])
|
||||||
|
} else {
|
||||||
|
reqToken = strings.TrimSpace(tokenCookie.Value)
|
||||||
|
}
|
||||||
|
return swag.String(reqToken), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetClaimsFromTokenInRequest(req *http.Request) (*DecryptedClaims, error) {
|
||||||
|
sessionID, err := GetTokenFromRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Perform decryption of the JWT, if MCS is able to decrypt the JWT that means a valid session
|
||||||
|
// was used in the first place to get it
|
||||||
|
claims, err := JWTAuthenticate(*sessionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
|||||||
77
pkg/auth/mkube.go
Normal file
77
pkg/auth/mkube.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/minio/mcs/pkg/auth/mkube"
|
||||||
|
"github.com/minio/minio-go/v6/pkg/credentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mkubeCredentialsProvider is an struct to hold the JWT (service account token)
|
||||||
|
type mkubeCredentialsProvider struct {
|
||||||
|
serviceAccountJWT string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementing the interfaces of the minio Provider, we use this to leverage on the existing mcs Authentication flow
|
||||||
|
func (s mkubeCredentialsProvider) Retrieve() (credentials.Value, error) {
|
||||||
|
return credentials.Value{
|
||||||
|
AccessKeyID: "",
|
||||||
|
SecretAccessKey: "",
|
||||||
|
SessionToken: s.serviceAccountJWT,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired dummy function, must be implemented in order to work with the minio provider authentication
|
||||||
|
func (s mkubeCredentialsProvider) IsExpired() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// isServiceAccountTokenValid will make an authenticated request (using bearer token) against Mkube hostname, if the
|
||||||
|
// request success means the provided jwt its a valid service account token and the MCS user can use it for future requests
|
||||||
|
// until it fails
|
||||||
|
func isServiceAccountTokenValid(client *http.Client, jwt string) bool {
|
||||||
|
url := fmt.Sprintf("%s/api/v1/tenants", mkube.GetMkubeEndpoint())
|
||||||
|
m3Req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
token := fmt.Sprintf("Bearer %s", jwt)
|
||||||
|
m3Req.Header.Add("Authorization", token)
|
||||||
|
resp, err := client.Do(m3Req)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMcsCredentialsFromMkube will validate the provided JWT (service account token) and return it in the form of credentials.Credentials
|
||||||
|
func GetMcsCredentialsFromMkube(jwt string) (*credentials.Credentials, error) {
|
||||||
|
if isServiceAccountTokenValid(mkube.HTTPClient, jwt) {
|
||||||
|
return credentials.New(mkubeCredentialsProvider{serviceAccountJWT: jwt}), nil
|
||||||
|
}
|
||||||
|
return nil, errInvalidCredentials
|
||||||
|
}
|
||||||
117
pkg/auth/mkube/config.go
Normal file
117
pkg/auth/mkube/config.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 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 mkube
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
certDontExists = "File certificate doesn't exists: %s"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getMkubeEndpoint returns the hostname of mkube
|
||||||
|
func GetMkubeEndpoint() string {
|
||||||
|
return env.Get(McsMkubeHost, "http://m3:8787")
|
||||||
|
}
|
||||||
|
|
||||||
|
// getMkubeEndpointIsSecure returns true or false depending on the protocol in Mkube URL
|
||||||
|
func getMkubeEndpointIsSecure() bool {
|
||||||
|
server := GetMkubeEndpoint()
|
||||||
|
if strings.Contains(server, "://") {
|
||||||
|
parts := strings.Split(server, "://")
|
||||||
|
if len(parts) > 1 {
|
||||||
|
if parts[0] == "https" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If MCS_M3_SERVER_TLS_CA_CERTIFICATE is true mcs will load a list of certificates into the
|
||||||
|
// http.client rootCAs store, this is useful for testing or when working with self-signed certificates
|
||||||
|
func getMkubeServerTLSRootCAs() []string {
|
||||||
|
caCertFileNames := strings.TrimSpace(env.Get(McsMkubeTLSCACertificate, ""))
|
||||||
|
if caCertFileNames == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
return strings.Split(caCertFileNames, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileExists verifies if a file exist on the desired location and its not a folder
|
||||||
|
func FileExists(filename string) bool {
|
||||||
|
info, err := os.Stat(filename)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return !info.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMkubeHTTPClient returns an http.Client with custom configurations used by MCS to talk to Mkube
|
||||||
|
// custom configurations include the use of CA certificates
|
||||||
|
func getMkubeHTTPClient() *http.Client {
|
||||||
|
httpTransport := &http.Transport{}
|
||||||
|
// If Mkube server is running with TLS enabled and it's using a self-signed certificate
|
||||||
|
// or a certificate issued by a custom certificate authority we prepare a new custom *http.Transport
|
||||||
|
if getMkubeEndpointIsSecure() {
|
||||||
|
caCertFileNames := getMkubeServerTLSRootCAs()
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
// Can't use SSLv3 because of POODLE and BEAST
|
||||||
|
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
|
||||||
|
// Can't use TLSv1.1 because of RC4 cipher usage
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
}
|
||||||
|
// If CAs certificates are configured we save them to the http.Client RootCAs store
|
||||||
|
if len(caCertFileNames) > 0 {
|
||||||
|
certs := x509.NewCertPool()
|
||||||
|
for _, caCert := range caCertFileNames {
|
||||||
|
// Validate certificate exists
|
||||||
|
if FileExists(caCert) {
|
||||||
|
pemData, err := ioutil.ReadFile(caCert)
|
||||||
|
if err != nil {
|
||||||
|
// if there was an error reading pem file stop mcs
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
certs.AppendCertsFromPEM(pemData)
|
||||||
|
} else {
|
||||||
|
// if provided cert filename doesn't exists stop mcs
|
||||||
|
panic(fmt.Sprintf(certDontExists, caCert))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tlsConfig.RootCAs = certs
|
||||||
|
}
|
||||||
|
httpTransport.TLSClientConfig = tlsConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return http client with default configuration
|
||||||
|
return &http.Client{
|
||||||
|
Transport: httpTransport,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPClient it's a public variable that contains the HTTP configuration to be used by MCS to talk to Mkube
|
||||||
|
// This function will run only once
|
||||||
|
var HTTPClient = getMkubeHTTPClient()
|
||||||
22
pkg/auth/mkube/const.go
Normal file
22
pkg/auth/mkube/const.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 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 mkube
|
||||||
|
|
||||||
|
const (
|
||||||
|
McsMkubeHost = "MCS_M3_HOSTNAME"
|
||||||
|
McsMkubeTLSCACertificate = "MCS_M3_SERVER_TLS_CA_CERTIFICATE"
|
||||||
|
)
|
||||||
77
pkg/auth/mkube_test.go
Normal file
77
pkg/auth/mkube_test.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RoundTripFunc .
|
||||||
|
type RoundTripFunc func(req *http.Request) (*http.Response, error)
|
||||||
|
|
||||||
|
// RoundTrip .
|
||||||
|
func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
return f(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewTestClient returns *http.Client with Transport replaced to avoid making real calls
|
||||||
|
func NewTestClient(fn RoundTripFunc) *http.Client {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: fn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_isServiceAccountTokenValid(t *testing.T) {
|
||||||
|
|
||||||
|
successResponse := NewTestClient(func(req *http.Request) (*http.Response, error) {
|
||||||
|
return &http.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Body: ioutil.NopCloser(bytes.NewBufferString(`OK`)),
|
||||||
|
Header: make(http.Header),
|
||||||
|
}, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
failResponse := NewTestClient(func(req *http.Request) (*http.Response, error) {
|
||||||
|
return &http.Response{
|
||||||
|
StatusCode: 500,
|
||||||
|
Body: ioutil.NopCloser(bytes.NewBufferString(`NOTOK`)),
|
||||||
|
Header: make(http.Header),
|
||||||
|
}, errors.New("something wrong")
|
||||||
|
})
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
client *http.Client
|
||||||
|
jwt string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Success authentication - correct jwt (service account token)",
|
||||||
|
args: args{
|
||||||
|
client: successResponse,
|
||||||
|
jwt: "GOODTOKEN",
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fail authentication - incorrect jwt (service account token)",
|
||||||
|
args: args{
|
||||||
|
client: failResponse,
|
||||||
|
jwt: "BADTOKEN",
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := isServiceAccountTokenValid(tt.args.client, tt.args.jwt); got != tt.want {
|
||||||
|
t.Errorf("isServiceAccountTokenValid() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
// This file is part of MinIO Console Server
|
|
||||||
// Copyright (c) 2020 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 ws contains websocket utils for mcs project
|
|
||||||
package ws
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/go-openapi/errors"
|
|
||||||
"github.com/go-openapi/swag"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetTokenFromRequest returns a token from a http Request
|
|
||||||
// either defined on a cookie `token` or on Authorization header.
|
|
||||||
//
|
|
||||||
// Authorization Header needs to be like "Authorization Bearer <jwt_token>"
|
|
||||||
func GetTokenFromRequest(r *http.Request) (*string, error) {
|
|
||||||
// Get Auth token
|
|
||||||
var reqToken string
|
|
||||||
|
|
||||||
// Token might come either as a Cookie or as a Header
|
|
||||||
// if not set in cookie, check if it is set on Header.
|
|
||||||
tokenCookie, err := r.Cookie("token")
|
|
||||||
if err != nil {
|
|
||||||
headerToken := r.Header.Get("Authorization")
|
|
||||||
// reqToken should come as "Bearer <token>"
|
|
||||||
splitHeaderToken := strings.Split(headerToken, "Bearer")
|
|
||||||
if len(splitHeaderToken) <= 1 {
|
|
||||||
return nil, errors.New(http.StatusBadRequest, "Authentication not valid")
|
|
||||||
}
|
|
||||||
reqToken = strings.TrimSpace(splitHeaderToken[1])
|
|
||||||
} else {
|
|
||||||
reqToken = strings.TrimSpace(tokenCookie.Value)
|
|
||||||
}
|
|
||||||
return swag.String(reqToken), nil
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import request from "superagent";
|
import request from "superagent";
|
||||||
import storage from "local-storage-fallback";
|
import storage from "local-storage-fallback";
|
||||||
import { connect, ConnectedProps } from "react-redux";
|
import { connect, ConnectedProps } from "react-redux";
|
||||||
@@ -26,9 +26,8 @@ import { CircularProgress, Paper } from "@material-ui/core";
|
|||||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||||
import { SystemState } from "../../types";
|
import { SystemState } from "../../types";
|
||||||
import { userLoggedIn } from "../../actions";
|
import { userLoggedIn } from "../../actions";
|
||||||
import history from "../../history";
|
|
||||||
import api from "../../common/api";
|
import api from "../../common/api";
|
||||||
import { ILoginDetails } from "./types";
|
import { ILoginDetails, loginStrategyType } from "./types";
|
||||||
import { setCookie } from "../../common/utils";
|
import { setCookie } from "../../common/utils";
|
||||||
|
|
||||||
const styles = (theme: Theme) =>
|
const styles = (theme: Theme) =>
|
||||||
@@ -101,57 +100,57 @@ interface ILoginProps {
|
|||||||
classes: any;
|
classes: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ILoginState {
|
interface LoginStrategyRoutes {
|
||||||
accessKey: string;
|
[key: string]: string;
|
||||||
secretKey: string;
|
|
||||||
error: string;
|
|
||||||
loading: boolean;
|
|
||||||
loginStrategy: ILoginDetails;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Login extends React.Component<ILoginProps, ILoginState> {
|
interface LoginStrategyPayload {
|
||||||
state: ILoginState = {
|
[key: string]: any;
|
||||||
accessKey: "",
|
}
|
||||||
secretKey: "",
|
|
||||||
error: "",
|
|
||||||
loading: false,
|
|
||||||
loginStrategy: {
|
|
||||||
loginStrategy: "",
|
|
||||||
redirect: "",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchConfiguration() {
|
const Login = ({ classes, userLoggedIn }: ILoginProps) => {
|
||||||
this.setState({ loading: true }, () => {
|
const [accessKey, setAccessKey] = useState<string>("");
|
||||||
api
|
const [jwt, setJwt] = useState<string>("");
|
||||||
.invoke("GET", "/api/v1/login")
|
const [secretKey, setSecretKey] = useState<string>("");
|
||||||
.then((loginDetails: ILoginDetails) => {
|
const [error, setError] = useState<string>("");
|
||||||
this.setState({
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
loading: false,
|
const [loginStrategy, setLoginStrategy] = useState<ILoginDetails>({
|
||||||
});
|
loginStrategy: loginStrategyType.unknown,
|
||||||
this.setState({
|
redirect: "",
|
||||||
loading: false,
|
});
|
||||||
loginStrategy: loginDetails,
|
|
||||||
error: "",
|
const loginStrategyEndpoints: LoginStrategyRoutes = {
|
||||||
});
|
"form": "/api/v1/login",
|
||||||
})
|
"service-account": "/api/v1/login/mkube",
|
||||||
.catch((err: any) => {
|
}
|
||||||
this.setState({ loading: false, error: err });
|
const loginStrategyPayload: LoginStrategyPayload = {
|
||||||
});
|
"form": { accessKey, secretKey },
|
||||||
});
|
"service-account": { jwt },
|
||||||
}
|
}
|
||||||
|
|
||||||
formSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
const fetchConfiguration = () => {
|
||||||
e.preventDefault();
|
setLoading(true);
|
||||||
const url = "/api/v1/login";
|
|
||||||
const { accessKey, secretKey } = this.state;
|
|
||||||
|
|
||||||
|
api
|
||||||
|
.invoke("GET", "/api/v1/login")
|
||||||
|
.then((loginDetails: ILoginDetails) => {
|
||||||
|
setLoading(false);
|
||||||
|
setLoginStrategy(loginDetails);
|
||||||
|
setError("");
|
||||||
|
})
|
||||||
|
.catch((err: any) => {
|
||||||
|
setLoading(false);
|
||||||
|
setError(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const formSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
request
|
request
|
||||||
.post(url)
|
.post(loginStrategyEndpoints[loginStrategy.loginStrategy] || "/api/v1/login")
|
||||||
.send({ accessKey, secretKey })
|
.send(loginStrategyPayload[loginStrategy.loginStrategy])
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
const bodyResponse = res.body;
|
const bodyResponse = res.body;
|
||||||
|
|
||||||
if (bodyResponse.sessionId) {
|
if (bodyResponse.sessionId) {
|
||||||
// store the jwt token
|
// store the jwt token
|
||||||
setCookie("token", bodyResponse.sessionId);
|
setCookie("token", bodyResponse.sessionId);
|
||||||
@@ -164,134 +163,173 @@ class Login extends React.Component<ILoginProps, ILoginState> {
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// We set the state in redux
|
// We set the state in redux
|
||||||
this.props.userLoggedIn(true);
|
userLoggedIn(true);
|
||||||
// There is a browser cache issue if we change the policy associated to an account and then logout and history.push("/") after login
|
// There is a browser cache issue if we change the policy associated to an account and then logout and history.push("/") after login
|
||||||
// therefore after login we need to use window.location redirect
|
// therefore after login we need to use window.location redirect
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
this.setState({ error: `${err}` });
|
setError(err.message);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount(): void {
|
useEffect(() => {
|
||||||
this.fetchConfiguration();
|
fetchConfiguration();
|
||||||
}
|
}, []);
|
||||||
|
|
||||||
render() {
|
let loginComponent = null;
|
||||||
const { error, accessKey, secretKey, loginStrategy } = this.state;
|
|
||||||
const { classes } = this.props;
|
|
||||||
|
|
||||||
let loginComponent = null;
|
switch (loginStrategy.loginStrategy) {
|
||||||
|
case loginStrategyType.form: {
|
||||||
switch (loginStrategy.loginStrategy) {
|
loginComponent = (
|
||||||
case "form": {
|
<React.Fragment>
|
||||||
loginComponent = (
|
<Typography component="h1" variant="h6">
|
||||||
<React.Fragment>
|
Login
|
||||||
<Typography component="h1" variant="h6">
|
</Typography>
|
||||||
Login
|
<form className={classes.form} noValidate onSubmit={formSubmit}>
|
||||||
</Typography>
|
<Grid container spacing={2}>
|
||||||
<form
|
{error !== "" && (
|
||||||
className={classes.form}
|
|
||||||
noValidate
|
|
||||||
onSubmit={this.formSubmit}
|
|
||||||
>
|
|
||||||
<Grid container spacing={2}>
|
|
||||||
{error !== "" && (
|
|
||||||
<Grid item xs={12}>
|
|
||||||
<Typography
|
|
||||||
component="p"
|
|
||||||
variant="body1"
|
|
||||||
className={classes.errorBlock}
|
|
||||||
>
|
|
||||||
{error}
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
)}
|
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<TextField
|
<Typography
|
||||||
required
|
component="p"
|
||||||
fullWidth
|
variant="body1"
|
||||||
id="accessKey"
|
className={classes.errorBlock}
|
||||||
value={accessKey}
|
>
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
{error}
|
||||||
this.setState({ accessKey: e.target.value })
|
</Typography>
|
||||||
}
|
|
||||||
label="Access Key"
|
|
||||||
name="accessKey"
|
|
||||||
autoComplete="username"
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12}>
|
|
||||||
<TextField
|
|
||||||
required
|
|
||||||
fullWidth
|
|
||||||
value={secretKey}
|
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
||||||
this.setState({ secretKey: e.target.value })
|
|
||||||
}
|
|
||||||
name="secretKey"
|
|
||||||
label="Secret Key"
|
|
||||||
type="password"
|
|
||||||
id="secretKey"
|
|
||||||
autoComplete="current-password"
|
|
||||||
/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
)}
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
fullWidth
|
||||||
|
id="accessKey"
|
||||||
|
value={accessKey}
|
||||||
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setAccessKey(e.target.value)
|
||||||
|
}
|
||||||
|
label="Access Key"
|
||||||
|
name="accessKey"
|
||||||
|
autoComplete="username"
|
||||||
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Button
|
<Grid item xs={12}>
|
||||||
type="submit"
|
<TextField
|
||||||
fullWidth
|
required
|
||||||
variant="contained"
|
fullWidth
|
||||||
color="primary"
|
value={secretKey}
|
||||||
className={classes.submit}
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
>
|
setSecretKey(e.target.value)
|
||||||
Login
|
}
|
||||||
</Button>
|
name="secretKey"
|
||||||
</form>
|
label="Secret Key"
|
||||||
</React.Fragment>
|
type="password"
|
||||||
);
|
id="secretKey"
|
||||||
break;
|
autoComplete="current-password"
|
||||||
}
|
/>
|
||||||
case "redirect": {
|
</Grid>
|
||||||
loginComponent = (
|
</Grid>
|
||||||
<React.Fragment>
|
|
||||||
<Typography component="h1" variant="h6">
|
|
||||||
Login
|
|
||||||
</Typography>
|
|
||||||
<Button
|
<Button
|
||||||
component={"a"}
|
|
||||||
href={loginStrategy.redirect}
|
|
||||||
type="submit"
|
type="submit"
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
className={classes.submit}
|
className={classes.submit}
|
||||||
>
|
>
|
||||||
Welcome
|
Login
|
||||||
</Button>
|
</Button>
|
||||||
</React.Fragment>
|
</form>
|
||||||
);
|
</React.Fragment>
|
||||||
break;
|
);
|
||||||
}
|
break;
|
||||||
default:
|
|
||||||
loginComponent = (
|
|
||||||
<CircularProgress className={classes.loadingLoginStrategy} />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
case loginStrategyType.redirect: {
|
||||||
return (
|
loginComponent = (
|
||||||
<Paper className={classes.paper}>
|
<React.Fragment>
|
||||||
<Grid container className={classes.mainContainer}>
|
<Typography component="h1" variant="h6">
|
||||||
<Grid item xs={7} className={classes.theOcean}>
|
Login
|
||||||
<div className={classes.oceanBg} />
|
</Typography>
|
||||||
</Grid>
|
<Button
|
||||||
<Grid item xs={5} className={classes.theLogin}>
|
component={"a"}
|
||||||
{loginComponent}
|
href={loginStrategy.redirect}
|
||||||
</Grid>
|
type="submit"
|
||||||
</Grid>
|
fullWidth
|
||||||
</Paper>
|
variant="contained"
|
||||||
);
|
color="primary"
|
||||||
|
className={classes.submit}
|
||||||
|
>
|
||||||
|
Welcome
|
||||||
|
</Button>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case loginStrategyType.serviceAccount: {
|
||||||
|
loginComponent = (
|
||||||
|
<React.Fragment>
|
||||||
|
<Typography component="h1" variant="h6">
|
||||||
|
Login
|
||||||
|
</Typography>
|
||||||
|
<form className={classes.form} noValidate onSubmit={formSubmit}>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{error !== "" && (
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Typography
|
||||||
|
component="p"
|
||||||
|
variant="body1"
|
||||||
|
className={classes.errorBlock}
|
||||||
|
>
|
||||||
|
{error}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
fullWidth
|
||||||
|
id="jwt"
|
||||||
|
value={jwt}
|
||||||
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setJwt(e.target.value)
|
||||||
|
}
|
||||||
|
label="JWT"
|
||||||
|
name="jwt"
|
||||||
|
autoComplete="Service Account JWT Token"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
fullWidth
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
className={classes.submit}
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
loginComponent = (
|
||||||
|
<CircularProgress className={classes.loadingLoginStrategy} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return (
|
||||||
|
<Paper className={classes.paper}>
|
||||||
|
<Grid container className={classes.mainContainer}>
|
||||||
|
<Grid item xs={7} className={classes.theOcean}>
|
||||||
|
<div className={classes.oceanBg} />
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={5} className={classes.theLogin}>
|
||||||
|
{loginComponent}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default connector(withStyles(styles)(Login));
|
export default connector(withStyles(styles)(Login));
|
||||||
|
|||||||
@@ -15,6 +15,13 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export interface ILoginDetails {
|
export interface ILoginDetails {
|
||||||
loginStrategy: string;
|
loginStrategy: loginStrategyType;
|
||||||
redirect: string;
|
redirect: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum loginStrategyType {
|
||||||
|
unknown = "unknown",
|
||||||
|
form = "form",
|
||||||
|
redirect = "redirect",
|
||||||
|
serviceAccount = "service-account",
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,9 +25,11 @@ import (
|
|||||||
|
|
||||||
mc "github.com/minio/mc/cmd"
|
mc "github.com/minio/mc/cmd"
|
||||||
"github.com/minio/mc/pkg/probe"
|
"github.com/minio/mc/pkg/probe"
|
||||||
|
"github.com/minio/mcs/pkg/acl"
|
||||||
"github.com/minio/mcs/pkg/auth"
|
"github.com/minio/mcs/pkg/auth"
|
||||||
xjwt "github.com/minio/mcs/pkg/auth/jwt"
|
xjwt "github.com/minio/mcs/pkg/auth/jwt"
|
||||||
"github.com/minio/mcs/pkg/auth/ldap"
|
"github.com/minio/mcs/pkg/auth/ldap"
|
||||||
|
"github.com/minio/mcs/pkg/auth/mkube"
|
||||||
"github.com/minio/minio-go/v6"
|
"github.com/minio/minio-go/v6"
|
||||||
"github.com/minio/minio-go/v6/pkg/credentials"
|
"github.com/minio/minio-go/v6/pkg/credentials"
|
||||||
)
|
)
|
||||||
@@ -120,7 +122,7 @@ func (c mcS3Client) watch(options mc.WatchOptions) (*mc.WatchObject, *probe.Erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MCSCredentials interface with all functions to be implemented
|
// MCSCredentials interface with all functions to be implemented
|
||||||
// by mock when testing, it should include all needed minioCredentials.Credentials api calls
|
// by mock when testing, it should include all needed mcsCredentials.Credentials api calls
|
||||||
// that are used within this project.
|
// that are used within this project.
|
||||||
type MCSCredentials interface {
|
type MCSCredentials interface {
|
||||||
Get() (credentials.Value, error)
|
Get() (credentials.Value, error)
|
||||||
@@ -129,17 +131,17 @@ type MCSCredentials interface {
|
|||||||
|
|
||||||
// Interface implementation
|
// Interface implementation
|
||||||
type mcsCredentials struct {
|
type mcsCredentials struct {
|
||||||
minioCredentials *credentials.Credentials
|
mcsCredentials *credentials.Credentials
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements *Credentials.Get()
|
// implements *Credentials.Get()
|
||||||
func (c mcsCredentials) Get() (credentials.Value, error) {
|
func (c mcsCredentials) Get() (credentials.Value, error) {
|
||||||
return c.minioCredentials.Get()
|
return c.mcsCredentials.Get()
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements *Credentials.Expire()
|
// implements *Credentials.Expire()
|
||||||
func (c mcsCredentials) Expire() {
|
func (c mcsCredentials) Expire() {
|
||||||
c.minioCredentials.Expire()
|
c.mcsCredentials.Expire()
|
||||||
}
|
}
|
||||||
|
|
||||||
// mcsSTSAssumeRole it's a STSAssumeRole wrapper, in general
|
// mcsSTSAssumeRole it's a STSAssumeRole wrapper, in general
|
||||||
@@ -159,22 +161,31 @@ func (s mcsSTSAssumeRole) IsExpired() bool {
|
|||||||
|
|
||||||
// STSClient contains http.client configuration need it by STSAssumeRole
|
// STSClient contains http.client configuration need it by STSAssumeRole
|
||||||
var STSClient = PrepareSTSClient()
|
var STSClient = PrepareSTSClient()
|
||||||
|
var MinioEndpoint = getMinIOServer()
|
||||||
|
var MkubeEndpoint = mkube.GetMkubeEndpoint()
|
||||||
|
|
||||||
func newMcsCredentials(accessKey, secretKey, location string) (*credentials.Credentials, error) {
|
func newMcsCredentials(accessKey, secretKey, location string) (*credentials.Credentials, error) {
|
||||||
mcsEndpoint := getMinIOServer()
|
|
||||||
if mcsEndpoint == "" {
|
|
||||||
return nil, errors.New("endpoint cannot be empty for AssumeRoleSTS")
|
|
||||||
}
|
|
||||||
if accessKey == "" || secretKey == "" {
|
|
||||||
return nil, errors.New("creredentials access/secretkey is mandatory for AssumeRoleSTS")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Future authentication methods can be added under this switch statement
|
// Future authentication methods can be added under this switch statement
|
||||||
switch {
|
switch {
|
||||||
|
// MKUBE authentication for MCS
|
||||||
|
case acl.GetOperatorOnly():
|
||||||
|
{
|
||||||
|
if MkubeEndpoint == "" {
|
||||||
|
return nil, errors.New("endpoint cannot be empty for Mkube")
|
||||||
|
}
|
||||||
|
creds, err := auth.GetMcsCredentialsFromMkube(secretKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return creds, nil
|
||||||
|
}
|
||||||
// LDAP authentication for MCS
|
// LDAP authentication for MCS
|
||||||
case ldap.GetLDAPEnabled():
|
case ldap.GetLDAPEnabled():
|
||||||
{
|
{
|
||||||
creds, err := auth.GetMcsCredentialsFromLDAP(mcsEndpoint, accessKey, secretKey)
|
if MinioEndpoint == "" {
|
||||||
|
return nil, errors.New("endpoint cannot be empty for AssumeRoleSTS")
|
||||||
|
}
|
||||||
|
creds, err := auth.GetMcsCredentialsFromLDAP(MinioEndpoint, accessKey, secretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -183,6 +194,9 @@ func newMcsCredentials(accessKey, secretKey, location string) (*credentials.Cred
|
|||||||
// default authentication for MCS is via STS (Security Token Service) against MinIO
|
// default authentication for MCS is via STS (Security Token Service) against MinIO
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
if MinioEndpoint == "" || accessKey == "" || secretKey == "" {
|
||||||
|
return nil, errors.New("creredentials endpont, access and secretkey are mandatory for AssumeRoleSTS")
|
||||||
|
}
|
||||||
opts := credentials.STSAssumeRoleOptions{
|
opts := credentials.STSAssumeRoleOptions{
|
||||||
AccessKey: accessKey,
|
AccessKey: accessKey,
|
||||||
SecretKey: secretKey,
|
SecretKey: secretKey,
|
||||||
@@ -191,7 +205,7 @@ func newMcsCredentials(accessKey, secretKey, location string) (*credentials.Cred
|
|||||||
}
|
}
|
||||||
stsAssumeRole := &credentials.STSAssumeRole{
|
stsAssumeRole := &credentials.STSAssumeRole{
|
||||||
Client: STSClient,
|
Client: STSClient,
|
||||||
STSEndpoint: mcsEndpoint,
|
STSEndpoint: MinioEndpoint,
|
||||||
Options: opts,
|
Options: opts,
|
||||||
}
|
}
|
||||||
mcsSTSWrapper := mcsSTSAssumeRole{stsAssumeRole: stsAssumeRole}
|
mcsSTSWrapper := mcsSTSAssumeRole{stsAssumeRole: stsAssumeRole}
|
||||||
@@ -209,7 +223,7 @@ func GetClaimsFromJWT(jwt string) (*auth.DecryptedClaims, error) {
|
|||||||
return claims, nil
|
return claims, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getMcsCredentialsFromJWT returns the *minioCredentials.Credentials associated to the
|
// getMcsCredentialsFromJWT returns the *mcsCredentials.Credentials associated to the
|
||||||
// provided jwt, this is useful for running the Expire() or IsExpired() operations
|
// provided jwt, this is useful for running the Expire() or IsExpired() operations
|
||||||
func getMcsCredentialsFromJWT(jwt string) (*credentials.Credentials, error) {
|
func getMcsCredentialsFromJWT(jwt string) (*credentials.Credentials, error) {
|
||||||
claims, err := GetClaimsFromJWT(jwt)
|
claims, err := GetClaimsFromJWT(jwt)
|
||||||
@@ -220,7 +234,7 @@ func getMcsCredentialsFromJWT(jwt string) (*credentials.Credentials, error) {
|
|||||||
return creds, nil
|
return creds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// newMinioClient creates a new MinIO client based on the minioCredentials extracted
|
// newMinioClient creates a new MinIO client based on the mcsCredentials extracted
|
||||||
// from the provided jwt
|
// from the provided jwt
|
||||||
func newMinioClient(jwt string) (*minio.Client, error) {
|
func newMinioClient(jwt string) (*minio.Client, error) {
|
||||||
creds, err := getMcsCredentialsFromJWT(jwt)
|
creds, err := getMcsCredentialsFromJWT(jwt)
|
||||||
@@ -239,19 +253,18 @@ func newMinioClient(jwt string) (*minio.Client, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newS3BucketClient creates a new mc S3Client to talk to the server based on a bucket
|
// newS3BucketClient creates a new mc S3Client to talk to the server based on a bucket
|
||||||
func newS3BucketClient(jwt string, bucketName string) (*mc.S3Client, error) {
|
func newS3BucketClient(claims *auth.DecryptedClaims, bucketName string) (*mc.S3Client, error) {
|
||||||
endpoint := getMinIOServer()
|
endpoint := getMinIOServer()
|
||||||
useSSL := getMinIOEndpointIsSecure()
|
useSSL := getMinIOEndpointIsSecure()
|
||||||
|
|
||||||
claims, err := auth.JWTAuthenticate(jwt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.TrimSpace(bucketName) != "" {
|
if strings.TrimSpace(bucketName) != "" {
|
||||||
endpoint += fmt.Sprintf("/%s", bucketName)
|
endpoint += fmt.Sprintf("/%s", bucketName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if claims == nil {
|
||||||
|
return nil, fmt.Errorf("the provided credentials are invalid")
|
||||||
|
}
|
||||||
|
|
||||||
s3Config := newS3Config(endpoint, claims.AccessKeyID, claims.SecretAccessKey, claims.SessionToken, !useSSL)
|
s3Config := newS3Config(endpoint, claims.AccessKeyID, claims.SecretAccessKey, claims.SessionToken, !useSSL)
|
||||||
client, pErr := mc.S3New(s3Config)
|
client, pErr := mc.S3New(s3Config)
|
||||||
if pErr != nil {
|
if pErr != nil {
|
||||||
@@ -269,7 +282,7 @@ func newS3BucketClient(jwt string, bucketName string) (*mc.S3Client, error) {
|
|||||||
// parameters.
|
// parameters.
|
||||||
func newS3Config(endpoint, accessKey, secretKey, sessionToken string, isSecure bool) *mc.Config {
|
func newS3Config(endpoint, accessKey, secretKey, sessionToken string, isSecure bool) *mc.Config {
|
||||||
// We have a valid alias and hostConfig. We populate the
|
// We have a valid alias and hostConfig. We populate the
|
||||||
// minioCredentials from the match found in the config file.
|
// mcsCredentials from the match found in the config file.
|
||||||
s3Config := new(mc.Config)
|
s3Config := new(mc.Config)
|
||||||
|
|
||||||
s3Config.AppName = "mcs" // TODO: make this a constant
|
s3Config.AppName = "mcs" // TODO: make this a constant
|
||||||
|
|||||||
@@ -228,8 +228,3 @@ func getSecureFeaturePolicy() string {
|
|||||||
func getSecureExpectCTHeader() string {
|
func getSecureExpectCTHeader() string {
|
||||||
return env.Get(McsSecureExpectCTHeader, "")
|
return env.Get(McsSecureExpectCTHeader, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// getM3Host returns the hostname of mkube
|
|
||||||
func getM3Host() string {
|
|
||||||
return env.Get(McsM3Host, "http://m3:8787")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/minio/mcs/models"
|
"github.com/minio/mcs/models"
|
||||||
"github.com/minio/mcs/pkg"
|
"github.com/minio/mcs/pkg"
|
||||||
"github.com/minio/mcs/pkg/auth"
|
"github.com/minio/mcs/pkg/auth"
|
||||||
|
"github.com/minio/mcs/pkg/auth/mkube"
|
||||||
|
|
||||||
assetFS "github.com/elazarl/go-bindata-assetfs"
|
assetFS "github.com/elazarl/go-bindata-assetfs"
|
||||||
|
|
||||||
@@ -167,8 +168,7 @@ func FileServerMiddleware(next http.Handler) http.Handler {
|
|||||||
case strings.HasPrefix(r.URL.Path, "/ws"):
|
case strings.HasPrefix(r.URL.Path, "/ws"):
|
||||||
serveWS(w, r)
|
serveWS(w, r)
|
||||||
case strings.HasPrefix(r.URL.Path, "/api/v1/mkube"):
|
case strings.HasPrefix(r.URL.Path, "/api/v1/mkube"):
|
||||||
client := &http.Client{}
|
serverMkube(mkube.HTTPClient, w, r)
|
||||||
serverMkube(client, w, r)
|
|
||||||
case strings.HasPrefix(r.URL.Path, "/api"):
|
case strings.HasPrefix(r.URL.Path, "/api"):
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -49,5 +49,4 @@ const (
|
|||||||
McsSecureReferrerPolicy = "MCS_SECURE_REFERRER_POLICY"
|
McsSecureReferrerPolicy = "MCS_SECURE_REFERRER_POLICY"
|
||||||
McsSecureFeaturePolicy = "MCS_SECURE_FEATURE_POLICY"
|
McsSecureFeaturePolicy = "MCS_SECURE_FEATURE_POLICY"
|
||||||
McsSecureExpectCTHeader = "MCS_SECURE_EXPECT_CT_HEADER"
|
McsSecureExpectCTHeader = "MCS_SECURE_EXPECT_CT_HEADER"
|
||||||
McsM3Host = "MCS_M3_HOSTNAME"
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -754,6 +754,40 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/login/mkube": {
|
||||||
|
"post": {
|
||||||
|
"security": [],
|
||||||
|
"tags": [
|
||||||
|
"UserAPI"
|
||||||
|
],
|
||||||
|
"summary": "Login to Mkube.",
|
||||||
|
"operationId": "LoginMkube",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/loginMkubeRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "A successful login.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/loginResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "Generic error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/login/oauth2/auth": {
|
"/login/oauth2/auth": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [],
|
"security": [],
|
||||||
@@ -1719,7 +1753,8 @@ func init() {
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
"form",
|
"form",
|
||||||
"redirect"
|
"redirect",
|
||||||
|
"service-account"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"redirect": {
|
"redirect": {
|
||||||
@@ -1727,6 +1762,17 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"loginMkubeRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"jwt"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"jwt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"loginOauth2AuthRequest": {
|
"loginOauth2AuthRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
@@ -2869,6 +2915,40 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/login/mkube": {
|
||||||
|
"post": {
|
||||||
|
"security": [],
|
||||||
|
"tags": [
|
||||||
|
"UserAPI"
|
||||||
|
],
|
||||||
|
"summary": "Login to Mkube.",
|
||||||
|
"operationId": "LoginMkube",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/loginMkubeRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "A successful login.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/loginResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "Generic error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/login/oauth2/auth": {
|
"/login/oauth2/auth": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [],
|
"security": [],
|
||||||
@@ -3834,7 +3914,8 @@ func init() {
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
"form",
|
"form",
|
||||||
"redirect"
|
"redirect",
|
||||||
|
"service-account"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"redirect": {
|
"redirect": {
|
||||||
@@ -3842,6 +3923,17 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"loginMkubeRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"jwt"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"jwt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"loginOauth2AuthRequest": {
|
"loginOauth2AuthRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package restapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@@ -25,24 +26,45 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
apiErrors "github.com/go-openapi/errors"
|
apiErrors "github.com/go-openapi/errors"
|
||||||
|
"github.com/minio/mcs/pkg/auth"
|
||||||
|
"github.com/minio/mcs/pkg/auth/mkube"
|
||||||
)
|
)
|
||||||
|
|
||||||
// serverMkube handles calls for mkube
|
// serverMkube handles calls for mkube
|
||||||
func serverMkube(client *http.Client, w http.ResponseWriter, req *http.Request) {
|
func serverMkube(client *http.Client, w http.ResponseWriter, req *http.Request) {
|
||||||
|
// extract the service account token inside the jwt encrypted claims
|
||||||
|
claims, err := auth.GetClaimsFromTokenInRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
apiErrors.ServeError(w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m3SAToken := claims.SessionToken
|
||||||
|
if m3SAToken == "" {
|
||||||
|
apiErrors.ServeError(w, req, errors.New("service M3 is not available"))
|
||||||
|
return
|
||||||
|
}
|
||||||
// destination of the request, the mkube server
|
// destination of the request, the mkube server
|
||||||
req.URL.Path = strings.Replace(req.URL.Path, "/mkube", "", 1)
|
req.URL.Path = strings.Replace(req.URL.Path, "/mkube", "", 1)
|
||||||
targetURL := fmt.Sprintf("%s%s", getM3Host(), req.URL.String())
|
targetURL := fmt.Sprintf("%s%s", mkube.GetMkubeEndpoint(), req.URL.String())
|
||||||
|
body := new(bytes.Buffer)
|
||||||
|
_, err = body.ReadFrom(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
apiErrors.ServeError(w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
// set the HTTP method, url, and m3Req body
|
// set the HTTP method, url, and m3Req body
|
||||||
m3Req, err := http.NewRequest(req.Method, targetURL, req.Body)
|
m3Req, err := http.NewRequest(req.Method, targetURL, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiErrors.ServeError(w, req, err)
|
apiErrors.ServeError(w, req, err)
|
||||||
log.Println("error creating m3 request:", err)
|
log.Println("error creating m3 request:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the m3Req headers
|
// Set the m3Req authorization headers
|
||||||
m3Req.Header = req.Header
|
// Authorization Header needs to be like "Authorization Bearer <jwt_token>"
|
||||||
|
token := fmt.Sprintf("Bearer %s", m3SAToken)
|
||||||
|
m3Req.Header.Add("Authorization", token)
|
||||||
|
m3Req.Header.Add("Content-type", "application/json; charset=utf-8")
|
||||||
resp, err := client.Do(m3Req)
|
resp, err := client.Do(m3Req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error on m3 request:", err)
|
log.Println("error on m3 request:", err)
|
||||||
|
|||||||
@@ -19,11 +19,15 @@ package restapi
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/minio/mcs/pkg/auth"
|
||||||
|
"github.com/minio/minio-go/v6/pkg/credentials"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RoundTripFunc .
|
// RoundTripFunc .
|
||||||
@@ -41,8 +45,17 @@ func NewTestClient(fn RoundTripFunc) *http.Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_serverMkube(t *testing.T) {
|
var audience = ""
|
||||||
|
var creds = &credentials.Value{
|
||||||
|
AccessKeyID: "fakeAccessKeyID",
|
||||||
|
SecretAccessKey: "fakeSecretAccessKey",
|
||||||
|
SessionToken: "fakeSessionToken",
|
||||||
|
SignerType: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_serverMkube(t *testing.T) {
|
||||||
|
jwt, _ := auth.NewJWTWithClaimsForClient(creds, []string{""}, audience)
|
||||||
|
dummyBody := ioutil.NopCloser(bytes.NewReader([]byte("foo")))
|
||||||
OKclient := NewTestClient(func(req *http.Request) (*http.Response, error) {
|
OKclient := NewTestClient(func(req *http.Request) (*http.Response, error) {
|
||||||
return &http.Response{
|
return &http.Response{
|
||||||
StatusCode: 200,
|
StatusCode: 200,
|
||||||
@@ -83,16 +96,53 @@ func Test_serverMkube(t *testing.T) {
|
|||||||
args: args{
|
args: args{
|
||||||
client: OKclient,
|
client: OKclient,
|
||||||
recorder: httptest.NewRecorder(),
|
recorder: httptest.NewRecorder(),
|
||||||
req: &http.Request{URL: testURL},
|
req: &http.Request{
|
||||||
|
Body: dummyBody,
|
||||||
|
URL: testURL,
|
||||||
|
Header: http.Header{
|
||||||
|
"Authorization": []string{fmt.Sprintf("Bearer %s", jwt)},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
wantCode: 200,
|
wantCode: 200,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Unsuccessful request - wrong jwt credentials",
|
||||||
|
args: args{
|
||||||
|
client: OKclient,
|
||||||
|
recorder: httptest.NewRecorder(),
|
||||||
|
req: &http.Request{
|
||||||
|
Body: dummyBody,
|
||||||
|
URL: testURL,
|
||||||
|
Header: http.Header{
|
||||||
|
"Authorization": []string{"EAEAEAEAE"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantCode: 500,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unsuccessful request - no mkube service account token provided",
|
||||||
|
args: args{
|
||||||
|
client: OKclient,
|
||||||
|
recorder: httptest.NewRecorder(),
|
||||||
|
req: &http.Request{
|
||||||
|
Body: dummyBody,
|
||||||
|
URL: testURL,
|
||||||
|
Header: http.Header{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantCode: 500,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Unsuccessful request",
|
name: "Unsuccessful request",
|
||||||
args: args{
|
args: args{
|
||||||
client: badClient,
|
client: badClient,
|
||||||
recorder: httptest.NewRecorder(),
|
recorder: httptest.NewRecorder(),
|
||||||
req: &http.Request{URL: testURL},
|
req: &http.Request{
|
||||||
|
URL: testURL,
|
||||||
|
Body: dummyBody,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
wantCode: 500,
|
wantCode: 500,
|
||||||
},
|
},
|
||||||
@@ -101,7 +151,10 @@ func Test_serverMkube(t *testing.T) {
|
|||||||
args: args{
|
args: args{
|
||||||
client: refusedClient,
|
client: refusedClient,
|
||||||
recorder: httptest.NewRecorder(),
|
recorder: httptest.NewRecorder(),
|
||||||
req: &http.Request{URL: testURL},
|
req: &http.Request{
|
||||||
|
URL: testURL,
|
||||||
|
Body: dummyBody,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
wantCode: 500,
|
wantCode: 500,
|
||||||
},
|
},
|
||||||
@@ -111,7 +164,7 @@ func Test_serverMkube(t *testing.T) {
|
|||||||
serverMkube(tt.args.client, tt.args.recorder, tt.args.req)
|
serverMkube(tt.args.client, tt.args.recorder, tt.args.req)
|
||||||
resp := tt.args.recorder.Result()
|
resp := tt.args.recorder.Result()
|
||||||
if resp.StatusCode != tt.wantCode {
|
if resp.StatusCode != tt.wantCode {
|
||||||
t.Errorf("Invalid code returned")
|
t.Errorf("Invalid code returned, expected: %d received: %d", tt.wantCode, resp.StatusCode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -141,6 +141,9 @@ func NewMcsAPI(spec *loads.Document) *McsAPI {
|
|||||||
UserAPILoginDetailHandler: user_api.LoginDetailHandlerFunc(func(params user_api.LoginDetailParams) middleware.Responder {
|
UserAPILoginDetailHandler: user_api.LoginDetailHandlerFunc(func(params user_api.LoginDetailParams) middleware.Responder {
|
||||||
return middleware.NotImplemented("operation user_api.LoginDetail has not yet been implemented")
|
return middleware.NotImplemented("operation user_api.LoginDetail has not yet been implemented")
|
||||||
}),
|
}),
|
||||||
|
UserAPILoginMkubeHandler: user_api.LoginMkubeHandlerFunc(func(params user_api.LoginMkubeParams) middleware.Responder {
|
||||||
|
return middleware.NotImplemented("operation user_api.LoginMkube has not yet been implemented")
|
||||||
|
}),
|
||||||
UserAPILoginOauth2AuthHandler: user_api.LoginOauth2AuthHandlerFunc(func(params user_api.LoginOauth2AuthParams) middleware.Responder {
|
UserAPILoginOauth2AuthHandler: user_api.LoginOauth2AuthHandlerFunc(func(params user_api.LoginOauth2AuthParams) middleware.Responder {
|
||||||
return middleware.NotImplemented("operation user_api.LoginOauth2Auth has not yet been implemented")
|
return middleware.NotImplemented("operation user_api.LoginOauth2Auth has not yet been implemented")
|
||||||
}),
|
}),
|
||||||
@@ -293,6 +296,8 @@ type McsAPI struct {
|
|||||||
UserAPILoginHandler user_api.LoginHandler
|
UserAPILoginHandler user_api.LoginHandler
|
||||||
// UserAPILoginDetailHandler sets the operation handler for the login detail operation
|
// UserAPILoginDetailHandler sets the operation handler for the login detail operation
|
||||||
UserAPILoginDetailHandler user_api.LoginDetailHandler
|
UserAPILoginDetailHandler user_api.LoginDetailHandler
|
||||||
|
// UserAPILoginMkubeHandler sets the operation handler for the login mkube operation
|
||||||
|
UserAPILoginMkubeHandler user_api.LoginMkubeHandler
|
||||||
// UserAPILoginOauth2AuthHandler sets the operation handler for the login oauth2 auth operation
|
// UserAPILoginOauth2AuthHandler sets the operation handler for the login oauth2 auth operation
|
||||||
UserAPILoginOauth2AuthHandler user_api.LoginOauth2AuthHandler
|
UserAPILoginOauth2AuthHandler user_api.LoginOauth2AuthHandler
|
||||||
// UserAPILogoutHandler sets the operation handler for the logout operation
|
// UserAPILogoutHandler sets the operation handler for the logout operation
|
||||||
@@ -478,6 +483,9 @@ func (o *McsAPI) Validate() error {
|
|||||||
if o.UserAPILoginDetailHandler == nil {
|
if o.UserAPILoginDetailHandler == nil {
|
||||||
unregistered = append(unregistered, "user_api.LoginDetailHandler")
|
unregistered = append(unregistered, "user_api.LoginDetailHandler")
|
||||||
}
|
}
|
||||||
|
if o.UserAPILoginMkubeHandler == nil {
|
||||||
|
unregistered = append(unregistered, "user_api.LoginMkubeHandler")
|
||||||
|
}
|
||||||
if o.UserAPILoginOauth2AuthHandler == nil {
|
if o.UserAPILoginOauth2AuthHandler == nil {
|
||||||
unregistered = append(unregistered, "user_api.LoginOauth2AuthHandler")
|
unregistered = append(unregistered, "user_api.LoginOauth2AuthHandler")
|
||||||
}
|
}
|
||||||
@@ -736,6 +744,10 @@ func (o *McsAPI) initHandlerCache() {
|
|||||||
if o.handlers["POST"] == nil {
|
if o.handlers["POST"] == nil {
|
||||||
o.handlers["POST"] = make(map[string]http.Handler)
|
o.handlers["POST"] = make(map[string]http.Handler)
|
||||||
}
|
}
|
||||||
|
o.handlers["POST"]["/login/mkube"] = user_api.NewLoginMkube(o.context, o.UserAPILoginMkubeHandler)
|
||||||
|
if o.handlers["POST"] == nil {
|
||||||
|
o.handlers["POST"] = make(map[string]http.Handler)
|
||||||
|
}
|
||||||
o.handlers["POST"]["/login/oauth2/auth"] = user_api.NewLoginOauth2Auth(o.context, o.UserAPILoginOauth2AuthHandler)
|
o.handlers["POST"]["/login/oauth2/auth"] = user_api.NewLoginOauth2Auth(o.context, o.UserAPILoginOauth2AuthHandler)
|
||||||
if o.handlers["POST"] == nil {
|
if o.handlers["POST"] == nil {
|
||||||
o.handlers["POST"] = make(map[string]http.Handler)
|
o.handlers["POST"] = make(map[string]http.Handler)
|
||||||
|
|||||||
75
restapi/operations/user_api/login_mkube.go
Normal file
75
restapi/operations/user_api/login_mkube.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 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 user_api
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoginMkubeHandlerFunc turns a function with the right signature into a login mkube handler
|
||||||
|
type LoginMkubeHandlerFunc func(LoginMkubeParams) middleware.Responder
|
||||||
|
|
||||||
|
// Handle executing the request and returning a response
|
||||||
|
func (fn LoginMkubeHandlerFunc) Handle(params LoginMkubeParams) middleware.Responder {
|
||||||
|
return fn(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoginMkubeHandler interface for that can handle valid login mkube params
|
||||||
|
type LoginMkubeHandler interface {
|
||||||
|
Handle(LoginMkubeParams) middleware.Responder
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLoginMkube creates a new http.Handler for the login mkube operation
|
||||||
|
func NewLoginMkube(ctx *middleware.Context, handler LoginMkubeHandler) *LoginMkube {
|
||||||
|
return &LoginMkube{Context: ctx, Handler: handler}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*LoginMkube swagger:route POST /login/mkube UserAPI loginMkube
|
||||||
|
|
||||||
|
Login to Mkube.
|
||||||
|
|
||||||
|
*/
|
||||||
|
type LoginMkube struct {
|
||||||
|
Context *middleware.Context
|
||||||
|
Handler LoginMkubeHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *LoginMkube) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||||
|
if rCtx != nil {
|
||||||
|
r = rCtx
|
||||||
|
}
|
||||||
|
var Params = NewLoginMkubeParams()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
}
|
||||||
94
restapi/operations/user_api/login_mkube_parameters.go
Normal file
94
restapi/operations/user_api/login_mkube_parameters.go
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 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 user_api
|
||||||
|
|
||||||
|
// 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/minio/mcs/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewLoginMkubeParams creates a new LoginMkubeParams object
|
||||||
|
// no default values defined in spec.
|
||||||
|
func NewLoginMkubeParams() LoginMkubeParams {
|
||||||
|
|
||||||
|
return LoginMkubeParams{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoginMkubeParams contains all the bound params for the login mkube operation
|
||||||
|
// typically these are obtained from a http.Request
|
||||||
|
//
|
||||||
|
// swagger:parameters LoginMkube
|
||||||
|
type LoginMkubeParams struct {
|
||||||
|
|
||||||
|
// HTTP Request Object
|
||||||
|
HTTPRequest *http.Request `json:"-"`
|
||||||
|
|
||||||
|
/*
|
||||||
|
Required: true
|
||||||
|
In: body
|
||||||
|
*/
|
||||||
|
Body *models.LoginMkubeRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 NewLoginMkubeParams() beforehand.
|
||||||
|
func (o *LoginMkubeParams) 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.LoginMkubeRequest
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
133
restapi/operations/user_api/login_mkube_responses.go
Normal file
133
restapi/operations/user_api/login_mkube_responses.go
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 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 user_api
|
||||||
|
|
||||||
|
// 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/mcs/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoginMkubeCreatedCode is the HTTP code returned for type LoginMkubeCreated
|
||||||
|
const LoginMkubeCreatedCode int = 201
|
||||||
|
|
||||||
|
/*LoginMkubeCreated A successful login.
|
||||||
|
|
||||||
|
swagger:response loginMkubeCreated
|
||||||
|
*/
|
||||||
|
type LoginMkubeCreated struct {
|
||||||
|
|
||||||
|
/*
|
||||||
|
In: Body
|
||||||
|
*/
|
||||||
|
Payload *models.LoginResponse `json:"body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLoginMkubeCreated creates LoginMkubeCreated with default headers values
|
||||||
|
func NewLoginMkubeCreated() *LoginMkubeCreated {
|
||||||
|
|
||||||
|
return &LoginMkubeCreated{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPayload adds the payload to the login mkube created response
|
||||||
|
func (o *LoginMkubeCreated) WithPayload(payload *models.LoginResponse) *LoginMkubeCreated {
|
||||||
|
o.Payload = payload
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPayload sets the payload to the login mkube created response
|
||||||
|
func (o *LoginMkubeCreated) SetPayload(payload *models.LoginResponse) {
|
||||||
|
o.Payload = payload
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse to the client
|
||||||
|
func (o *LoginMkubeCreated) 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*LoginMkubeDefault Generic error response.
|
||||||
|
|
||||||
|
swagger:response loginMkubeDefault
|
||||||
|
*/
|
||||||
|
type LoginMkubeDefault struct {
|
||||||
|
_statusCode int
|
||||||
|
|
||||||
|
/*
|
||||||
|
In: Body
|
||||||
|
*/
|
||||||
|
Payload *models.Error `json:"body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLoginMkubeDefault creates LoginMkubeDefault with default headers values
|
||||||
|
func NewLoginMkubeDefault(code int) *LoginMkubeDefault {
|
||||||
|
if code <= 0 {
|
||||||
|
code = 500
|
||||||
|
}
|
||||||
|
|
||||||
|
return &LoginMkubeDefault{
|
||||||
|
_statusCode: code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStatusCode adds the status to the login mkube default response
|
||||||
|
func (o *LoginMkubeDefault) WithStatusCode(code int) *LoginMkubeDefault {
|
||||||
|
o._statusCode = code
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStatusCode sets the status to the login mkube default response
|
||||||
|
func (o *LoginMkubeDefault) SetStatusCode(code int) {
|
||||||
|
o._statusCode = code
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPayload adds the payload to the login mkube default response
|
||||||
|
func (o *LoginMkubeDefault) WithPayload(payload *models.Error) *LoginMkubeDefault {
|
||||||
|
o.Payload = payload
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPayload sets the payload to the login mkube default response
|
||||||
|
func (o *LoginMkubeDefault) SetPayload(payload *models.Error) {
|
||||||
|
o.Payload = payload
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse to the client
|
||||||
|
func (o *LoginMkubeDefault) 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
104
restapi/operations/user_api/login_mkube_urlbuilder.go
Normal file
104
restapi/operations/user_api/login_mkube_urlbuilder.go
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 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 user_api
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoginMkubeURL generates an URL for the login mkube operation
|
||||||
|
type LoginMkubeURL 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 *LoginMkubeURL) WithBasePath(bp string) *LoginMkubeURL {
|
||||||
|
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 *LoginMkubeURL) SetBasePath(bp string) {
|
||||||
|
o._basePath = bp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a url path and query string
|
||||||
|
func (o *LoginMkubeURL) Build() (*url.URL, error) {
|
||||||
|
var _result url.URL
|
||||||
|
|
||||||
|
var _path = "/login/mkube"
|
||||||
|
|
||||||
|
_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 *LoginMkubeURL) 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 *LoginMkubeURL) String() string {
|
||||||
|
return o.Must(o.Build()).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildFull builds a full url with scheme, host, path and query string
|
||||||
|
func (o *LoginMkubeURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||||
|
if scheme == "" {
|
||||||
|
return nil, errors.New("scheme is required for a full url on LoginMkubeURL")
|
||||||
|
}
|
||||||
|
if host == "" {
|
||||||
|
return nil, errors.New("host is required for a full url on LoginMkubeURL")
|
||||||
|
}
|
||||||
|
|
||||||
|
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 *LoginMkubeURL) StringFull(scheme, host string) string {
|
||||||
|
return o.Must(o.BuildFull(scheme, host)).String()
|
||||||
|
}
|
||||||
@@ -60,7 +60,7 @@ func prepareSTSClientTransport() *http.Transport {
|
|||||||
// Can't use TLSv1.1 because of RC4 cipher usage
|
// Can't use TLSv1.1 because of RC4 cipher usage
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
}
|
}
|
||||||
// If root CAs are configured we save them to the http.Client RootCAs store
|
// If CAs certificates are configured we save them to the http.Client RootCAs store
|
||||||
if len(caCertFileNames) > 0 {
|
if len(caCertFileNames) > 0 {
|
||||||
certs := x509.NewCertPool()
|
certs := x509.NewCertPool()
|
||||||
for _, caCert := range caCertFileNames {
|
for _, caCert := range caCertFileNames {
|
||||||
@@ -85,7 +85,7 @@ func prepareSTSClientTransport() *http.Transport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PrepareSTSClient returns an http.Client with custom configurations need it by *credentials.STSAssumeRole
|
// PrepareSTSClient returns an http.Client with custom configurations need it by *credentials.STSAssumeRole
|
||||||
// custom configurations include skipVerification flag, and root CA certificates
|
// custom configurations include the use of CA certificates
|
||||||
func PrepareSTSClient() *http.Client {
|
func PrepareSTSClient() *http.Client {
|
||||||
transport := prepareSTSClientTransport()
|
transport := prepareSTSClientTransport()
|
||||||
// Return http client with default configuration
|
// Return http client with default configuration
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/go-openapi/runtime/middleware"
|
"github.com/go-openapi/runtime/middleware"
|
||||||
"github.com/go-openapi/swag"
|
"github.com/go-openapi/swag"
|
||||||
"github.com/minio/mcs/models"
|
"github.com/minio/mcs/models"
|
||||||
|
"github.com/minio/mcs/pkg/auth"
|
||||||
"github.com/minio/mcs/restapi/operations"
|
"github.com/minio/mcs/restapi/operations"
|
||||||
"github.com/minio/mcs/restapi/operations/user_api"
|
"github.com/minio/mcs/restapi/operations/user_api"
|
||||||
"github.com/minio/minio-go/v6"
|
"github.com/minio/minio-go/v6"
|
||||||
@@ -181,7 +182,11 @@ func createBucketEvent(client MCS3Client, arn string, notificationEvents []model
|
|||||||
|
|
||||||
// getCreateBucketEventsResponse calls createBucketEvent to add a bucket event notification
|
// getCreateBucketEventsResponse calls createBucketEvent to add a bucket event notification
|
||||||
func getCreateBucketEventsResponse(sessionID, bucketName string, eventReq *models.BucketEventRequest) error {
|
func getCreateBucketEventsResponse(sessionID, bucketName string, eventReq *models.BucketEventRequest) error {
|
||||||
s3Client, err := newS3BucketClient(sessionID, bucketName)
|
claims, err := auth.JWTAuthenticate(sessionID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s3Client, err := newS3BucketClient(claims, bucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error creating S3Client:", err)
|
log.Println("error creating S3Client:", err)
|
||||||
return err
|
return err
|
||||||
@@ -217,7 +222,11 @@ func joinNotificationEvents(events []models.NotificationEventType) string {
|
|||||||
|
|
||||||
// getDeleteBucketEventsResponse calls deleteBucketEventNotification() to delete a bucket event notification
|
// getDeleteBucketEventsResponse calls deleteBucketEventNotification() to delete a bucket event notification
|
||||||
func getDeleteBucketEventsResponse(sessionID, bucketName string, arn string, events []models.NotificationEventType, prefix, suffix *string) error {
|
func getDeleteBucketEventsResponse(sessionID, bucketName string, arn string, events []models.NotificationEventType, prefix, suffix *string) error {
|
||||||
s3Client, err := newS3BucketClient(sessionID, bucketName)
|
claims, err := auth.JWTAuthenticate(sessionID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s3Client, err := newS3BucketClient(claims, bucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error creating S3Client:", err)
|
log.Println("error creating S3Client:", err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -61,18 +61,25 @@ func registerLoginHandlers(api *operations.McsAPI) {
|
|||||||
}
|
}
|
||||||
return user_api.NewLoginOauth2AuthCreated().WithPayload(loginResponse)
|
return user_api.NewLoginOauth2AuthCreated().WithPayload(loginResponse)
|
||||||
})
|
})
|
||||||
|
api.UserAPILoginMkubeHandler = user_api.LoginMkubeHandlerFunc(func(params user_api.LoginMkubeParams) middleware.Responder {
|
||||||
|
loginResponse, err := getLoginMkubeResponse(params.Body)
|
||||||
|
if err != nil {
|
||||||
|
return user_api.NewLoginMkubeDefault(401).WithPayload(&models.Error{Code: 401, Message: swag.String(err.Error())})
|
||||||
|
}
|
||||||
|
return user_api.NewLoginMkubeCreated().WithPayload(loginResponse)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// login performs a check of minioCredentials against MinIO, generates some claims and returns the jwt
|
// login performs a check of mcsCredentials against MinIO, generates some claims and returns the jwt
|
||||||
// for subsequent authentication
|
// for subsequent authentication
|
||||||
func login(credentials MCSCredentials, actions []string) (*string, error) {
|
func login(credentials MCSCredentials, actions []string) (*string, error) {
|
||||||
// try to obtain minioCredentials,
|
// try to obtain mcsCredentials,
|
||||||
tokens, err := credentials.Get()
|
tokens, err := credentials.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error authenticating user", err)
|
log.Println("error authenticating user", err)
|
||||||
return nil, errInvalidCredentials
|
return nil, errInvalidCredentials
|
||||||
}
|
}
|
||||||
// if we made it here, the minioCredentials work, generate a jwt with claims
|
// if we made it here, the mcsCredentials work, generate a jwt with claims
|
||||||
jwt, err := auth.NewJWTWithClaimsForClient(&tokens, actions, getMinIOServer())
|
jwt, err := auth.NewJWTWithClaimsForClient(&tokens, actions, getMinIOServer())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error authenticating user", err)
|
log.Println("error authenticating user", err)
|
||||||
@@ -115,7 +122,7 @@ func getLoginResponse(lr *models.LoginRequest) (*models.LoginResponse, error) {
|
|||||||
log.Println("error login:", err)
|
log.Println("error login:", err)
|
||||||
return nil, errInvalidCredentials
|
return nil, errInvalidCredentials
|
||||||
}
|
}
|
||||||
credentials := mcsCredentials{minioCredentials: creds}
|
credentials := mcsCredentials{mcsCredentials: creds}
|
||||||
// obtain the current policy assigned to this user
|
// obtain the current policy assigned to this user
|
||||||
// necessary for generating the list of allowed endpoints
|
// necessary for generating the list of allowed endpoints
|
||||||
userInfo, err := adminClient.getUserInfo(ctx, *lr.AccessKey)
|
userInfo, err := adminClient.getUserInfo(ctx, *lr.AccessKey)
|
||||||
@@ -127,7 +134,7 @@ func getLoginResponse(lr *models.LoginRequest) (*models.LoginResponse, error) {
|
|||||||
// by default every user starts with an empty array of available actions
|
// by default every user starts with an empty array of available actions
|
||||||
// therefore we would have access only to pages that doesn't require any privilege
|
// therefore we would have access only to pages that doesn't require any privilege
|
||||||
// ie: service-account page
|
// ie: service-account page
|
||||||
actions := []string{}
|
var actions []string
|
||||||
// if a policy is assigned to this user we parse the actions from there
|
// if a policy is assigned to this user we parse the actions from there
|
||||||
if policy != nil {
|
if policy != nil {
|
||||||
actions = acl.GetActionsStringFromPolicy(policy)
|
actions = acl.GetActionsStringFromPolicy(policy)
|
||||||
@@ -148,7 +155,9 @@ func getLoginDetailsResponse() (*models.LoginDetails, error) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
loginStrategy := models.LoginDetailsLoginStrategyForm
|
loginStrategy := models.LoginDetailsLoginStrategyForm
|
||||||
redirectURL := ""
|
redirectURL := ""
|
||||||
if oauth2.IsIdpEnabled() {
|
if acl.GetOperatorOnly() {
|
||||||
|
loginStrategy = models.LoginDetailsLoginStrategyServiceAccount
|
||||||
|
} else if oauth2.IsIdpEnabled() {
|
||||||
loginStrategy = models.LoginDetailsLoginStrategyRedirect
|
loginStrategy = models.LoginDetailsLoginStrategyRedirect
|
||||||
// initialize new oauth2 client
|
// initialize new oauth2 client
|
||||||
oauth2Client, err := oauth2.NewOauth2ProviderClient(ctx, nil)
|
oauth2Client, err := oauth2.NewOauth2ProviderClient(ctx, nil)
|
||||||
@@ -238,7 +247,7 @@ func getLoginOauth2AuthResponse(lr *models.LoginOauth2AuthRequest) (*models.Logi
|
|||||||
log.Println("error login:", err)
|
log.Println("error login:", err)
|
||||||
return nil, errorGeneric
|
return nil, errorGeneric
|
||||||
}
|
}
|
||||||
credentials := mcsCredentials{minioCredentials: creds}
|
credentials := mcsCredentials{mcsCredentials: creds}
|
||||||
jwt, err := login(credentials, actions)
|
jwt, err := login(credentials, actions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -251,3 +260,23 @@ func getLoginOauth2AuthResponse(lr *models.LoginOauth2AuthRequest) (*models.Logi
|
|||||||
}
|
}
|
||||||
return nil, errorGeneric
|
return nil, errorGeneric
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getLoginMkubeResponse validate the provided service account token against mkube
|
||||||
|
func getLoginMkubeResponse(lmr *models.LoginMkubeRequest) (*models.LoginResponse, error) {
|
||||||
|
creds, err := newMcsCredentials("", *lmr.Jwt, "")
|
||||||
|
if err != nil {
|
||||||
|
log.Println("error login:", err)
|
||||||
|
return nil, errInvalidCredentials
|
||||||
|
}
|
||||||
|
credentials := mcsCredentials{mcsCredentials: creds}
|
||||||
|
var actions []string
|
||||||
|
jwt, err := login(credentials, actions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// serialize output
|
||||||
|
loginResponse := &models.LoginResponse{
|
||||||
|
SessionID: *jwt,
|
||||||
|
}
|
||||||
|
return loginResponse, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func registerLogoutHandlers(api *operations.McsAPI) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// logout() call Expire() on the provided minioCredentials
|
// logout() call Expire() on the provided mcsCredentials
|
||||||
func logout(credentials MCSCredentials) {
|
func logout(credentials MCSCredentials) {
|
||||||
credentials.Expire()
|
credentials.Expire()
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ func getLogoutResponse(jwt string) error {
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
credentials := mcsCredentials{minioCredentials: creds}
|
credentials := mcsCredentials{mcsCredentials: creds}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error creating MinIO Client:", err)
|
log.Println("error creating MinIO Client:", err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import (
|
|||||||
"github.com/go-openapi/errors"
|
"github.com/go-openapi/errors"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/minio/mcs/pkg/auth"
|
"github.com/minio/mcs/pkg/auth"
|
||||||
"github.com/minio/mcs/pkg/ws"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var upgrader = websocket.Upgrader{
|
var upgrader = websocket.Upgrader{
|
||||||
@@ -99,14 +98,9 @@ func (c wsConn) readMessage() (messageType int, p []byte, err error) {
|
|||||||
// on the path.
|
// on the path.
|
||||||
// Request should come like ws://<host>:<port>/ws/<api>
|
// Request should come like ws://<host>:<port>/ws/<api>
|
||||||
func serveWS(w http.ResponseWriter, req *http.Request) {
|
func serveWS(w http.ResponseWriter, req *http.Request) {
|
||||||
sessionID, err := ws.GetTokenFromRequest(req)
|
|
||||||
if err != nil {
|
|
||||||
errors.ServeError(w, req, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Perform authentication before upgrading to a Websocket Connection
|
// Perform authentication before upgrading to a Websocket Connection
|
||||||
// authenticate WS connection with MCS
|
// authenticate WS connection with MCS
|
||||||
claims, err := auth.JWTAuthenticate(*sessionID)
|
claims, err := auth.GetClaimsFromTokenInRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print("error on ws authentication: ", err)
|
log.Print("error on ws authentication: ", err)
|
||||||
errors.ServeError(w, req, errors.New(http.StatusUnauthorized, err.Error()))
|
errors.ServeError(w, req, errors.New(http.StatusUnauthorized, err.Error()))
|
||||||
@@ -152,7 +146,7 @@ func serveWS(w http.ResponseWriter, req *http.Request) {
|
|||||||
go wsAdminClient.heal(hOptions)
|
go wsAdminClient.heal(hOptions)
|
||||||
case strings.HasPrefix(wsPath, `/watch`):
|
case strings.HasPrefix(wsPath, `/watch`):
|
||||||
wOptions := getWatchOptionsFromReq(req)
|
wOptions := getWatchOptionsFromReq(req)
|
||||||
wsS3Client, err := newWebSocketS3Client(conn, *sessionID, wOptions.BucketName)
|
wsS3Client, err := newWebSocketS3Client(conn, claims, wOptions.BucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
closeWsConn(conn)
|
closeWsConn(conn)
|
||||||
return
|
return
|
||||||
@@ -188,10 +182,10 @@ func newWebSocketAdminClient(conn *websocket.Conn, autClaims *auth.DecryptedClai
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newWebSocketS3Client returns a wsAdminClient authenticated as MCS admin
|
// newWebSocketS3Client returns a wsAdminClient authenticated as MCS admin
|
||||||
func newWebSocketS3Client(conn *websocket.Conn, jwt, bucketName string) (*wsS3Client, error) {
|
func newWebSocketS3Client(conn *websocket.Conn, claims *auth.DecryptedClaims, bucketName string) (*wsS3Client, error) {
|
||||||
// Only start Websocket Interaction after user has been
|
// Only start Websocket Interaction after user has been
|
||||||
// authenticated with MinIO
|
// authenticated with MinIO
|
||||||
s3Client, err := newS3BucketClient(jwt, bucketName)
|
s3Client, err := newS3BucketClient(claims, bucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error creating S3Client:", err)
|
log.Println("error creating S3Client:", err)
|
||||||
conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
|
conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
|
||||||
|
|||||||
37
swagger.yml
37
swagger.yml
@@ -60,6 +60,28 @@ paths:
|
|||||||
security: []
|
security: []
|
||||||
tags:
|
tags:
|
||||||
- UserAPI
|
- UserAPI
|
||||||
|
/login/mkube:
|
||||||
|
post:
|
||||||
|
summary: Login to Mkube.
|
||||||
|
operationId: LoginMkube
|
||||||
|
parameters:
|
||||||
|
- name: body
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/loginMkubeRequest'
|
||||||
|
responses:
|
||||||
|
201:
|
||||||
|
description: A successful login.
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/loginResponse'
|
||||||
|
default:
|
||||||
|
description: Generic error response.
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/error"
|
||||||
|
security: []
|
||||||
|
tags:
|
||||||
|
- UserAPI
|
||||||
|
|
||||||
/login/oauth2/auth:
|
/login/oauth2/auth:
|
||||||
post:
|
post:
|
||||||
@@ -354,7 +376,7 @@ paths:
|
|||||||
$ref: "#/definitions/error"
|
$ref: "#/definitions/error"
|
||||||
tags:
|
tags:
|
||||||
- UserAPI
|
- UserAPI
|
||||||
|
|
||||||
/service-accounts/{access_key}:
|
/service-accounts/{access_key}:
|
||||||
delete:
|
delete:
|
||||||
summary: Delete Service Account
|
summary: Delete Service Account
|
||||||
@@ -1173,7 +1195,7 @@ definitions:
|
|||||||
- get
|
- get
|
||||||
notificationConfig:
|
notificationConfig:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- arn
|
- arn
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
@@ -1212,7 +1234,7 @@ definitions:
|
|||||||
title: "filter event associated to the specified suffix"
|
title: "filter event associated to the specified suffix"
|
||||||
bucketEventRequest:
|
bucketEventRequest:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- configuration
|
- configuration
|
||||||
properties:
|
properties:
|
||||||
configuration:
|
configuration:
|
||||||
@@ -1242,7 +1264,7 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
loginStrategy:
|
loginStrategy:
|
||||||
type: string
|
type: string
|
||||||
enum: [form,redirect]
|
enum: [form,redirect,service-account]
|
||||||
redirect:
|
redirect:
|
||||||
type: string
|
type: string
|
||||||
loginOauth2AuthRequest:
|
loginOauth2AuthRequest:
|
||||||
@@ -1255,6 +1277,13 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
code:
|
code:
|
||||||
type: string
|
type: string
|
||||||
|
loginMkubeRequest:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- jwt
|
||||||
|
properties:
|
||||||
|
jwt:
|
||||||
|
type: string
|
||||||
loginRequest:
|
loginRequest:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
|||||||
Reference in New Issue
Block a user