iam

package module
v1.9.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 3, 2023 License: Apache-2.0 Imports: 24 Imported by: 5

README

Build Status

IAM Go SDK

This is AccelByte's IAM Go SDK for integrating with IAM in Go projects.

Usage

Importing package
import "github.com/AccelByte/iam-go-sdk"
Creating default IAM client
cfg := &iam.Config{
    BaseURL: "<IAM URL>",
    ClientID: "<client ID>",
    ClientSecret: "<client secret>",
}

client := iam.NewDefaultClient(cfg)

It's recommended that you store the interface rather than the type since it enables you to mock the client during tests.

var client iam.Client

client := iam.NewDefaultClient(cfg)

So during tests, you can replace the client with:

var client iam.Client

client := iam.NewMockClient() // or create your own mock implementation that suits your test case

Note

By default, the client can only do token validation by requesting to IAM service.

To enable local validation, you need to call:

client.StartLocalValidation()

Then the client will automatically get JWK and revocation list and refreshing them periodically. This enables you to do local token validation and JWT claims parsing.

However, if you need to validate permission, you'll need to call ClientTokenGrant() to retrieve client access token that will be used as bearer token when requesting role details to IAM service.

Calling ClientTokenGrant() once will automatically trigger periodic token refresh.

client.ClientTokenGrant()
Validating token
Validating locally using downloaded JWK and revocation list:
claims, _ := client.ValidateAndParseClaims(accessToken)

Note

Store the claims output if you need to validate it's permission, role, or other properties.

Validating by sending request to IAM service:
ok, _ := client.ValidateAccessToken(accessToken)
Validating permission

For example, you have a resource permission that needs NAMESPACE:{namespace}:USER:{userId} resource string and 4 [UPDATE] action to access.

Using claims you can verify if the token owner is allowed to access the resource by:

permissionResource := make(map[string]string)
permissionResource["{namespace}"] = "example"
permissionResource["{userId}"] = "example"
client.ValidatePermission(claims, iam.Permission{Resource:"NAMESPACE:{namespace}:USER:{userId}", Action:4}, permissionResource)
Validating Audience

Validate audience from the token owner with client's base URI

_ = client.ValidateAudience(claims *JWTClaims) error

Note

Required client access token to get client information (client base URI)

Validating Scope

Validate scope from token owner with client scope

_ = client.ValidateScope(claims *JWTClaims, scope string) error
Health check

Whenever the IAM service went unhealthy, the client will know by detecting if any of the automated refresh goroutines has error.

You can check the health by:

client.HealthCheck()

Jaeger Tracing

IAM service client supports Opentracing Jaeger Traces in Zipkin B3 format(multiple headers mode). Additionally, the client handles k8s istio traces and includes it into outbound calls.

Jaeger Tracing configuration

To configure Jaegeer Client - provide Jaeger Agent host:port or Jaeger Collector URL and setup global tracer

/*
func InitGlobalTracer(
    jaegerAgentHost string,
    jaegerCollectorEndpoint string,
    serviceName string,
    realm string,
)
*/

jaeger.InitGlobalTracer(jaegerAgentHost, "", "service-name", "node-name")
// or
jaeger.InitGlobalTracer("", jaegerCollectorURL, "service-name", "node-name")
Jaeger Tracing usage

Use API methods with received from the response context

// istead of 
validationResult, err := testClient.ValidatePermission(
    claims,
    requiredPermission,
    permissionResources,
)

// use received from the request context
validationResult, err := testClient.ValidatePermission(
    claims,
    requiredPermission,
    permissionResources,
    WithJaegerContext(ctx),
)

// or an empty context to start a new Jaeger Span
validationResult, err := testClient.ValidatePermission(
    claims,
    requiredPermission,
    permissionResources,
    WithJaegerContext(context.Background()),
)

Documentation

Index

Constants

View Source
const (
	UserStatusEmailVerified = 1
	UserStatusPhoneVerified = 1 << 1
	UserStatusAnonymous     = 1 << 2
)

JFlags constants

