Adding key creation in tenant wizard. (#697)
Signed-off-by: Adam Stafford <adam@minio.io> Co-authored-by: Adam Stafford <adamstafford@MacBook-Pro-van-Adam-2.local>
This commit is contained in:
@@ -23,6 +23,8 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
@@ -37,6 +39,9 @@ type IdpConfiguration struct {
|
||||
// active directory
|
||||
ActiveDirectory *IdpConfigurationActiveDirectory `json:"active_directory,omitempty"`
|
||||
|
||||
// keys
|
||||
Keys []*IdpConfigurationKeysItems0 `json:"keys"`
|
||||
|
||||
// oidc
|
||||
Oidc *IdpConfigurationOidc `json:"oidc,omitempty"`
|
||||
}
|
||||
@@ -49,6 +54,10 @@ func (m *IdpConfiguration) Validate(formats strfmt.Registry) error {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateKeys(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateOidc(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
@@ -77,6 +86,31 @@ func (m *IdpConfiguration) validateActiveDirectory(formats strfmt.Registry) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *IdpConfiguration) validateKeys(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Keys) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(m.Keys); i++ {
|
||||
if swag.IsZero(m.Keys[i]) { // not required
|
||||
continue
|
||||
}
|
||||
|
||||
if m.Keys[i] != nil {
|
||||
if err := m.Keys[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("keys" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *IdpConfiguration) validateOidc(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Oidc) { // not required
|
||||
@@ -213,6 +247,74 @@ func (m *IdpConfigurationActiveDirectory) UnmarshalBinary(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IdpConfigurationKeysItems0 idp configuration keys items0
|
||||
//
|
||||
// swagger:model IdpConfigurationKeysItems0
|
||||
type IdpConfigurationKeysItems0 struct {
|
||||
|
||||
// access key
|
||||
// Required: true
|
||||
AccessKey *string `json:"access_key"`
|
||||
|
||||
// secret key
|
||||
// Required: true
|
||||
SecretKey *string `json:"secret_key"`
|
||||
}
|
||||
|
||||
// Validate validates this idp configuration keys items0
|
||||
func (m *IdpConfigurationKeysItems0) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateAccessKey(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateSecretKey(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *IdpConfigurationKeysItems0) validateAccessKey(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("access_key", "body", m.AccessKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *IdpConfigurationKeysItems0) validateSecretKey(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("secret_key", "body", m.SecretKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *IdpConfigurationKeysItems0) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *IdpConfigurationKeysItems0) UnmarshalBinary(b []byte) error {
|
||||
var res IdpConfigurationKeysItems0
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
|
||||
// IdpConfigurationOidc idp configuration oidc
|
||||
//
|
||||
// swagger:model IdpConfigurationOidc
|
||||
|
||||
10
node_modules/.yarn-integrity
generated
vendored
Normal file
10
node_modules/.yarn-integrity
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"systemParams": "darwin-x64-88",
|
||||
"modulesFolders": [],
|
||||
"flags": [],
|
||||
"linkedModules": [],
|
||||
"topLevelPatterns": [],
|
||||
"lockfileEntries": {},
|
||||
"files": [],
|
||||
"artifacts": {}
|
||||
}
|
||||
@@ -1,25 +1,25 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.a19f3d53.chunk.css",
|
||||
"main.js": "/static/js/main.fb87f627.chunk.js",
|
||||
"main.js.map": "/static/js/main.fb87f627.chunk.js.map",
|
||||
"main.js": "/static/js/main.0888f199.chunk.js",
|
||||
"main.js.map": "/static/js/main.0888f199.chunk.js.map",
|
||||
"runtime-main.js": "/static/js/runtime-main.f48e99e5.js",
|
||||
"runtime-main.js.map": "/static/js/runtime-main.f48e99e5.js.map",
|
||||
"static/css/2.f324abd6.chunk.css": "/static/css/2.f324abd6.chunk.css",
|
||||
"static/js/2.26e254ca.chunk.js": "/static/js/2.26e254ca.chunk.js",
|
||||
"static/js/2.26e254ca.chunk.js.map": "/static/js/2.26e254ca.chunk.js.map",
|
||||
"static/js/2.a71657cf.chunk.js": "/static/js/2.a71657cf.chunk.js",
|
||||
"static/js/2.a71657cf.chunk.js.map": "/static/js/2.a71657cf.chunk.js.map",
|
||||
"index.html": "/index.html",
|
||||
"static/css/2.f324abd6.chunk.css.map": "/static/css/2.f324abd6.chunk.css.map",
|
||||
"static/css/main.a19f3d53.chunk.css.map": "/static/css/main.a19f3d53.chunk.css.map",
|
||||
"static/js/2.26e254ca.chunk.js.LICENSE.txt": "/static/js/2.26e254ca.chunk.js.LICENSE.txt",
|
||||
"static/js/2.a71657cf.chunk.js.LICENSE.txt": "/static/js/2.a71657cf.chunk.js.LICENSE.txt",
|
||||
"static/media/minio_console_logo.0837460e.svg": "/static/media/minio_console_logo.0837460e.svg",
|
||||
"static/media/minio_operator_logo.1312b7c9.svg": "/static/media/minio_operator_logo.1312b7c9.svg"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/js/runtime-main.f48e99e5.js",
|
||||
"static/css/2.f324abd6.chunk.css",
|
||||
"static/js/2.26e254ca.chunk.js",
|
||||
"static/js/2.a71657cf.chunk.js",
|
||||
"static/css/main.a19f3d53.chunk.css",
|
||||
"static/js/main.fb87f627.chunk.js"
|
||||
"static/js/main.0888f199.chunk.js"
|
||||
]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="MinIO Console"/><link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;500;700;900&display=swap" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/><link rel="manifest" href="/manifest.json"/><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="/static/css/2.f324abd6.chunk.css" rel="stylesheet"><link href="/static/css/main.a19f3d53.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="/static/js/2.26e254ca.chunk.js"></script><script src="/static/js/main.fb87f627.chunk.js"></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="MinIO Console"/><link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;500;700;900&display=swap" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/><link rel="manifest" href="/manifest.json"/><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="/static/css/2.f324abd6.chunk.css" rel="stylesheet"><link href="/static/css/main.a19f3d53.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="/static/js/2.a71657cf.chunk.js"></script><script src="/static/js/main.0888f199.chunk.js"></script></body></html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/main.0888f199.chunk.js.map
Normal file
1
portal-ui/build/static/js/main.0888f199.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -54,6 +54,8 @@ export interface ITenantCreator {
|
||||
enable_tls: boolean;
|
||||
access_key: string;
|
||||
secret_key: string;
|
||||
access_keys: string[];
|
||||
secret_keys: string[];
|
||||
image: string;
|
||||
console_image: string;
|
||||
expose_minio: boolean;
|
||||
@@ -66,8 +68,8 @@ export interface ITenantCreator {
|
||||
idp?: IIDPConfiguration;
|
||||
annotations?: Object;
|
||||
image_registry?: ImageRegistry;
|
||||
logSearchConfiguration?: LogSearchConfiguration,
|
||||
prometheusConfiguration?: PrometheusConfiguration,
|
||||
logSearchConfiguration?: LogSearchConfiguration;
|
||||
prometheusConfiguration?: PrometheusConfiguration;
|
||||
}
|
||||
|
||||
export interface ImageRegistry {
|
||||
|
||||
@@ -59,7 +59,6 @@ import EnableVersioningModal from "./EnableVersioningModal";
|
||||
import UsageIcon from "../../../../icons/UsageIcon";
|
||||
import AddPolicy from "../../Policies/AddPolicy";
|
||||
import SetAccessPolicy from "./SetAccessPolicy";
|
||||
|
||||
import DeleteReplicationRule from "../ViewBucket/DeleteReplicationRule";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
|
||||
@@ -112,6 +112,8 @@ const AddTenant = ({
|
||||
const ADGroupBaseDN = fields.identityProvider.ADGroupBaseDN;
|
||||
const ADGroupSearchFilter = fields.identityProvider.ADGroupSearchFilter;
|
||||
const ADNameAttribute = fields.identityProvider.ADNameAttribute;
|
||||
const accessKeys = fields.identityProvider.accessKeys;
|
||||
const secretKeys = fields.identityProvider.secretKeys;
|
||||
const minioCertificates = certificates.minioCertificates;
|
||||
const caCertificates = certificates.caCertificates;
|
||||
const consoleCertificate = certificates.consoleCertificate;
|
||||
@@ -155,11 +157,12 @@ const AddTenant = ({
|
||||
const logSearchCustom = fields.configure.logSearchCustom;
|
||||
const prometheusCustom = fields.configure.prometheusCustom;
|
||||
const logSearchVolumeSize = fields.configure.logSearchVolumeSize;
|
||||
const logSearchSelectedStorageClass = fields.configure.logSearchSelectedStorageClass;
|
||||
const prometheusSelectedStorageClass = fields.configure.prometheusSelectedStorageClass;
|
||||
const logSearchSelectedStorageClass =
|
||||
fields.configure.logSearchSelectedStorageClass;
|
||||
const prometheusSelectedStorageClass =
|
||||
fields.configure.prometheusSelectedStorageClass;
|
||||
const prometheusVolumeSize = fields.configure.prometheusVolumeSize;
|
||||
|
||||
|
||||
if (addSending) {
|
||||
const poolName = generatePoolName([]);
|
||||
|
||||
@@ -175,6 +178,8 @@ const AddTenant = ({
|
||||
namespace: namespace,
|
||||
access_key: "",
|
||||
secret_key: "",
|
||||
access_keys: [],
|
||||
secret_keys: [],
|
||||
enable_tls: enableTLS && enableAutoCert,
|
||||
enable_console: true,
|
||||
enable_prometheus: true,
|
||||
@@ -217,23 +222,23 @@ const AddTenant = ({
|
||||
};
|
||||
}
|
||||
|
||||
if(logSearchCustom) {
|
||||
if (logSearchCustom) {
|
||||
dataSend = {
|
||||
...dataSend,
|
||||
logSearchConfiguration: {
|
||||
storageClass: logSearchSelectedStorageClass,
|
||||
storageSize: parseInt(logSearchVolumeSize),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if(prometheusCustom) {
|
||||
if (prometheusCustom) {
|
||||
dataSend = {
|
||||
...dataSend,
|
||||
prometheusConfiguration: {
|
||||
storageClass: prometheusSelectedStorageClass,
|
||||
storageSize: parseInt(prometheusVolumeSize),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -428,41 +433,50 @@ const AddTenant = ({
|
||||
};
|
||||
}
|
||||
|
||||
if (idpSelection !== "Built-in") {
|
||||
let dataIDP: any = {};
|
||||
|
||||
switch (idpSelection) {
|
||||
case "OpenID":
|
||||
dataIDP = {
|
||||
oidc: {
|
||||
url: openIDURL,
|
||||
client_id: openIDClientID,
|
||||
secret_id: openIDSecretID,
|
||||
},
|
||||
};
|
||||
break;
|
||||
case "AD":
|
||||
dataIDP = {
|
||||
active_directory: {
|
||||
url: ADURL,
|
||||
skip_tls_verification: ADSkipTLS,
|
||||
server_insecure: ADServerInsecure,
|
||||
username_format: "",
|
||||
user_search_filter: ADUserNameFilter,
|
||||
group_search_base_dn: ADGroupBaseDN,
|
||||
group_search_filter: ADGroupSearchFilter,
|
||||
group_name_attribute: ADNameAttribute,
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
dataSend = {
|
||||
...dataSend,
|
||||
idp: { ...dataIDP },
|
||||
};
|
||||
let dataIDP: any = {};
|
||||
switch (idpSelection) {
|
||||
case "Built-in":
|
||||
let keyarray = [];
|
||||
for (let i = 0; i < accessKeys.length; i++) {
|
||||
keyarray.push({
|
||||
access_key: accessKeys[i],
|
||||
secret_key: secretKeys[i],
|
||||
});
|
||||
}
|
||||
dataIDP = {
|
||||
keys: keyarray,
|
||||
};
|
||||
break;
|
||||
case "OpenID":
|
||||
dataIDP = {
|
||||
oidc: {
|
||||
url: openIDURL,
|
||||
client_id: openIDClientID,
|
||||
secret_id: openIDSecretID,
|
||||
},
|
||||
};
|
||||
break;
|
||||
case "AD":
|
||||
dataIDP = {
|
||||
active_directory: {
|
||||
url: ADURL,
|
||||
skip_tls_verification: ADSkipTLS,
|
||||
server_insecure: ADServerInsecure,
|
||||
username_format: "",
|
||||
user_search_filter: ADUserNameFilter,
|
||||
group_search_base_dn: ADGroupBaseDN,
|
||||
group_search_filter: ADGroupSearchFilter,
|
||||
group_name_attribute: ADNameAttribute,
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
dataSend = {
|
||||
...dataSend,
|
||||
idp: { ...dataIDP },
|
||||
};
|
||||
|
||||
api
|
||||
.invoke("POST", `/api/v1/tenants`, dataSend)
|
||||
.then((res) => {
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
import React, { useEffect, useState, useCallback, Fragment } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { Grid, Typography } from "@material-ui/core";
|
||||
import { Grid, Typography, Button, IconButton, Icon } from "@material-ui/core";
|
||||
import CasinoIcon from "@material-ui/icons/Casino";
|
||||
import {
|
||||
modalBasic,
|
||||
wizardCommon,
|
||||
@@ -32,10 +33,15 @@ import { clearValidationError } from "../../utils";
|
||||
import RadioGroupSelector from "../../../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
|
||||
import InputBoxWrapper from "../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import FormSwitchWrapper from "../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
import AddIcon from "../../../../../icons/AddIcon";
|
||||
import { CreateIcon } from "../../../../../icons";
|
||||
import { Casino } from "@material-ui/icons";
|
||||
|
||||
interface IIdentityProviderProps {
|
||||
classes: any;
|
||||
idpSelection: string;
|
||||
accessKeys: string[];
|
||||
secretKeys: string[];
|
||||
openIDURL: string;
|
||||
openIDClientID: string;
|
||||
openIDSecretID: string;
|
||||
@@ -55,6 +61,11 @@ const styles = (theme: Theme) =>
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
shortened: {
|
||||
gridTemplateColumns: "auto auto 30px",
|
||||
display: "grid",
|
||||
gridGap: 20,
|
||||
},
|
||||
...modalBasic,
|
||||
...wizardCommon,
|
||||
});
|
||||
@@ -62,6 +73,8 @@ const styles = (theme: Theme) =>
|
||||
const IdentityProvider = ({
|
||||
classes,
|
||||
idpSelection,
|
||||
accessKeys,
|
||||
secretKeys,
|
||||
openIDURL,
|
||||
openIDClientID,
|
||||
openIDSecretID,
|
||||
@@ -78,12 +91,32 @@ const IdentityProvider = ({
|
||||
const [validationErrors, setValidationErrors] = useState<any>({});
|
||||
|
||||
// Common
|
||||
let randomKey = function (): string {
|
||||
let retval = "";
|
||||
let legalcharacters =
|
||||
"1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
for (let i = 0; i < 16; i++) {
|
||||
retval +=
|
||||
legalcharacters[Math.floor(Math.random() * legalcharacters.length)];
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
const updateField = useCallback(
|
||||
(field: string, value: any) => {
|
||||
updateAddField("identityProvider", field, value);
|
||||
},
|
||||
[updateAddField]
|
||||
);
|
||||
const updateUserField = (index: number, value: string) => {
|
||||
const newUserField = [...accessKeys];
|
||||
newUserField[index] = value;
|
||||
updateField("accessKeys", newUserField);
|
||||
};
|
||||
const updatePwordField = (index: number, value: string) => {
|
||||
const newUserField = [...secretKeys];
|
||||
newUserField[index] = value;
|
||||
updateField("secretKeys", newUserField);
|
||||
};
|
||||
|
||||
const cleanValidation = (fieldName: string) => {
|
||||
setValidationErrors(clearValidationError(validationErrors, fieldName));
|
||||
@@ -95,10 +128,23 @@ const IdentityProvider = ({
|
||||
let customIDPValidation: IValidation[] = [];
|
||||
|
||||
if (idpSelection === "Built-in") {
|
||||
isPageValid("identityProvider", true);
|
||||
setValidationErrors({});
|
||||
|
||||
return;
|
||||
customIDPValidation = [...customIDPValidation];
|
||||
for (var i = 0; i < accessKeys.length; i++) {
|
||||
customIDPValidation.push({
|
||||
fieldKey: `accesskey-${i.toString()}`,
|
||||
required: true,
|
||||
value: accessKeys[i],
|
||||
pattern: /^[a-zA-Z0-9-]{8,63}$/,
|
||||
customPatternMessage: "Keys must be at least length 8",
|
||||
});
|
||||
customIDPValidation.push({
|
||||
fieldKey: `secretkey-${i.toString()}`,
|
||||
required: true,
|
||||
value: secretKeys[i],
|
||||
pattern: /^[a-zA-Z0-9-]{8,63}$/,
|
||||
customPatternMessage: "Keys must be at least length 8",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (idpSelection === "OpenID") {
|
||||
@@ -160,6 +206,8 @@ const IdentityProvider = ({
|
||||
setValidationErrors(commonVal);
|
||||
}, [
|
||||
idpSelection,
|
||||
accessKeys,
|
||||
secretKeys,
|
||||
openIDURL,
|
||||
openIDClientID,
|
||||
openIDSecretID,
|
||||
@@ -170,7 +218,52 @@ const IdentityProvider = ({
|
||||
ADNameAttribute,
|
||||
isPageValid,
|
||||
]);
|
||||
|
||||
let inputs = null;
|
||||
if (idpSelection === "Built-in") {
|
||||
inputs = accessKeys.map((element, index) => {
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={classes.shortened}>
|
||||
<InputBoxWrapper
|
||||
id={`accesskey-${index.toString()}`}
|
||||
label={"Access Key"}
|
||||
name={`accesskey-${index.toString()}`}
|
||||
value={accessKeys[index]}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updateUserField(index, e.target.value);
|
||||
cleanValidation(`accesskey-${index.toString()}`);
|
||||
}}
|
||||
index={index}
|
||||
key={`csv-accesskey-${index.toString()}`}
|
||||
error={validationErrors[`accesskey-${index.toString()}`] || ""}
|
||||
/>
|
||||
<InputBoxWrapper
|
||||
id={`secretkey-${index.toString()}`}
|
||||
label={"Secret Key"}
|
||||
name={`secretkey-${index.toString()}`}
|
||||
value={secretKeys[index]}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updatePwordField(index, e.target.value);
|
||||
cleanValidation(`secretkey-${index.toString()}`);
|
||||
}}
|
||||
index={index}
|
||||
key={`csv-secretkey-${index.toString()}`}
|
||||
error={validationErrors[`secretkey-${index.toString()}`] || ""}
|
||||
/>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
updateUserField(index, randomKey());
|
||||
updatePwordField(index, randomKey());
|
||||
}}
|
||||
>
|
||||
<CasinoIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
<br />
|
||||
</Fragment>
|
||||
);
|
||||
});
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={classes.headerElement}>
|
||||
@@ -196,8 +289,22 @@ const IdentityProvider = ({
|
||||
]}
|
||||
/>
|
||||
MinIO supports both OpenID and Active Directory
|
||||
</Grid>
|
||||
|
||||
<Button
|
||||
onClick={() => {
|
||||
accessKeys.push("");
|
||||
secretKeys.push("");
|
||||
updateUserField(accessKeys.length - 1, "");
|
||||
updatePwordField(secretKeys.length - 1, "");
|
||||
}}
|
||||
startIcon={<CreateIcon />}
|
||||
className={classes.buttonList}
|
||||
color="primary"
|
||||
variant="contained"
|
||||
>
|
||||
Add accesskey/secretkey pair
|
||||
</Button>
|
||||
</Grid>{" "}
|
||||
{idpSelection === "Built-in" && <Fragment>{inputs}</Fragment>}
|
||||
{idpSelection === "OpenID" && (
|
||||
<Fragment>
|
||||
<Grid item xs={12}>
|
||||
@@ -367,6 +474,8 @@ const IdentityProvider = ({
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
idpSelection: state.tenants.createTenant.fields.identityProvider.idpSelection,
|
||||
accessKeys: state.tenants.createTenant.fields.identityProvider.accessKeys,
|
||||
secretKeys: state.tenants.createTenant.fields.identityProvider.secretKeys,
|
||||
openIDURL: state.tenants.createTenant.fields.identityProvider.openIDURL,
|
||||
openIDClientID:
|
||||
state.tenants.createTenant.fields.identityProvider.openIDClientID,
|
||||
|
||||
@@ -70,10 +70,12 @@ const initialState: ITenantState = {
|
||||
prometheusVolumeSize: "5",
|
||||
prometheusSizeFactor: "Gi",
|
||||
logSearchSelectedStorageClass: "",
|
||||
prometheusSelectedStorageClass: "",
|
||||
prometheusSelectedStorageClass: "",
|
||||
},
|
||||
identityProvider: {
|
||||
idpSelection: "Built-in",
|
||||
accessKeys: [""],
|
||||
secretKeys: [""],
|
||||
openIDURL: "",
|
||||
openIDClientID: "",
|
||||
openIDSecretID: "",
|
||||
@@ -459,6 +461,8 @@ export function tenantsReducer(
|
||||
},
|
||||
identityProvider: {
|
||||
idpSelection: "Built-in",
|
||||
accessKeys: [""],
|
||||
secretKeys: [""],
|
||||
openIDURL: "",
|
||||
openIDClientID: "",
|
||||
openIDSecretID: "",
|
||||
|
||||
@@ -110,6 +110,8 @@ export interface IConfigureFields {
|
||||
|
||||
export interface IIdentityProviderFields {
|
||||
idpSelection: string;
|
||||
accessKeys: string[];
|
||||
secretKeys: string[];
|
||||
openIDURL: string;
|
||||
openIDClientID: string;
|
||||
openIDSecretID: string;
|
||||
|
||||
@@ -540,8 +540,8 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
}
|
||||
|
||||
ns := *tenantReq.Namespace
|
||||
|
||||
// if access/secret are provided, use them, else create a random pair
|
||||
|
||||
accessKey := RandomCharString(16)
|
||||
secretKey := RandomCharString(32)
|
||||
|
||||
@@ -555,24 +555,48 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
tenantName := *tenantReq.Name
|
||||
secretName := fmt.Sprintf("%s-secret", tenantName)
|
||||
imm := true
|
||||
|
||||
instanceSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName,
|
||||
Labels: map[string]string{
|
||||
miniov2.TenantLabel: tenantName,
|
||||
var instanceSecret corev1.Secret
|
||||
var users []*corev1.LocalObjectReference
|
||||
if !(len(tenantReq.Idp.Keys) > 0) {
|
||||
instanceSecret = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName,
|
||||
Labels: map[string]string{
|
||||
miniov2.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
},
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"accesskey": []byte(accessKey),
|
||||
"secretkey": []byte(secretKey),
|
||||
},
|
||||
}
|
||||
|
||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"accesskey": []byte(accessKey),
|
||||
"secretkey": []byte(secretKey),
|
||||
},
|
||||
}
|
||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
}
|
||||
} else {
|
||||
users = append(users, &corev1.LocalObjectReference{Name: secretName})
|
||||
for i := 0; i < len(tenantReq.Idp.Keys); i++ {
|
||||
users = append(users, &corev1.LocalObjectReference{Name: fmt.Sprintf("%s%d", secretName, i)})
|
||||
instanceSecret = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("%s%d", secretName, i),
|
||||
Labels: map[string]string{
|
||||
miniov2.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"CONSOLE_ACCESS_KEY": []byte(*tenantReq.Idp.Keys[i].AccessKey),
|
||||
"CONSOLE_SECRET_KEY": []byte(*tenantReq.Idp.Keys[i].SecretKey),
|
||||
},
|
||||
}
|
||||
_, err := clientSet.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// delete secrets created if an error occurred during tenant creation,
|
||||
defer func() {
|
||||
@@ -616,6 +640,9 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
},
|
||||
}
|
||||
idpEnabled := false
|
||||
if len(tenantReq.Idp.Keys) > 0 {
|
||||
minInst.Spec.Users = users
|
||||
}
|
||||
// Enable IDP (Active Directory) for MinIO
|
||||
if tenantReq.Idp != nil && tenantReq.Idp.ActiveDirectory != nil {
|
||||
url := *tenantReq.Idp.ActiveDirectory.URL
|
||||
@@ -749,18 +776,36 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
|
||||
if enableConsole {
|
||||
// provision initial user for tenant
|
||||
tenantUserAccessKey = RandomCharString(16)
|
||||
tenantUserSecretKey = RandomCharString(32)
|
||||
consoleUserSecretName := fmt.Sprintf("%s-user-secret", tenantName)
|
||||
consoleUserSecretData := map[string][]byte{
|
||||
"CONSOLE_ACCESS_KEY": []byte(tenantUserAccessKey),
|
||||
"CONSOLE_SECRET_KEY": []byte(tenantUserSecretKey),
|
||||
if !(len(tenantReq.Idp.Keys) > 0) {
|
||||
tenantUserAccessKey = RandomCharString(16)
|
||||
tenantUserSecretKey = RandomCharString(32)
|
||||
consoleUserSecretName := fmt.Sprintf("%s-user-secret", tenantName)
|
||||
consoleUserSecretData := map[string][]byte{
|
||||
"CONSOLE_ACCESS_KEY": []byte(tenantUserAccessKey),
|
||||
"CONSOLE_SECRET_KEY": []byte(tenantUserSecretKey),
|
||||
}
|
||||
_, err := createOrReplaceSecrets(ctx, &k8sClient, ns, []tenantSecret{{Name: consoleUserSecretName, Content: consoleUserSecretData}}, tenantName)
|
||||
if err != nil {
|
||||
return nil, prepareError(errorGeneric, nil, err)
|
||||
}
|
||||
minInst.Spec.Users = []*corev1.LocalObjectReference{{Name: consoleUserSecretName}}
|
||||
} else {
|
||||
tenantUserAccessKey = *tenantReq.Idp.Keys[0].AccessKey
|
||||
tenantUserSecretKey = *tenantReq.Idp.Keys[0].SecretKey
|
||||
for i := 0; i < len(tenantReq.Idp.Keys); i++ {
|
||||
userSecretName := fmt.Sprintf("%s-%d-user-secret", tenantName, i)
|
||||
userSecretData := map[string][]byte{
|
||||
"CONSOLE_ACCESS_KEY": []byte(*tenantReq.Idp.Keys[i].AccessKey),
|
||||
"CONSOLE_SECRET_KEY": []byte(*tenantReq.Idp.Keys[i].SecretKey),
|
||||
}
|
||||
_, err := createOrReplaceSecrets(ctx, &k8sClient, ns, []tenantSecret{{Name: userSecretName, Content: userSecretData}}, tenantName)
|
||||
if err != nil {
|
||||
return nil, prepareError(errorGeneric, nil, err)
|
||||
}
|
||||
minInst.Spec.Users = append(minInst.Spec.Users, &corev1.LocalObjectReference{Name: userSecretName})
|
||||
}
|
||||
|
||||
}
|
||||
_, err := createOrReplaceSecrets(ctx, &k8sClient, ns, []tenantSecret{{Name: consoleUserSecretName, Content: consoleUserSecretData}}, tenantName)
|
||||
if err != nil {
|
||||
return nil, prepareError(errorGeneric, nil, err)
|
||||
}
|
||||
minInst.Spec.Users = []*corev1.LocalObjectReference{{Name: consoleUserSecretName}}
|
||||
consoleSelector := fmt.Sprintf("%s-console", tenantName)
|
||||
consoleSecretName := fmt.Sprintf("%s-secret", consoleSelector)
|
||||
consoleSecretData := map[string][]byte{
|
||||
@@ -962,7 +1007,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
return nil, prepareError(err)
|
||||
}
|
||||
|
||||
// Integratrions
|
||||
// Integrations
|
||||
if os.Getenv("GKE_INTEGRATION") != "" {
|
||||
err := gkeIntegration(clientSet, tenantName, ns, session.STSSessionToken)
|
||||
if err != nil {
|
||||
|
||||
@@ -4308,6 +4308,24 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"keys": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"access_key",
|
||||
"secret_key"
|
||||
],
|
||||
"properties": {
|
||||
"access_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"secret_key": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"oidc": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -9717,6 +9735,21 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"IdpConfigurationKeysItems0": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"access_key",
|
||||
"secret_key"
|
||||
],
|
||||
"properties": {
|
||||
"access_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"secret_key": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"IdpConfigurationOidc": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -11000,6 +11033,12 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"keys": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/IdpConfigurationKeysItems0"
|
||||
}
|
||||
},
|
||||
"oidc": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
||||
12
swagger.yml
12
swagger.yml
@@ -3454,6 +3454,18 @@ definitions:
|
||||
type: string
|
||||
secret_id:
|
||||
type: string
|
||||
keys:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- access_key
|
||||
- secret_key
|
||||
properties:
|
||||
access_key:
|
||||
type: string
|
||||
secret_key:
|
||||
type: string
|
||||
active_directory:
|
||||
type: object
|
||||
required:
|
||||
|
||||
Reference in New Issue
Block a user