Compare commits

...

9 Commits

Author SHA1 Message Date
Minio Trusted
8a4139c8e7 update to v0.6.2 2021-02-26 13:01:28 -08:00
Lenin Alevski
34bcd25c9f Disable Users and Groups Menu options when LDAP is enabled on MinIO (#614) 2021-02-26 11:20:17 -08:00
Minio Trusted
7853aa6bb9 update to v0.6.1 2021-02-25 10:20:32 -08:00
Lenin Alevski
9c1f0c47b0 Custom HTTP Client TLS transport for STSWebIdentity (#612)
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2021-02-25 09:09:55 -08:00
Daniel Valdivia
6ac95e40a4 Get Tenants endpoints check hostname (#609) 2021-02-23 12:49:46 -08:00
Joshua Hoblitt
70fb7291f5 fix docker "dev" tag string (#611) 2021-02-23 10:28:05 -08:00
Lenin Alevski
4b28bf5921 New design for License Page (#608) 2021-02-22 16:41:17 -08:00
jinapurapu
99d5e71512 Added refresh tenant functionality (#604)
* Added refresh tenant functionality

* Delete bindata.go

Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-02-18 17:33:00 -08:00
Minio Trusted
2a5c1afbdf release console version v0.6.0 2021-02-18 12:23:47 -08:00
20 changed files with 524 additions and 388 deletions

View File

@@ -3,7 +3,7 @@
project_name: console
release:
name_template: "Release version {{.Version}}"
name_template: "Release version {{.Tag}}"
github:
owner: minio
name: console
@@ -27,8 +27,6 @@ builds:
- s390x
- arm64
ignore:
- goos: darwin
goarch: arm64
- goos: darwin
goarch: arm
- goos: windows
@@ -85,6 +83,7 @@ dockers:
- image_templates:
- "minio/console:{{ .Tag }}-amd64"
use_buildx: true
goarch: amd64
dockerfile: Dockerfile.release
extra_files:
- LICENSE
@@ -94,6 +93,7 @@ dockers:
- image_templates:
- "minio/console:{{ .Tag }}-ppc64le"
use_buildx: true
goarch: ppc64le
dockerfile: Dockerfile.release
extra_files:
- LICENSE
@@ -103,6 +103,7 @@ dockers:
- image_templates:
- "minio/console:{{ .Tag }}-s390x"
use_buildx: true
goarch: s390x
dockerfile: Dockerfile.release
extra_files:
- LICENSE
@@ -113,6 +114,7 @@ dockers:
- "minio/console:{{ .Tag }}-arm64"
use_buildx: true
goarch: arm64
goos: linux
dockerfile: Dockerfile.release
extra_files:
- LICENSE

View File

@@ -6,8 +6,8 @@ COPY LICENSE /licenses/LICENSE
LABEL name="MinIO" \
vendor="MinIO Inc <dev@min.io>" \
maintainer="MinIO Inc <dev@min.io>" \
version="v0.5.2" \
release="v0.5.2" \
version="v0.6.2" \
release="v0.6.2" \
summary="A graphical user interface for MinIO" \
description="MinIO object storage is fundamentally different. Designed for performance and the S3 API, it is 100% open-source. MinIO is ideal for large, private cloud environments with stringent security requirements and delivers mission-critical availability across a diverse range of workloads."

View File

@@ -3,7 +3,7 @@ GOPATH := $(shell go env GOPATH)
# Sets the build version based on the output of the following command, if we are building for a tag, that's the build else it uses the current git branch as the build
BUILD_VERSION:=$(shell git describe --exact-match --tags $(git log -n1 --pretty='%h') 2>/dev/null || git rev-parse --abbrev-ref HEAD 2>/dev/null)
BUILD_TIME:=$(shell date 2>/dev/null)
TAG ?= "minio/console:$(VERSION)-dev"
TAG ?= "minio/console:$(BUILD_VERSION)-dev"
default: console

View File

@@ -15,7 +15,7 @@ spec:
serviceAccountName: console-sa
containers:
- name: console
image: minio/console:v0.5.2
image: minio/console:v0.6.2
imagePullPolicy: "IfNotPresent"
args:
- server

View File

@@ -15,7 +15,7 @@ spec:
serviceAccountName: console-sa
containers:
- name: console
image: minio/console:v0.5.2
image: minio/console:v0.6.2
imagePullPolicy: "IfNotPresent"
env:
- name: CONSOLE_OPERATOR_MODE

View File

@@ -26,3 +26,7 @@ import (
func GetOperatorMode() bool {
return strings.ToLower(env.Get(consoleOperatorMode, "off")) == "on"
}
func GetLDAPEnabled() bool {
return strings.ToLower(env.Get(ConsoleLDAPEnabled, "off")) == "on"
}

View File

@@ -18,4 +18,6 @@ package acl
const (
consoleOperatorMode = "CONSOLE_OPERATOR_MODE"
// const for ldap configuration
ConsoleLDAPEnabled = "CONSOLE_LDAP_ENABLED"
)

View File

@@ -243,6 +243,17 @@ var healthInfoActionSet = ConfigurationActionSet{
),
}
var displayRules = map[string]func() bool{
// disable users page if LDAP is enabled
users: func() bool {
return !GetLDAPEnabled()
},
// disable groups page if LDAP is enabled
groups: func() bool {
return !GetLDAPEnabled()
},
}
// endpointRules contains the mapping between endpoints and ActionSets, additional rules can be added here
var endpointRules = map[string]ConfigurationActionSet{
configuration: configurationActionSet,
@@ -337,6 +348,15 @@ func GetAuthorizedEndpoints(actions []string) []string {
userAllowedAction := actionsStringToActionSet(actions)
var allowedEndpoints []string
for endpoint, rules := range rangeTake {
// check if display rule exists for this endpoint, this will control
// what user sees on the console UI
if rule, ok := displayRules[endpoint]; ok {
if rule != nil && !rule() {
continue
}
}
// check if user policy matches s3:* or admin:* typesIntersection
endpointActionTypes := rules.actionTypes
typesIntersection := endpointActionTypes.Intersection(userAllowedAction)

View File

@@ -91,9 +91,10 @@ type Provider struct {
// often available via site-specific packages, such as
// google.Endpoint or github.Endpoint.
// - Scopes specifies optional requested permissions.
ClientID string
oauth2Config Configuration
oidcProvider *oidc.Provider
ClientID string
oauth2Config Configuration
oidcProvider *oidc.Provider
provHTTPClient *http.Client
}
// derivedKey is the key used to compute the HMAC for signing the oauth state parameter
@@ -103,8 +104,9 @@ var derivedKey = pbkdf2.Key([]byte(getPassphraseForIdpHmac()), []byte(getSaltFor
// NewOauth2ProviderClient instantiates a new oauth2 client using the configured credentials
// it returns a *Provider object that contains the necessary configuration to initiate an
// oauth2 authentication flow
func NewOauth2ProviderClient(ctx context.Context, scopes []string) (*Provider, error) {
provider, err := oidc.NewProvider(ctx, GetIdpURL())
func NewOauth2ProviderClient(ctx context.Context, scopes []string, httpClient *http.Client) (*Provider, error) {
customCtx := oidc.ClientContext(ctx, httpClient)
provider, err := oidc.NewProvider(customCtx, GetIdpURL())
if err != nil {
return nil, err
}
@@ -122,6 +124,7 @@ func NewOauth2ProviderClient(ctx context.Context, scopes []string) (*Provider, e
}
client.oidcProvider = provider
client.ClientID = GetIdpClientID()
client.provHTTPClient = httpClient
return client, nil
}
@@ -172,10 +175,11 @@ func (client *Provider) VerifyIdentity(ctx context.Context, code, state string)
}, nil
}
stsEndpoint := GetSTSEndpoint()
sts, err := credentials.NewSTSWebIdentity(stsEndpoint, getWebTokenExpiry)
if err != nil {
return nil, err
}
sts := credentials.New(&credentials.STSWebIdentity{
Client: client.provHTTPClient,
STSEndpoint: stsEndpoint,
GetWebIDTokenExpiry: getWebTokenExpiry,
})
return sts, nil
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@@ -49,23 +49,22 @@ const styles = (theme: Theme) =>
},
licenseContainer: {
padding: "20px 52px 0px 28px",
background:
"transparent linear-gradient(180deg, #ffffff 0%, #d6e1e8 100%) 0% 0% no-repeat padding-box",
background: "#032F51",
boxShadow: "0px 3px 7px #00000014",
"& h2": {
color: "#000",
marginBottom: "50px",
color: "#FFF",
marginBottom: 67,
},
"& a": {
textDecoration: "none",
},
"& h3": {
color: "#000",
color: "#FFFFFF",
marginBottom: "30px",
fontWeight: "bold",
},
"& h6": {
color: "#000 !important",
color: "#FFFFFF !important",
},
},
tableContainer: {
@@ -81,26 +80,29 @@ const styles = (theme: Theme) =>
detailsContainerBorder: {
border: "1px solid #e2e2e2",
borderBottom: 0,
borderRadius: "4px 4px 0px 0px",
},
detailsContainerBorderHighlighted: {
border: "1px solid #9a93ad",
border: "1px solid #B5B5B5",
borderBottom: 0,
},
detailsTitle: {
fontSize: 17,
fontSize: 19,
fontWeight: 700,
marginBottom: 26,
paddingTop: 18,
},
currentPlan: {
fontWeight: 700,
background:
"transparent linear-gradient(90deg, #073052 0%, #081C42 100%) 0% 0% no-repeat padding-box",
boxShadow: "0px 3px 7px #00000014",
color: "#fff",
background: "#D5DDE5",
borderRadius: "3px 3px 0px 0px",
color: "#121212",
padding: 8,
borderTop: "1px solid #D5DDE5",
marginTop: -2,
},
detailsPrice: {
fontSize: 12,
fontSize: 13,
fontWeight: 700,
marginBottom: 8,
},
@@ -110,18 +112,15 @@ const styles = (theme: Theme) =>
fontWeight: 700,
marginBottom: 12,
padding: "0% 15%",
color: "#474747",
},
detailsCapacityMin: {
fontSize: 10,
},
itemContainer: {
height: 36,
borderTop: "1px solid #e5e5e5",
},
itemContainerDetail: {
height: 48,
borderTop: "1px solid #e5e5e5",
},
item: {
height: "100%",
@@ -135,18 +134,20 @@ const styles = (theme: Theme) =>
alignContent: "center",
marginLeft: 8,
maxWidth: "calc(25% - 8px)",
borderTop: "1px solid #e5e5e5",
},
itemFirst: {
borderLeft: 0,
borderRight: 0,
},
itemHighlighted: {
borderLeft: "1px solid #9a93ad",
borderRight: "1px solid #9a93ad",
borderLeft: "1px solid #B5B5B5",
borderRight: "1px solid #B5B5B5",
},
field: {
textAlign: "left",
fontWeight: 400,
fontSize: 12,
},
checkIcon: {
height: 12,
@@ -169,7 +170,7 @@ const styles = (theme: Theme) =>
border: 0,
},
buttonContainerHighlighted: {
border: "1px solid #000",
border: "1px solid #B5B5B5",
borderTop: 0,
},
button: {
@@ -210,20 +211,36 @@ const styles = (theme: Theme) =>
height: "100%",
borderRadius: "0px 3px 0px 0px !important",
},
licenseInfo: { color: "#000" },
licenseInfo: { color: "#FFFFFF" },
licenseInfoTitle: {
textTransform: "none",
color: "#000",
color: "#FFFFFF",
},
licenseInfoValue: {
textTransform: "none",
fontSize: 17,
},
licenseDescription: {
background: "#fff",
background: "#032F51",
padding: "30px 30px",
border: "1px solid #e2e5e4",
borderRadius: "5px 5px 0px 0px",
borderTop: "1px solid #e2e5e4",
borderLeft: "1px solid #e2e5e4",
borderRight: "1px solid #e2e5e4",
},
currentPlanBG: {
background: "#022A4A 0% 0% no-repeat padding-box",
color: "#FFFFFF",
borderTop: "1px solid #52687d",
},
currentPlanButton: {
background: "#FFFFFF",
color: "#022A4A",
"&:hover": {
background: "#FFFFFF",
},
},
planItemsPadding: {
padding: "23px 33px",
},
...containerForHeader(theme.spacing(4)),
});
@@ -269,6 +286,7 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
</Grid>
);
}
let currentPlanID = 0;
return (
<React.Fragment>
<React.Fragment>
@@ -387,7 +405,7 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
</React.Fragment>
) : (
<React.Fragment>
<img src="agpl.png" height={40} alt="agpl" />
<img src="agpl.svg" height={40} alt="agpl" />
<Typography component="h2" variant="h6">
GNU Affero General Public License
</Typography>
@@ -422,9 +440,9 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
If you are building proprietary applications, you may want to
choose the commercial license included as part of the Standard
and Enterprise subscription plans. Applications must otherwise
comply with all GNU AGPLv3 obligations and requirements. Click
the link below to learn more about Open Source license
compliance.
comply with all the GNU AGPLv3 License & Trademark
obligations. Follow the links below to learn more about the
compliance policy.
</Typography>
<br />
<a
@@ -435,14 +453,23 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
>
Open Source Policy Compliance
</a>
<br />
<br />
<a
href="https://min.io/logo"
className={classes.openSourcePolicy}
target="_blank"
rel="nofollow noopener noreferrer"
>
Trademark Policy
</a>
</Paper>
)}
</Grid>
<Grid
item
xs={12}
className={classes.container}
style={{ padding: "0px 33px" }}
className={clsx(classes.container, classes.planItemsPadding)}
>
<Paper
className={classes.paper}
@@ -459,6 +486,11 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
<Grid container item xs={12}>
<Grid item xs={3} className={classes.detailsContainer} />
{planDetails.map((details: any) => {
let currentPlan =
(!licenseInfo && details.title === "Community") ||
(licenseInfo &&
licenseInfo.plan.toLowerCase() ===
details.title.toLowerCase());
return (
<Grid
key={details.id}
@@ -471,13 +503,11 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
{
[classes.detailsContainerBorderHighlighted]:
details.title !== "Community",
}
},
currentPlan ? classes.currentPlanBG : ""
)}
>
{(!licenseInfo && details.title === "Community") ||
(licenseInfo &&
licenseInfo.plan.toLowerCase() ===
details.title.toLowerCase()) ? (
{currentPlan ? (
<Grid item xs={12} className={classes.currentPlan}>
Current Plan
</Grid>
@@ -495,13 +525,6 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
>
{details.capacityMax || ""}
</Grid>
<Grid
item
xs={12}
className={classes.detailsCapacityMin}
>
{details.capacityMin}
</Grid>
</Grid>
);
})}
@@ -529,7 +552,15 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
>
{item.field}
</Grid>
<Grid container item xs={3} className={classes.item}>
<Grid
container
item
xs={3}
className={clsx(
classes.item,
currentPlanID === 0 ? classes.currentPlanBG : ""
)}
>
<Grid item xs={12}>
{item.community === "N/A" ? (
""
@@ -551,7 +582,8 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
xs={3}
className={clsx(
classes.item,
classes.itemHighlighted
classes.itemHighlighted,
currentPlanID === 1 ? classes.currentPlanBG : ""
)}
>
<Grid item xs={12}>
@@ -563,11 +595,6 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
item.standard
)}
</Grid>
{item.standardDetail !== undefined && (
<Grid item xs={12}>
{item.standardDetail}
</Grid>
)}
</Grid>
<Grid
container
@@ -575,7 +602,8 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
xs={3}
className={clsx(
classes.item,
classes.itemHighlighted
classes.itemHighlighted,
currentPlanID === 2 ? classes.currentPlanBG : ""
)}
>
<Grid item xs={12}>
@@ -587,11 +615,6 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
item.enterprise
)}
</Grid>
{item.enterpriseDetail !== undefined && (
<Grid item xs={12}>
{item.enterpriseDetail}
</Grid>
)}
</Grid>
</Grid>
);
@@ -605,7 +628,7 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
classes.buttonContainerBlank
)}
/>
{planButtons.map((button: any) => {
{planButtons.map((button: any, index: any) => {
return (
<Grid
key={button.id}
@@ -613,16 +636,27 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
item
xs={3}
style={{ textAlign: "center" }}
className={clsx(classes.buttonContainer, {
[classes.buttonContainerHighlighted]:
button.text === "Subscribe",
})}
className={clsx(
classes.buttonContainer,
currentPlanID === index
? classes.currentPlanBG
: "",
{
[classes.buttonContainerHighlighted]:
button.text === "Subscribe",
}
)}
>
<Grid item xs={12}>
<Button
variant="contained"
color="primary"
className={classes.button}
className={clsx(
classes.button,
currentPlanID === index
? classes.currentPlanButton
: ""
)}
target="_blank"
rel="noopener noreferrer"
href="#"

View File

@@ -18,22 +18,22 @@ export const planDetails = [
{
id: 0,
title: "Community",
price: "Free",
capacityMin: "(No minimum)",
price: "Open Source",
capacityMin: "",
},
{
id: 1,
title: "Standard",
price: "$10/TB/month",
capacityMax: "Up to 10PB. No additional charges for capacity over 10PB",
capacityMin: "(25TB minimum)",
capacityMin: "",
},
{
id: 2,
title: "Enterprise",
price: "$20/TB/month",
capacityMax: "Up to 5PB. No additional charges for capacity over 5PB",
capacityMin: "(100TB minimum)",
capacityMin: "",
},
];
@@ -41,12 +41,12 @@ export const planItems = [
{
id: 0,
field: "License",
community: "100% Open Source",
communityDetail: "Apache License v2, GNU AGPL v3",
standard: "Dual License",
standardDetail: "Commercial + Open Source",
enterprise: "Dual License",
enterpriseDetail: "Commercial + Open Source",
community: "GNU AGPL v3",
communityDetail: "",
standard: "Commercial License",
standardDetail: "",
enterprise: "Commercial License",
enterpriseDetail: "",
},
{
id: 1,

View File

@@ -154,7 +154,8 @@ const TenantDetails = ({
setAddPool(false);
if (reload) {
console.log("reload");
loadInfo();
loadUsage();
}
};
@@ -166,7 +167,8 @@ const TenantDetails = ({
setAddReplicationOpen(false);
if (reload) {
console.log("reload");
loadInfo();
loadUsage();
}
};

View File

@@ -404,10 +404,22 @@ func getTenantInfoResponse(session *models.Principal, params admin_api.TenantInf
var minioEndpoint string
var consoleEndpoint string
if minSvc != nil && len(minSvc.Status.LoadBalancer.Ingress) > 0 {
minioEndpoint = fmt.Sprintf("%s://%s", schema, minSvc.Status.LoadBalancer.Ingress[0].IP)
if minSvc.Status.LoadBalancer.Ingress[0].IP != "" {
minioEndpoint = fmt.Sprintf("%s://%s", schema, minSvc.Status.LoadBalancer.Ingress[0].IP)
}
if minSvc.Status.LoadBalancer.Ingress[0].Hostname != "" {
minioEndpoint = fmt.Sprintf("%s://%s", schema, minSvc.Status.LoadBalancer.Ingress[0].Hostname)
}
}
if conSvc != nil && len(conSvc.Status.LoadBalancer.Ingress) > 0 {
consoleEndpoint = fmt.Sprintf("%s://%s%s", consoleSchema, conSvc.Status.LoadBalancer.Ingress[0].IP, consolePort)
if conSvc.Status.LoadBalancer.Ingress[0].IP != "" {
consoleEndpoint = fmt.Sprintf("%s://%s%s", consoleSchema, conSvc.Status.LoadBalancer.Ingress[0].IP, consolePort)
}
if conSvc.Status.LoadBalancer.Ingress[0].Hostname != "" {
consoleEndpoint = fmt.Sprintf("%s://%s%s", consoleSchema, conSvc.Status.LoadBalancer.Ingress[0].Hostname, consolePort)
}
}
if minioEndpoint != "" || consoleEndpoint != "" {
info.Endpoints = &models.TenantEndpoints{

View File

@@ -1028,7 +1028,7 @@ func Test_UpdateTenantAction(t *testing.T) {
},
params: admin_api.UpdateTenantParams{
Body: &models.UpdateTenantRequest{
ConsoleImage: "minio/console:v0.5.2",
ConsoleImage: "minio/console:v0.6.2",
},
},
},

View File

@@ -63,7 +63,7 @@ const (
// Image versions
const (
KESImageVersion = "minio/kes:v0.13.4"
ConsoleImageDefaultVersion = "minio/console:v0.5.2"
ConsoleImageDefaultVersion = "minio/console:v0.6.2"
)
// K8s

View File

@@ -187,7 +187,7 @@ func getLoginDetailsResponse() (*models.LoginDetails, *models.Error) {
if oauth2.IsIdpEnabled() {
loginStrategy = models.LoginDetailsLoginStrategyRedirect
// initialize new oauth2 client
oauth2Client, err := oauth2.NewOauth2ProviderClient(ctx, nil)
oauth2Client, err := oauth2.NewOauth2ProviderClient(ctx, nil, GetConsoleSTSClient())
if err != nil {
return nil, prepareError(err)
}
@@ -235,7 +235,7 @@ func getLoginOauth2AuthResponse(lr *models.LoginOauth2AuthRequest) (*models.Logi
return loginResponse, nil
} else if oauth2.IsIdpEnabled() {
// initialize new oauth2 client
oauth2Client, err := oauth2.NewOauth2ProviderClient(ctx, nil)
oauth2Client, err := oauth2.NewOauth2ProviderClient(ctx, nil, GetConsoleSTSClient())
if err != nil {
return nil, prepareError(err)
}

View File

@@ -58,7 +58,9 @@ func registerServiceAccountsHandlers(api *operations.ConsoleAPI) {
// createServiceAccount adds a service account to the userClient and assigns a policy to him if defined.
func createServiceAccount(ctx context.Context, userClient MinioAdmin, policy string) (*models.ServiceAccountCreds, error) {
iamPolicy := &iampolicy.Policy{}
// By default a nil policy will be used so the service account inherit the parent account policy, otherwise
// we override with the user provided iam policy
var iamPolicy *iampolicy.Policy
if strings.TrimSpace(policy) != "" {
iamp, err := iampolicy.ParseConfig(bytes.NewReader([]byte(policy)))
if err != nil {