View Source
const (
	MockUnauthorized = "unauthorized"
	MockForbidden    = "forbidden"
	MockAudience     = "http://example.com"
	MockSecret       = "mocksecret"
)

Mock IAM constants

View Source
const (
	ActionCreate = 1
	ActionRead   = 1 << 1
	ActionUpdate = 1 << 2
	ActionDelete = 1 << 3
)

Permission action bit flags

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client interface {
	// ClientTokenGrant starts client token grant to get client bearer token for role caching
	ClientTokenGrant(opts ...Option) error

	// ClientToken returns client access token
	ClientToken(opts ...Option) string

	// StartLocalValidation starts goroutines to refresh JWK and revocation list periodically
	// this enables local token validation
	StartLocalValidation(opts ...Option) error

	// ValidateAccessToken validates access token by calling IAM service
	ValidateAccessToken(accessToken string, opts ...Option) (bool, error)

	// ValidateAndParseClaims validates access token locally and returns the JWT claims contained in the token
	ValidateAndParseClaims(accessToken string, opts ...Option) (*JWTClaims, error)

	// ValidatePermission validates if an access token has right for a specific permission
	// requiredPermission: permission to access resource, example:
	// 		{Resource: "NAMESPACE:{namespace}:USER:{userId}", Action: 2}
	// permissionResources: resource string to replace the `{}` placeholder in
	// 		`requiredPermission`, example: p["{namespace}"] = "accelbyte"
	ValidatePermission(claims *JWTClaims, requiredPermission Permission,
		permissionResources map[string]string, opts ...Option) (bool, error)

	// ValidateRole validates if an access token has a specific role
	ValidateRole(requiredRoleID string, claims *JWTClaims, opts ...Option) (bool, error)

	// UserPhoneVerificationStatus gets user phone verification status on access token
	UserPhoneVerificationStatus(claims *JWTClaims, opts ...Option) (bool, error)

	// UserEmailVerificationStatus gets user email verification status on access token
	UserEmailVerificationStatus(claims *JWTClaims, opts ...Option) (bool, error)

	// UserAnonymousStatus gets user anonymous status on access token
	UserAnonymousStatus(claims *JWTClaims, opts ...Option) (bool, error)

	// HasBan validates if certain ban exist
	HasBan(claims *JWTClaims, banType string, opts ...Option) bool

	// HealthCheck lets caller know the health of the IAM client
	HealthCheck(opts ...Option) bool

	// ValidateAudience validate audience of user access token
	ValidateAudience(claims *JWTClaims, opts ...Option) error

	// ValidateScope validate scope of user access token
	ValidateScope(claims *JWTClaims, scope string, opts ...Option) error

	// GetRolePermissions gets permissions of a role
	GetRolePermissions(roleID string, opts ...Option) (perms []Permission, err error)

	// GetClientInformation gets IAM client information,
	// it will look into cache first, if not found then fetch it to IAM.
	GetClientInformation(namespace string, clientID string, opts ...Option) (*ClientInformation, error)
}

Client provides interface for IAM Client It can be used as mocking point usage example:

func main() {
	config := Config{
		BaseURL:      "/iam",
		ClientID:     "clientID",
		ClientSecret: "clientSecret",
	}

	iamClient, _ := client.NewClient(&config)
	myFunction(iamClient)
}
func myFunction(iamClient *client.IAMClientAPI) {
	iamClient.ValidateTokenPermission(models.Permission{
		Resource: "NAMESPACE:{namespace}:EXAMPLE", Action: 4
		}, "accessToken")
}

func NewMockClient

func NewMockClient() Client

NewMockClient creates new mock IAM DefaultClient

type ClientInformation added in v1.7.0

type ClientInformation struct {
	ClientName  string `json:"clientName"`
	Namespace   string `json:"namespace"`
	RedirectURI string `json:"redirectUri"`
	BaseURI     string `json:"baseUri"`
}

ClientInformation holds client information

type Config

type Config struct {
	BaseURL                       string
	ClientID                      string
	ClientSecret                  string
	RolesCacheExpirationTime      time.Duration // default: 60s
	JWKSRefreshInterval           time.Duration // default: 60s
	RevocationListRefreshInterval time.Duration // default: 60s
	Debug                         bool
}

