// Copyright 2020 IBM Corp. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package kp import ( "context" "fmt" "net/url" "time" ) const ( policyType = "application/vnd.ibm.kms.policy+json" RotationPolicy = "rotation" ) // Policy represents a policy as returned by the KP API. type Policy struct { Type string `json:"type,omitempty"` CreatedBy string `json:"createdBy,omitempty"` CreatedAt *time.Time `json:"creationDate,omitempty"` CRN string `json:"crn,omitempty"` UpdatedAt *time.Time `json:"lastUpdateDate,omitempty"` UpdatedBy string `json:"updatedBy,omitempty"` Rotation *Rotation `json:"rotation,omitempty"` DualAuth *DualAuth `json:"dualAuthDelete,omitempty"` } type Rotation struct { Interval int `json:"interval_month,omitempty"` } type DualAuth struct { Enabled *bool `json:"enabled,omitempty"` } // PoliciesMetadata represents the metadata of a collection of keys. type PoliciesMetadata struct { CollectionType string `json:"collectionType"` NumberOfPolicies int `json:"collectionTotal"` } // Policies represents a collection of Policies. type Policies struct { Metadata PoliciesMetadata `json:"metadata"` Policies []Policy `json:"resources"` } // GetPolicy retrieves a policy by Key ID. This function is // deprecated, as it only returns one policy and does not let you // select which policy set it will return. It is kept for backward // compatibility on keys with only one rotation policy. Please update // to use the new GetPolicies or GetPolicy functions. func (c *Client) GetPolicy(ctx context.Context, id string) (*Policy, error) { policyresponse := Policies{} req, err := c.newRequest("GET", fmt.Sprintf("keys/%s/policies", id), nil) if err != nil { return nil, err } _, err = c.do(ctx, req, &policyresponse) if err != nil { return nil, err } return &policyresponse.Policies[0], nil } // SetPolicy updates a policy resource by specifying the ID of the key and // the rotation interval needed. This function is deprecated as it will only // let you set key rotation policies. To set dual auth and other newer policies // on a key, please use the new SetPolicies of SetPolicy functions. func (c *Client) SetPolicy(ctx context.Context, id string, prefer PreferReturn, rotationInterval int) (*Policy, error) { policy := Policy{ Type: policyType, Rotation: &Rotation{ Interval: rotationInterval, }, } policyRequest := Policies{ Metadata: PoliciesMetadata{ CollectionType: policyType, NumberOfPolicies: 1, }, Policies: []Policy{policy}, } policyresponse := Policies{} req, err := c.newRequest("PUT", fmt.Sprintf("keys/%s/policies", id), &policyRequest) if err != nil { return nil, err } req.Header.Set("Prefer", preferHeaders[prefer]) _, err = c.do(ctx, req, &policyresponse) if err != nil { return nil, err } return &policyresponse.Policies[0], nil } // GetPolicies retrieves all policies details associated with a Key ID. func (c *Client) GetPolicies(ctx context.Context, id string) ([]Policy, error) { policyresponse := Policies{} req, err := c.newRequest("GET", fmt.Sprintf("keys/%s/policies", id), nil) if err != nil { return nil, err } _, err = c.do(ctx, req, &policyresponse) if err != nil { return nil, err } return policyresponse.Policies, nil } func (c *Client) getPolicy(ctx context.Context, id, policyType string, policyresponse *Policies) error { req, err := c.newRequest("GET", fmt.Sprintf("keys/%s/policies", id), nil) if err != nil { return err } v := url.Values{} v.Set("policy", policyType) req.URL.RawQuery = v.Encode() _, err = c.do(ctx, req, &policyresponse) if err != nil { return err } return err } // GetRotationPolivy method retrieves rotation policy details of a key // For more information can refet the Key Protect docs in the link below: // https://cloud.ibm.com/docs/key-protect?topic=key-protect-set-rotation-policy#view-rotation-policy-api func (c *Client) GetRotationPolicy(ctx context.Context, id string) (*Policy, error) { policyresponse := Policies{} err := c.getPolicy(ctx, id, RotationPolicy, &policyresponse) if err != nil { return nil, err } if len(policyresponse.Policies) == 0 { return nil, nil } return &policyresponse.Policies[0], nil } // GetDualAuthDeletePolicy method retrieves dual auth delete policy details of a key // For more information can refer the Key Protect docs in the link below: // https://cloud.ibm.com/docs/key-protect?topic=key-protect-set-dual-auth-key-policy#view-dual-auth-key-policy-api func (c *Client) GetDualAuthDeletePolicy(ctx context.Context, id string) (*Policy, error) { policyresponse := Policies{} err := c.getPolicy(ctx, id, DualAuthDelete, &policyresponse) if err != nil { return nil, err } if len(policyresponse.Policies) == 0 { return nil, nil } return &policyresponse.Policies[0], nil } func (c *Client) setPolicy(ctx context.Context, id, policyType string, policyRequest Policies) (*Policies, error) { policyresponse := Policies{} req, err := c.newRequest("PUT", fmt.Sprintf("keys/%s/policies", id), &policyRequest) if err != nil { return nil, err } v := url.Values{} v.Set("policy", policyType) req.URL.RawQuery = v.Encode() _, err = c.do(ctx, req, &policyresponse) if err != nil { return nil, err } return &policyresponse, nil } // SetRotationPolicy updates the rotation policy associated with a key by specifying key ID and rotation interval. // For more information can refer the Key Protect docs in the link below: // https://cloud.ibm.com/docs/key-protect?topic=key-protect-set-rotation-policy#update-rotation-policy-api func (c *Client) SetRotationPolicy(ctx context.Context, id string, rotationInterval int) (*Policy, error) { policy := Policy{ Type: policyType, Rotation: &Rotation{ Interval: rotationInterval, }, } policyRequest := Policies{ Metadata: PoliciesMetadata{ CollectionType: policyType, NumberOfPolicies: 1, }, Policies: []Policy{policy}, } policyresponse, err := c.setPolicy(ctx, id, RotationPolicy, policyRequest) if err != nil { return nil, err } if len(policyresponse.Policies) == 0 { return nil, nil } return &policyresponse.Policies[0], nil } // SetDualAuthDeletePolicy updates the dual auth delete policy by passing the key ID and enable detail // For more information can refer the Key Protect docs in the link below: // https://cloud.ibm.com/docs/key-protect?topic=key-protect-set-dual-auth-key-policy#create-dual-auth-key-policy-api func (c *Client) SetDualAuthDeletePolicy(ctx context.Context, id string, enabled bool) (*Policy, error) { policy := Policy{ Type: policyType, DualAuth: &DualAuth{ Enabled: &enabled, }, } policyRequest := Policies{ Metadata: PoliciesMetadata{ CollectionType: policyType, NumberOfPolicies: 1, }, Policies: []Policy{policy}, } policyresponse, err := c.setPolicy(ctx, id, DualAuthDelete, policyRequest) if err != nil { return nil, err } if len(policyresponse.Policies) == 0 { return nil, nil } return &policyresponse.Policies[0], nil } // SetPolicies updates all policies of the key or a single policy by passing key ID. // To set rotation policy for the key pass the setRotationPolicy parameter as true and set the rotationInterval detail. // To set dual auth delete policy for the key pass the setDualAuthDeletePolicy parameter as true and set the dualAuthEnable detail. // Both the policies can be set or either of the policies can be set. func (c *Client) SetPolicies(ctx context.Context, id string, setRotationPolicy bool, rotationInterval int, setDualAuthDeletePolicy, dualAuthEnable bool) ([]Policy, error) { policies := []Policy{} if setRotationPolicy { rotationPolicy := Policy{ Type: policyType, Rotation: &Rotation{ Interval: rotationInterval, }, } policies = append(policies, rotationPolicy) } if setDualAuthDeletePolicy { dulaAuthPolicy := Policy{ Type: policyType, DualAuth: &DualAuth{ Enabled: &dualAuthEnable, }, } policies = append(policies, dulaAuthPolicy) } policyRequest := Policies{ Metadata: PoliciesMetadata{ CollectionType: policyType, NumberOfPolicies: len(policies), }, Policies: policies, } policyresponse := Policies{} req, err := c.newRequest("PUT", fmt.Sprintf("keys/%s/policies", id), &policyRequest) if err != nil { return nil, err } _, err = c.do(ctx, req, &policyresponse) if err != nil { return nil, err } return policyresponse.Policies, nil }