This commit changes the authentication mechanism between mcs and minio to an sts
(security token service) schema using the user provided credentials, previously
mcs was using master credentials. With that said in order for you to
login to MCS as an admin your user must exists first on minio and have enough
privileges to do administrative operations.
```
./mc admin user add myminio alevsk alevsk12345
```
```
cat admin.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"admin:*",
"s3:*"
],
"Resource": [
"arn:aws:s3:::*"
]
}
]
}
./mc admin policy add myminio admin admin.json
```
```
./mc admin policy set myminio admin user=alevsk
```
286 lines
10 KiB
Go
286 lines
10 KiB
Go
// 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 restapi
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"log"
|
|
|
|
"github.com/go-openapi/errors"
|
|
|
|
"github.com/go-openapi/runtime/middleware"
|
|
"github.com/go-openapi/swag"
|
|
"github.com/minio/mcs/models"
|
|
"github.com/minio/mcs/restapi/operations"
|
|
"github.com/minio/mcs/restapi/operations/admin_api"
|
|
iampolicy "github.com/minio/minio/pkg/iam/policy"
|
|
)
|
|
|
|
func registersPoliciesHandler(api *operations.McsAPI) {
|
|
// List Policies
|
|
api.AdminAPIListPoliciesHandler = admin_api.ListPoliciesHandlerFunc(func(params admin_api.ListPoliciesParams, principal *models.Principal) middleware.Responder {
|
|
sessionID := string(*principal)
|
|
listPoliciesResponse, err := getListPoliciesResponse(sessionID)
|
|
if err != nil {
|
|
return admin_api.NewListPoliciesDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
|
|
}
|
|
return admin_api.NewListPoliciesOK().WithPayload(listPoliciesResponse)
|
|
})
|
|
// Policy Info
|
|
api.AdminAPIPolicyInfoHandler = admin_api.PolicyInfoHandlerFunc(func(params admin_api.PolicyInfoParams, principal *models.Principal) middleware.Responder {
|
|
sessionID := string(*principal)
|
|
policyInfo, err := getPolicyInfoResponse(sessionID, params)
|
|
if err != nil {
|
|
return admin_api.NewPolicyInfoDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
|
|
}
|
|
return admin_api.NewPolicyInfoOK().WithPayload(policyInfo)
|
|
})
|
|
// Add Policy
|
|
api.AdminAPIAddPolicyHandler = admin_api.AddPolicyHandlerFunc(func(params admin_api.AddPolicyParams, principal *models.Principal) middleware.Responder {
|
|
sessionID := string(*principal)
|
|
policyResponse, err := getAddPolicyResponse(sessionID, params.Body)
|
|
if err != nil {
|
|
return admin_api.NewAddPolicyDefault(500).WithPayload(&models.Error{
|
|
Code: 500,
|
|
Message: swag.String(err.Error()),
|
|
})
|
|
}
|
|
return admin_api.NewAddPolicyCreated().WithPayload(policyResponse)
|
|
})
|
|
// Remove Policy
|
|
api.AdminAPIRemovePolicyHandler = admin_api.RemovePolicyHandlerFunc(func(params admin_api.RemovePolicyParams, principal *models.Principal) middleware.Responder {
|
|
sessionID := string(*principal)
|
|
if err := getRemovePolicyResponse(sessionID, params); err != nil {
|
|
return admin_api.NewRemovePolicyDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
|
|
}
|
|
return admin_api.NewRemovePolicyNoContent()
|
|
})
|
|
// Set Policy
|
|
api.AdminAPISetPolicyHandler = admin_api.SetPolicyHandlerFunc(func(params admin_api.SetPolicyParams, principal *models.Principal) middleware.Responder {
|
|
sessionID := string(*principal)
|
|
if err := getSetPolicyResponse(sessionID, params.Name, params.Body); err != nil {
|
|
return admin_api.NewSetPolicyDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
|
|
}
|
|
return admin_api.NewSetPolicyNoContent()
|
|
})
|
|
}
|
|
|
|
// listPolicies calls MinIO server to list all policy names present on the server.
|
|
// listPolicies() converts the map[string][]byte returned by client.listPolicies()
|
|
// to []*models.Policy by iterating over each key in policyRawMap and
|
|
// then using Unmarshal on the raw bytes to create a *models.Policy
|
|
func listPolicies(ctx context.Context, client MinioAdmin) ([]*models.Policy, error) {
|
|
policyMap, err := client.listPolicies(ctx)
|
|
var policies []*models.Policy
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for name, policy := range policyMap {
|
|
policy, err := parsePolicy(name, policy)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
policies = append(policies, policy)
|
|
}
|
|
return policies, nil
|
|
}
|
|
|
|
// getListPoliciesResponse performs listPolicies() and serializes it to the handler's output
|
|
func getListPoliciesResponse(sessionID string) (*models.ListPoliciesResponse, error) {
|
|
ctx := context.Background()
|
|
mAdmin, err := newMAdminClient(sessionID)
|
|
if err != nil {
|
|
log.Println("error creating Madmin Client:", err)
|
|
return nil, err
|
|
}
|
|
// create a MinIO Admin Client interface implementation
|
|
// defining the client to be used
|
|
adminClient := adminClient{client: mAdmin}
|
|
|
|
policies, err := listPolicies(ctx, adminClient)
|
|
if err != nil {
|
|
log.Println("error listing policies:", err)
|
|
return nil, err
|
|
}
|
|
// serialize output
|
|
listPoliciesResponse := &models.ListPoliciesResponse{
|
|
Policies: policies,
|
|
Total: int64(len(policies)),
|
|
}
|
|
return listPoliciesResponse, nil
|
|
}
|
|
|
|
// removePolicy() calls MinIO server to remove a policy based on name.
|
|
func removePolicy(ctx context.Context, client MinioAdmin, name string) error {
|
|
err := client.removePolicy(ctx, name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// getRemovePolicyResponse() performs removePolicy() and serializes it to the handler's output
|
|
func getRemovePolicyResponse(sessionID string, params admin_api.RemovePolicyParams) error {
|
|
ctx := context.Background()
|
|
if params.Name == "" {
|
|
log.Println("error policy name not in request")
|
|
return errors.New(500, "error policy name not in request")
|
|
}
|
|
mAdmin, err := newMAdminClient(sessionID)
|
|
if err != nil {
|
|
log.Println("error creating Madmin Client:", err)
|
|
return err
|
|
}
|
|
// create a MinIO Admin Client interface implementation
|
|
// defining the client to be used
|
|
adminClient := adminClient{client: mAdmin}
|
|
|
|
if err := removePolicy(ctx, adminClient, params.Name); err != nil {
|
|
log.Println("error removing policy:", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// addPolicy calls MinIO server to add a canned policy.
|
|
// addPolicy() takes name and policy in string format, policy
|
|
// policy must be string in json format, in the future this will change
|
|
// to a Policy struct{} - https://github.com/minio/minio/issues/9171
|
|
func addPolicy(ctx context.Context, client MinioAdmin, name, policy string) (*models.Policy, error) {
|
|
iamp, err := iampolicy.ParseConfig(bytes.NewReader([]byte(policy)))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := client.addPolicy(ctx, name, iamp); err != nil {
|
|
return nil, err
|
|
}
|
|
policyObject, err := policyInfo(ctx, client, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return policyObject, nil
|
|
}
|
|
|
|
// getAddPolicyResponse performs addPolicy() and serializes it to the handler's output
|
|
func getAddPolicyResponse(sessionID string, params *models.AddPolicyRequest) (*models.Policy, error) {
|
|
ctx := context.Background()
|
|
if params == nil {
|
|
log.Println("error AddPolicy body not in request")
|
|
return nil, errors.New(500, "error AddPolicy body not in request")
|
|
}
|
|
|
|
mAdmin, err := newMAdminClient(sessionID)
|
|
if err != nil {
|
|
log.Println("error creating Madmin Client:", err)
|
|
return nil, err
|
|
}
|
|
// create a MinIO Admin Client interface implementation
|
|
// defining the client to be used
|
|
adminClient := adminClient{client: mAdmin}
|
|
policy, err := addPolicy(ctx, adminClient, *params.Name, *params.Policy)
|
|
if err != nil {
|
|
log.Println("error adding policy")
|
|
return nil, err
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// policyInfo calls MinIO server to retrieve information of a canned policy.
|
|
// policyInfo() takes a policy name, obtains the []byte (represents a string in JSON format)
|
|
// and return it as *models.Policy , in the future this will change
|
|
// to a Policy struct{} - https://github.com/minio/minio/issues/9171
|
|
func policyInfo(ctx context.Context, client MinioAdmin, name string) (*models.Policy, error) {
|
|
policyRaw, err := client.getPolicy(ctx, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
policy, err := parsePolicy(name, policyRaw)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// getPolicyInfoResponse performs policyInfo() and serializes it to the handler's output
|
|
func getPolicyInfoResponse(sessionID string, params admin_api.PolicyInfoParams) (*models.Policy, error) {
|
|
ctx := context.Background()
|
|
mAdmin, err := newMAdminClient(sessionID)
|
|
if err != nil {
|
|
log.Println("error creating Madmin Client:", err)
|
|
return nil, err
|
|
}
|
|
// create a MinIO Admin Client interface implementation
|
|
// defining the client to be used
|
|
adminClient := adminClient{client: mAdmin}
|
|
policy, err := policyInfo(ctx, adminClient, params.Name)
|
|
if err != nil {
|
|
log.Println("error getting group info:", err)
|
|
return nil, err
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// setPolicy() calls MinIO server to assign policy to a group or user.
|
|
func setPolicy(ctx context.Context, client MinioAdmin, name, entityName string, entityType models.PolicyEntity) error {
|
|
isGroup := false
|
|
if entityType == models.PolicyEntityGroup {
|
|
isGroup = true
|
|
}
|
|
if err := client.setPolicy(ctx, name, entityName, isGroup); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// getSetPolicyResponse() performs setPolicy() and serializes it to the handler's output
|
|
func getSetPolicyResponse(sessionID string, name string, params *models.SetPolicyRequest) error {
|
|
ctx := context.Background()
|
|
if name == "" {
|
|
log.Println("error policy name not in request")
|
|
return errors.New(500, "error policy name not in request")
|
|
}
|
|
mAdmin, err := newMAdminClient(sessionID)
|
|
if err != nil {
|
|
log.Println("error creating Madmin Client:", err)
|
|
return err
|
|
}
|
|
// create a MinIO Admin Client interface implementation
|
|
// defining the client to be used
|
|
adminClient := adminClient{client: mAdmin}
|
|
|
|
if err := setPolicy(ctx, adminClient, name, *params.EntityName, params.EntityType); err != nil {
|
|
log.Println("error setting policy:", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// parsePolicy() converts from *rawPolicy to *models.Policy
|
|
func parsePolicy(name string, rawPolicy *iampolicy.Policy) (*models.Policy, error) {
|
|
stringPolicy, err := json.Marshal(rawPolicy)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
policy := &models.Policy{
|
|
Name: name,
|
|
Policy: string(stringPolicy),
|
|
}
|
|
return policy, nil
|
|
}
|