Config contains IAM configurations

type DefaultClient

type DefaultClient struct {
	// contains filtered or unexported fields
}

DefaultClient define oauth client config

func NewDefaultClient

func NewDefaultClient(config *Config) *DefaultClient

NewDefaultClient creates new IAM DefaultClient

func (*DefaultClient) ClientToken

func (client *DefaultClient) ClientToken(opts ...Option) string

ClientToken returns client access token

func (*DefaultClient) ClientTokenGrant

func (client *DefaultClient) ClientTokenGrant(opts ...Option) error

ClientTokenGrant starts client token grant to get client bearer token for role caching

func (*DefaultClient) GetClientInformation added in v1.7.0

func (client *DefaultClient) GetClientInformation(namespace string, clientID string, opts ...Option) (*ClientInformation, error)

GetClientInformation gets IAM client information, it will look into cache first, if not found then fetch it to IAM.

func (*DefaultClient) GetRolePermissions added in v1.6.0

func (client *DefaultClient) GetRolePermissions(roleID string, opts ...Option) (perms []Permission, err error)

GetRolePermissions gets permissions of a role

func (*DefaultClient) HasBan

func (client *DefaultClient) HasBan(claims *JWTClaims, banType string, opts ...Option) bool

HasBan validates if certain ban exist

func (*DefaultClient) HealthCheck

func (client *DefaultClient) HealthCheck(opts ...Option) bool

HealthCheck lets caller know the health of the IAM client

func (*DefaultClient) StartLocalValidation

func (client *DefaultClient) StartLocalValidation(opts ...Option) error

StartLocalValidation starts goroutines to refresh JWK and revocation list periodically this enables local token validation

func (*DefaultClient) UserAnonymousStatus

func (client *DefaultClient) UserAnonymousStatus(claims *JWTClaims, opts ...Option) (bool, error)

UserAnonymousStatus gets user anonymous status on access token

func (*DefaultClient) UserEmailVerificationStatus

func (client *DefaultClient) UserEmailVerificationStatus(claims *JWTClaims, opts ...Option) (bool, error)

UserEmailVerificationStatus gets user email verification status on access token

func (*DefaultClient) UserPhoneVerificationStatus

func (client *DefaultClient) UserPhoneVerificationStatus(claims *JWTClaims, opts ...Option) (bool, error)

UserPhoneVerificationStatus gets user phone verification status on access token

func (*DefaultClient) ValidateAccessToken

func (client *DefaultClient) ValidateAccessToken(accessToken string, opts ...Option) (bool, error)

ValidateAccessToken validates access token by calling IAM service

func (*DefaultClient) ValidateAndParseClaims

func (client *DefaultClient) ValidateAndParseClaims(accessToken string, opts ...Option) (*JWTClaims, error)

ValidateAndParseClaims validates access token locally and returns the JWT claims contained in the token

func (*DefaultClient) ValidateAudience added in v1.0.6

func (client *DefaultClient) ValidateAudience(claims *JWTClaims, opts ...Option) error

ValidateAudience validate audience of user access token nolint: funlen

func (*DefaultClient) ValidatePermission

func (client *DefaultClient) ValidatePermission(claims *JWTClaims,
	requiredPermission Permission, permissionResources map[string]string, opts ...Option) (bool, error)

ValidatePermission validates if an access token has right for a specific permission requiredPermission: permission to access resource, example:

{Resource: "NAMESPACE:{namespace}:USER:{userId}", Action: 2}

permissionResources: resource string to replace the `{}` placeholder in

`requiredPermission`, example: p["{namespace}"] = "accelbyte"

nolint: funlen

func (*DefaultClient) ValidateRole

func (client *DefaultClient) ValidateRole(requiredRoleID string, claims *JWTClaims, opts ...Option) (bool, error)

ValidateRole validates if an access token has a specific role

func (*DefaultClient) ValidateScope added in v1.0.6

func (client *DefaultClient) ValidateScope(claims *JWTClaims, reqScope string, opts ...Option) error

ValidateScope validate scope of user access token

