Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Federations, Federation Certificates #8

Merged
merged 8 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions examples/federation-with-user/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Create Federation with Certificate & add User

This example program demonstrates how to manage creating and deleting Federation with Certificate and assigning Users.

The part of deleting is disabled by `deleteAfterRun` variable.

## Running this example

Running this file will execute the following operations:

1. **Create Federation:** Create is used to create a new Federation.
2. **Create Certificate for Federation:** Create is used to create a new Certificate for Federation.
3. **Create federated User:** Create is used to create a new federated User.
4. **Update Federation:** Updates the Federation Name and Description.
5. **(Delete Federation):** _(disabled by default)_ Delete a just-created Federation on a previous step.

You should see an output like the following:
```
Step 1: Created Federation Name: federation_name ID: 1a2b3c...
Step 2: Created Certificate for Federation ID: 12345_3... Federation ID: 1a2b3c...
Step 3: Created federated User ID: 54321_2... Keystone ID: 1c2b3a...
Step 4: Updated Federation Name and Description
Step 5: Deleting Federation with ID: 1a2b3c...
```
3 changes: 3 additions & 0 deletions examples/federation-with-user/cert.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-----BEGIN CERTIFICATE-----
MIICmzCCAYMCBgGI6ANFczANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjMwNjIzMTEyNjQ4WhcNMzMwNjIzMTEyODI4WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC04rOaDpre/MucE3HXVCnAnpqIqQOeMn696AW2FATnI26x1BsxVAGjcrheAOIu+CxC28m48Ah4+SiTEk/u2X/WbGTd/1GZooz37cge0AWMQGyh8ysZRd6q06kg4QGD1iUtdQyHioMbSr9pPne2QQgSX5/gM9XDuA6dpG9Yv0PIPLFlk3BIUL1qEfUiYbDlrunkN/y4XromJaJPpgXKWraH194bqcgXGQLrCqicKwsRBoQJHg3ODWHjHFOwYODJ1XBsRcAue4J88PKiPV1tZNPVczMptrkqGBYTgOYGjKXGe5EH50RJE4/3Ynurz2s34DSDVJhJOYtGwpfeSuU3i3mVAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGAweCuWJmJXMUdRtgoFIiu6BGotDX5sA/VOm4CRsEXV7/qnBagrAPkRz86KGm4lOPL0X+I13JQh4/OB1gxnPN+BXhNtCWCoj1wA3/BWjs1ow/gaVXzwdy+1mbc/sUBudsLq2Yqs54GgeYsTBKMVpSLKiRg1NebEFlqFmG2hjPzYg1QHL4VBusMQgqt7TTnOfGtdT3Ss9TKGRQ+iwfNL0BtSAKaTRdhNVU4lDYUs788Kw5od/uJj0wTICKO5/PrkX7Uy42+fyU+4SvJynPOy+M+z+s08JC9+eYXixfeeFG1nNWR+DIKXcXaSwNQW+8RweGbOJxQ2BoUKtl0NCHrvxJw=
-----END CERTIFICATE-----
117 changes: 117 additions & 0 deletions examples/federation-with-user/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package main

import (
"context"
"fmt"
"os"

"github.com/selectel/iam-go"
"github.com/selectel/iam-go/service/federations/certificates"
"github.com/selectel/iam-go/service/federations/saml"
"github.com/selectel/iam-go/service/roles"
"github.com/selectel/iam-go/service/users"
)

var (
// KeystoneToken
token = "gAAAAABmoPpv1X9N2ufmTIUeq6Z8xzhh7QvuZp3y9PqA-ISZWownO0bOZQqJGSv6LURN6LagfEVQCWKDyXREfVLOXpX05g45PNBiSZYHSf-sV0VoIFriD-ITwZCWfynm0wgDzh9u4Opwlj_hA06EPJJtrOfEP9uIOMcYAC-5i-VPwV5wTo2cVnI"
saydamir marked this conversation as resolved.
Show resolved Hide resolved
deleteAfterRun = false

// Prefix to be added to User-Agent.
prefix = "iam-go"

federationName = "federation_name"
federationDescription = "federation_description"
updatedFederationName = "new_federation_name"
updatedFederationDescription = "new_federation_description"

certificateName = "certificate name"
certificateDescription = "certificate description"
certificateFileName = "cert.crt"

userEmail = "[email protected]"
userExternalID = "some_id"
)

func main() {
// Create a new IAM client.
iamClient, err := iam.New(
iam.WithAuthOpts(&iam.AuthOpts{KeystoneToken: token}),
iam.WithUserAgentPrefix(prefix),
)
if err != nil {
fmt.Println(err)
return
}

federationsAPI := iamClient.Federations
federationsCertificatesAPI := iamClient.FederationsCertificates
usersAPI := iamClient.Users

ctx := context.Background()

federation, err := federationsAPI.Create(ctx, saml.CreateRequest{
Name: federationName,
Description: federationDescription,
Issuer: "http://localhost:8080/realms/master",
SSOUrl: "http://localhost:8080/realms/master/protocol/saml",
SessionMaxAgeHours: 24,
SignAuthnRequests: true,
})
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Step 1: Created Federation Name: %s ID: %s\n", federation.Name, federation.ID)

cert, err := os.ReadFile(certificateFileName)
if err != nil {
fmt.Println(err)
return
}

certificate, err := federationsCertificatesAPI.Create(ctx, federation.ID, certificates.CreateRequest{
Name: certificateName,
Description: certificateDescription,
Data: string(cert),
})
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Step 2: Created Certificate for Federation ID: %s Federation ID: %s\n", certificate.ID, federation.ID)

user, err := usersAPI.Create(ctx, users.CreateRequest{
AuthType: users.Federated,
Email: userEmail,
Federation: &users.Federation{
ExternalID: userExternalID,
ID: federation.ID,
},
Roles: []roles.Role{{Scope: roles.Account, RoleName: roles.Reader}},
})
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Step 3: Created federated User ID: %s Keystone ID: %s\n", user.ID, user.KeystoneID)

err = federationsAPI.Update(ctx, federation.ID, saml.UpdateRequest{
Name: updatedFederationName,
Description: updatedFederationDescription,
})
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Step 4: Updated Federation Name and Description")

if deleteAfterRun {
// Removing User and Federation Certificate is unnecessary because removal of Federation
// also deletes its Certificate and all attached Users
fmt.Printf("Step 5: Deleting Federation with ID: %s\n", federation.ID)
if err = federationsAPI.Delete(ctx, federation.ID); err != nil {
fmt.Println(err)
}
}
}
11 changes: 11 additions & 0 deletions iam.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (

"github.com/selectel/iam-go/iamerrors"
baseclient "github.com/selectel/iam-go/internal/client"
"github.com/selectel/iam-go/service/federations/certificates"
"github.com/selectel/iam-go/service/federations/saml"
"github.com/selectel/iam-go/service/groups"
"github.com/selectel/iam-go/service/s3credentials"
"github.com/selectel/iam-go/service/serviceusers"
Expand Down Expand Up @@ -57,6 +59,13 @@ type Client struct {

// S3Credentials instance is used to make requests against Selectel IAM API and manage S3 Credentials.
S3Credentials *s3credentials.Service

// Federations instance is used to make requests against Selectel IAM API and manage Federations.
Federations *saml.Service
Icerzack marked this conversation as resolved.
Show resolved Hide resolved

// FederationsCertificates instance is used to make requests against Selectel IAM API
// and manage Federations Certificates.
FederationsCertificates *certificates.Service
Icerzack marked this conversation as resolved.
Show resolved Hide resolved
}

type AuthOpts struct {
Expand Down Expand Up @@ -128,6 +137,8 @@ func New(opts ...Option) (*Client, error) {
c.ServiceUsers = serviceusers.New(c.baseClient)
c.Groups = groups.New(c.baseClient)
c.S3Credentials = s3credentials.New(c.baseClient)
c.Federations = saml.New(c.baseClient)
c.FederationsCertificates = certificates.New(c.baseClient)

return c, nil
}
Expand Down
38 changes: 23 additions & 15 deletions iam_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (

"github.com/selectel/iam-go/iamerrors"
baseclient "github.com/selectel/iam-go/internal/client"
"github.com/selectel/iam-go/service/federations/certificates"
"github.com/selectel/iam-go/service/federations/saml"
"github.com/selectel/iam-go/service/groups"
"github.com/selectel/iam-go/service/s3credentials"
"github.com/selectel/iam-go/service/serviceusers"
Expand Down Expand Up @@ -57,11 +59,13 @@ func TestNew(t *testing.T) {
authOpts: &AuthOpts{
KeystoneToken: testToken,
},
baseClient: baseClient,
Users: users.New(baseClient),
ServiceUsers: serviceusers.New(baseClient),
Groups: groups.New(baseClient),
S3Credentials: s3credentials.New(baseClient),
baseClient: baseClient,
Users: users.New(baseClient),
ServiceUsers: serviceusers.New(baseClient),
Groups: groups.New(baseClient),
S3Credentials: s3credentials.New(baseClient),
Federations: saml.New(baseClient),
FederationsCertificates: certificates.New(baseClient),
}
},
expectedError: nil,
Expand Down Expand Up @@ -99,11 +103,13 @@ func TestNew(t *testing.T) {
authOpts: &AuthOpts{
KeystoneToken: testToken,
},
baseClient: baseClient,
Users: users.New(baseClient),
ServiceUsers: serviceusers.New(baseClient),
Groups: groups.New(baseClient),
S3Credentials: s3credentials.New(baseClient),
baseClient: baseClient,
Users: users.New(baseClient),
ServiceUsers: serviceusers.New(baseClient),
Groups: groups.New(baseClient),
S3Credentials: s3credentials.New(baseClient),
Federations: saml.New(baseClient),
FederationsCertificates: certificates.New(baseClient),
}
},
expectedError: nil,
Expand Down Expand Up @@ -134,11 +140,13 @@ func TestNew(t *testing.T) {
authOpts: &AuthOpts{
KeystoneToken: testToken,
},
baseClient: baseClient,
Users: users.New(baseClient),
ServiceUsers: serviceusers.New(baseClient),
Groups: groups.New(baseClient),
S3Credentials: s3credentials.New(baseClient),
baseClient: baseClient,
Users: users.New(baseClient),
ServiceUsers: serviceusers.New(baseClient),
Groups: groups.New(baseClient),
S3Credentials: s3credentials.New(baseClient),
Federations: saml.New(baseClient),
FederationsCertificates: certificates.New(baseClient),
}
},
expectedError: nil,
Expand Down
75 changes: 45 additions & 30 deletions iamerrors/iamerrors.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ var (
ErrGroupNotFound = errors.New("GROUP_NOT_FOUND")
ErrUserOrGroupNotFound = errors.New("USER_OR_GROUP_NOT_FOUND")

ErrFederationNameRequired = errors.New("FEDERATION_NAME_REQUIRED")
ErrFederationIDRequired = errors.New("FEDERATION_ID_REQUIRED")
ErrFederationIssuerRequired = errors.New("FEDERATION_ISSUER_REQUIRED")
ErrFederationSSOURLRequired = errors.New("FEDERATION_SSO_URL_REQUIRED")
ErrFederationCertificateIDRequired = errors.New("FEDERATION_CERTIFICATE_ID_REQUIRED")
ErrFederationMaxAgeHoursRequired = errors.New("FEDERATION_MAX_AGE_HOURS_REQUIRED")
ErrFederationNotFound = errors.New("FEDERATION_NOT_FOUND")

ErrCredentialNameRequired = errors.New("CREDENTIAL_NAME_REQUIRED")
ErrCredentialAccessKeyRequired = errors.New("CREDENTIAL_ACCESS_KEY_REQUIRED")

Expand All @@ -48,36 +56,43 @@ var (

//nolint:gochecknoglobals // stringToError is not global.
stringToError = map[string]error{
ErrUserNotFound.Error(): ErrUserNotFound,
ErrClientNoAuthOpts.Error(): ErrClientNoAuthOpts,
ErrAuthTokenUnathorized.Error(): ErrAuthTokenUnathorized,
ErrDomainNotFound.Error(): ErrDomainNotFound,
ErrCredentialNotFound.Error(): ErrCredentialNotFound,
ErrProjectNotFound.Error(): ErrProjectNotFound,
ErrUserAlreadyExists.Error(): ErrUserAlreadyExists,
ErrRequestValidationError.Error(): ErrRequestValidationError,
ErrForbidden.Error(): ErrForbidden,
ErrUnauthorized.Error(): ErrUnauthorized,
ErrInternalServerError.Error(): ErrInternalServerError,
ErrCredentialNameRequired.Error(): ErrCredentialNameRequired,
ErrCredentialAccessKeyRequired.Error(): ErrCredentialAccessKeyRequired,
ErrUserIDRequired.Error(): ErrUserIDRequired,
ErrProjectIDRequired.Error(): ErrProjectIDRequired,
ErrGroupIDRequired.Error(): ErrGroupIDRequired,
ErrGroupUserIDsRequired.Error(): ErrGroupUserIDsRequired,
ErrGroupNameRequired.Error(): ErrGroupNameRequired,
ErrGroupRolesRequired.Error(): ErrGroupRolesRequired,
ErrGroupAlreadyExists.Error(): ErrGroupAlreadyExists,
ErrGroupNotFound.Error(): ErrGroupNotFound,
ErrUserOrGroupNotFound.Error(): ErrUserOrGroupNotFound,
ErrServiceUserNameRequired.Error(): ErrServiceUserNameRequired,
ErrServiceUserPasswordRequired.Error(): ErrServiceUserPasswordRequired,
ErrServiceUserRolesRequired.Error(): ErrServiceUserRolesRequired,
ErrUserRolesRequired.Error(): ErrUserRolesRequired,
ErrUserEmailRequired.Error(): ErrUserEmailRequired,
ErrInputDataRequired.Error(): ErrInputDataRequired,
ErrInternalAppError.Error(): ErrInternalAppError,
ErrUnknown.Error(): ErrUnknown,
ErrUserNotFound.Error(): ErrUserNotFound,
ErrClientNoAuthOpts.Error(): ErrClientNoAuthOpts,
ErrAuthTokenUnathorized.Error(): ErrAuthTokenUnathorized,
ErrDomainNotFound.Error(): ErrDomainNotFound,
ErrCredentialNotFound.Error(): ErrCredentialNotFound,
ErrProjectNotFound.Error(): ErrProjectNotFound,
ErrUserAlreadyExists.Error(): ErrUserAlreadyExists,
ErrRequestValidationError.Error(): ErrRequestValidationError,
ErrForbidden.Error(): ErrForbidden,
ErrUnauthorized.Error(): ErrUnauthorized,
ErrInternalServerError.Error(): ErrInternalServerError,
ErrCredentialNameRequired.Error(): ErrCredentialNameRequired,
ErrCredentialAccessKeyRequired.Error(): ErrCredentialAccessKeyRequired,
ErrUserIDRequired.Error(): ErrUserIDRequired,
ErrProjectIDRequired.Error(): ErrProjectIDRequired,
ErrGroupIDRequired.Error(): ErrGroupIDRequired,
ErrGroupUserIDsRequired.Error(): ErrGroupUserIDsRequired,
ErrGroupNameRequired.Error(): ErrGroupNameRequired,
ErrGroupRolesRequired.Error(): ErrGroupRolesRequired,
ErrGroupAlreadyExists.Error(): ErrGroupAlreadyExists,
ErrGroupNotFound.Error(): ErrGroupNotFound,
ErrFederationNameRequired.Error(): ErrFederationNameRequired,
ErrFederationIDRequired.Error(): ErrFederationIDRequired,
ErrFederationIssuerRequired.Error(): ErrFederationIssuerRequired,
ErrFederationSSOURLRequired.Error(): ErrFederationSSOURLRequired,
ErrFederationCertificateIDRequired.Error(): ErrFederationCertificateIDRequired,
ErrFederationNotFound.Error(): ErrFederationNotFound,
ErrFederationMaxAgeHoursRequired.Error(): ErrFederationMaxAgeHoursRequired,
ErrUserOrGroupNotFound.Error(): ErrUserOrGroupNotFound,
ErrServiceUserNameRequired.Error(): ErrServiceUserNameRequired,
ErrServiceUserPasswordRequired.Error(): ErrServiceUserPasswordRequired,
ErrServiceUserRolesRequired.Error(): ErrServiceUserRolesRequired,
ErrUserRolesRequired.Error(): ErrUserRolesRequired,
ErrUserEmailRequired.Error(): ErrUserEmailRequired,
ErrInputDataRequired.Error(): ErrInputDataRequired,
ErrInternalAppError.Error(): ErrInternalAppError,
ErrUnknown.Error(): ErrUnknown,
}
)

Expand Down
2 changes: 2 additions & 0 deletions service/federations/certificates/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package certificates provides a set of functions for interacting with the Selectel Federations Certificates API.
package certificates
Loading
Loading