type HTTPClient added in v1.1.0

type HTTPClient interface {
	Do(req *http.Request) (*http.Response, error)
}

HTTPClient is an interface for http.Client. The purpose for having this so we could easily mock the HTTP call.

type JWK

type JWK struct {
	Kty string `json:"kty"`
	Use string `json:"use"`
	Kid string `json:"kid"`
	N   string `json:"n"`
	E   string `json:"e"`
}

JWK contains json web key's data

type JWTBan

type JWTBan struct {
	Ban     string    `json:"Ban"`
	EndDate time.Time `json:"EndDate"`
}

JWTBan holds information about ban record in JWT

type JWTClaims

type JWTClaims struct {
	Namespace       string          `json:"namespace"`
	DisplayName     string          `json:"display_name"`
	Roles           []string        `json:"roles"`
	NamespaceRoles  []NamespaceRole `json:"namespace_roles"`
	Permissions     []Permission    `json:"permissions"`
	Bans            []JWTBan        `json:"bans"`
	JusticeFlags    int             `json:"jflgs"`
	Scope           string          `json:"scope"`
	Country         string          `json:"country"`
	ClientID        string          `json:"client_id"`
	IsComply        bool            `json:"is_comply"`
	ParentNamespace string          `json:"parent_namespace,omitempty"`
	UnionID         string          `json:"union_id,omitempty"`
	UnionNamespace  string          `json:"union_namespace,omitempty"`
	jwt.Claims
}

JWTClaims holds data stored in a JWT access token with additional Justice Flags field

func (*JWTClaims) Validate added in v1.0.2

func (c *JWTClaims) Validate() error

Validate checks if the JWT is still valid

type Keys

type Keys struct {
	Keys []JWK `json:"keys"`
}

Keys contains json web keys

type MockClient

type MockClient struct {
	Healthy     bool   // set this to false to mock unhealthy IAM service
	RedirectURI string // set this to use custom redirectURI
}

MockClient define mock oauth client config

func (*MockClient) ClientToken

func (client *MockClient) ClientToken(opts ...Option) string

ClientToken returns client access token

func (*MockClient) ClientTokenGrant

func (client *MockClient) ClientTokenGrant(opts ...Option) error

ClientTokenGrant starts client token grant to get client bearer token for role caching

func (*MockClient) GetClientInformation added in v1.7.0

func (client *MockClient) GetClientInformation(namespace string, clientID string, opts ...Option) (clientInfo *ClientInformation, err error)

GetClientInformation gets IAM client information

func (*MockClient) GetRolePermissions added in v1.6.0

func (client *MockClient) GetRolePermissions(roleID string, opts ...Option) (perms []Permission, err error)

GetRolePermissions gets permissions of a role

func (*MockClient) HasBan

func (client *MockClient) HasBan(claims *JWTClaims, banType string, opts ...Option) bool

HasBan validates if certain ban exist

func (*MockClient) HealthCheck

func (client *MockClient) HealthCheck(opts ...Option) bool

HealthCheck lets caller know the health of the IAM client

func (*MockClient) StartLocalValidation

func (client *MockClient) StartLocalValidation(opts ...Option) error

StartLocalValidation starts goroutines to refresh JWK and revocation list periodically this enables local token validation

func (*MockClient) UserAnonymousStatus

func (client *MockClient) UserAnonymousStatus(claims *JWTClaims, opts ...Option) (bool, error)

UserAnonymousStatus gets user anonymous status on access token

func (*MockClient) UserEmailVerificationStatus

func (client *MockClient) UserEmailVerificationStatus(claims *JWTClaims, opts ...Option) (bool, error)

UserEmailVerificationStatus gets user email verification status on access token

func (*MockClient) UserPhoneVerificationStatus

func (client *MockClient) UserPhoneVerificationStatus(claims *JWTClaims, opts ...Option) (bool, error)

UserPhoneVerificationStatus gets user phone verification status on access token

func (*MockClient) ValidateAccessToken

func (client *MockClient) ValidateAccessToken(accessToken string, opts ...Option) (bool, error)

ValidateAccessToken validates access token by calling IAM service

func (*MockClient) ValidateAndParseClaims

func (client *MockClient) ValidateAndParseClaims(accessToken string, opts ...Option) (*JWTClaims, error)

ValidateAndParseClaims validates access token locally and returns the JWT claims contained in the token

func (*MockClient) ValidateAudience added in v1.0.6

func (client *MockClient) ValidateAudience(claims *JWTClaims, opts ...Option) error

ValidateAudience gets user anonymous status on access token

func (*MockClient) ValidatePermission

func (client *MockClient) ValidatePermission(claims *JWTClaims,
	requiredPermission Permission, permissionResources map[string]string, opts ...Option) (bool, error)

ValidatePermission validates if an access token has right for a specific permission requiredPermission: permission to access resource, example:

{Resource: "NAMESPACE:{namespace}:USER:{userId}", Action: 2}

permissionResources: resource string to replace the `{}` placeholder in

`requiredPermission`, example: p["{namespace}"] = "accelbyte"

func (*MockClient) ValidateRole

func (client *MockClient) ValidateRole(requiredRoleID string, claims *JWTClaims, opts ...Option) (bool, error)

ValidateRole validates if an access token has a specific role

func (*MockClient) ValidateScope added in v1.0.6

func (client *MockClient) ValidateScope(claims *JWTClaims, scope string, opts ...Option) error

ValidateScope gets user anonymous status on access token

type NamespaceRole added in v1.3.0

type NamespaceRole struct {
	RoleID    string `json:"roleId"`
	Namespace string `json:"namespace"`
}

type Option added in v1.2.0

type Option func(*Options)

func WithJaegerContext added in v1.2.0

func WithJaegerContext(ctx context.Context) Option

type Options added in v1.2.0

type Options struct {
	// contains filtered or unexported fields
}

type Permission

type Permission struct {
	Resource        string
	Action          int
	ScheduledAction int      `json:"SchedAction,omitempty"`
	CronSchedule    string   `json:"SchedCron,omitempty"`
	RangeSchedule   []string `json:"SchedRange,omitempty"`
}

Permission holds information about the actions can be performed to the resource. Action is a bit flag of CREATE READ UPDATE and DELETE. Schedule is a string in quartz compatible cron syntax that is using github.com/gorhill/cronexpr to parse. in range type, first element will be start date, and second one will be end date

func (Permission) IsScheduled

func (perm Permission) IsScheduled() bool

IsScheduled checks if the schedule is active at current time

type RevocationList

type RevocationList struct {
	RevokedTokens bloom.FilterJSON           `json:"revoked_tokens"`
	RevokedUsers  []UserRevocationListRecord `json:"revoked_users"`
}

RevocationList contains revoked user and token

type Role

type Role struct {
	RoleID      string `json:"RoleId"`
	RoleName    string
	Permissions []Permission
}

Role holds info about a user role.

type TokenResponse

type TokenResponse struct {
	AccessToken           string          `json:"access_token"`
	RefreshToken          string          `json:"refresh_token"`
	ExpiresIn             int             `json:"expires_in"`
	TokenType             string          `json:"token_type"`
	Roles                 []string        `json:"roles"`
	AcceptedPolicyVersion []string        `json:"accepted_policy_version"`
	NamespaceRoles        []NamespaceRole `json:"namespace_roles"`
	Permissions           []Permission    `json:"permissions"`
	Bans                  []JWTBan        `json:"bans"`
	UserID                string          `json:"user_id"`
	PlatformID            string          `json:"platform_id,omitempty"`
	PlatformUserID        string          `json:"platform_user_id,omitempty"`
	JusticeFlags          int             `json:"jflgs,omitempty"`
	DisplayName           string          `json:"display_name"`
	Namespace             string          `json:"namespace"`
	IsComply              bool            `json:"is_comply"`
}

TokenResponse is the data structure for the response on successful token request.

type UserRevocationListRecord

type UserRevocationListRecord struct {
	ID        string    `json:"id" bson:"id"`
	RevokedAt time.Time `json:"revoked_at" bson:"revoked_at"`
}

UserRevocationListRecord is used to store revoked user data

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL