ladon

package module
v0.0.4 Latest Latest
Warning

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

Go to latest
Published: Mar 6, 2018 License: Apache-2.0 Imports: 19 Imported by: 0

README

d3sw/Ladon

d3sw/Ladon is based on the ory/Ladon which is a open source library for access management similar to AWS IAM Policies.

Differences from ory/Ladon

  • It includes a storage adapter for RethinkDB.
  • It considers multiple representatives, i.e. username, email, of a subject in the authorization process.

Services using d3sw/Ladon library

  • Fuac: a Universal Access Control system meant for any type of application

Table of Contents

Ladon utilizes ory-am/dockertest for tests. Please refer to ory-am/dockertest for more information of how to setup testing environment.

Installation

go get github.com/d3sw/ladon

We recommend to use Glide for dependency management. Ladon uses semantic versioning and versions beginning with zero (0.1.2) might introduce backwards compatibility breaks with each minor version.

Concepts

Ladon is an access control library that answers the question:

Who is able to do what on something given some context

  • Who: An arbitrary unique subject name, for example "ken" or "printer-service.mydomain.com".
  • Able: The effect which can be either "allow" or "deny".
  • What: An arbitrary action name, for example "delete", "create" or "scoped:action:something".
  • Something: An arbitrary unique resource name, for example "something", "resources.articles.1234" or some uniform resource name like "urn:isbn:3827370191".
  • Context: The current context containing information about the environment such as the IP Address, request date, the resource owner name, the department ken is working in or any other information you want to pass along. (optional)

To decide what the answer is, Ladon uses policy documents which can be represented as JSON

{
  "description": "One policy to rule them all.",
  "subjects": ["users:<[peter|ken]>", "users:maria", "groups:admins"],
  "actions" : ["delete", "<[create|update]>"],
  "effect": "allow",
  "resources": [
    "resources:articles:<.*>",
    "resources:printer"
  ],
  "conditions": {
    "remoteIP": {
        "type": "CIDRCondition",
        "options": {
            "cidr": "192.168.0.1/16"
        }
    }
  }
}

and can answer access requests that look like:

{
  "subject": "users:peter",
  "action" : "delete",
  "resource": "resource:articles:ladon-introduction",
  "context": {
    "remoteIP": "192.168.0.5"
  }
}

However, Ladon does not come with a HTTP or server implementation. It does not restrict JSON either. We believe that it is your job to decide if you want to use Protobuf, RESTful, HTTP, AMPQ, or some other protocol. It's up to you to write server!

The following example should give you an idea what a RESTful flow could look like. Initially we create a policy by POSTing it to an artificial HTTP endpoint:

> curl \
      -X POST \
      -H "Content-Type: application/json" \
      -d@- \
      "https://my-ladon-implementation.localhost/policies" <<EOF
        {
          "description": "One policy to rule them all.",
          "subjects": ["users:<[peter|ken]>", "users:maria", "groups:admins"],
          "actions" : ["delete", "<[create|update]>"],
          "effect": "allow",
          "resources": [
            "resources:articles:<.*>",
            "resources:printer"
          ],
          "conditions": {
            "remoteIP": {
                "type": "CIDRCondition",
                "options": {
                    "cidr": "192.168.0.1/16"
                }
            }
          }
        }
  EOF

Then we test if "peter" (ip: "192.168.0.5") is allowed to "delete" the "ladon-introduction" article:

> curl \
      -X POST \
      -H "Content-Type: application/json" \
      -d@- \
      "https://my-ladon-implementation.localhost/warden" <<EOF
        {
          "subject": "users:peter",
          "action" : "delete",
          "resource": "resource:articles:ladon-introduction",
          "context": {
            "remoteIP": "192.168.0.5"
          }
        }
  EOF

{
    "allowed": true
}

Usage

We already discussed two essential parts of Ladon: policies and access control requests. Let's take a closer look at those two.

Policies

Policies are the basis for access control decisions. Think of them as a set of rules. In this library, policies are abstracted as the ladon.Policy interface, and Ladon comes with a standard implementation of this interface which is ladon.DefaultPolicy. Creating such a policy could look like:

import "github.com/d3sw/ladon"

var pol = &ladon.DefaultPolicy{
	// A required unique identifier. Used primarily for database retrieval.
	ID: "68819e5a-738b-41ec-b03c-b58a1b19d043",

	// A optional human readable description.
	Description: "something humanly readable",

	// A subject can be an user or a service. It is the "who" in "who is allowed to do what on something".
	// As you can see here, you can use regular expressions inside < >.
	Subjects: []string{"max", "peter", "<zac|ken>"},

	// Which resources this policy affects.
	// Again, you can put regular expressions in inside < >.
	Resources: []string{"myrn:some.domain.com:resource:123", "myrn:some.domain.com:resource:345", "myrn:something:foo:<.+>"},

	// Which actions this policy affects. Supports RegExp
	// Again, you can put regular expressions in inside < >.
	Actions: []string{"<create|delete>", "get"},

	// Should access be allowed or denied?
	// Note: If multiple policies match an access request, ladon.DenyAccess will always override ladon.AllowAccess
	// and thus deny access.
	Effect: ladon.AllowAccess,

	// Under which conditions this policy is "active".
	Conditions: ladon.Conditions{
		// In this example, the policy is only "active" when the requested subject is the owner of the resource as well.
		"resourceOwner": &ladon.EqualsSubjectCondition{},

		// Additionally, the policy will only match if the requests remote ip address matches address range 127.0.0.1/32
		"remoteIPAddress": &ladon.CIDRCondition{
			CIDR: "127.0.0.1/32",
		},
	},
}
Conditions

Conditions are functions returning true or false given a context. Because conditions implement logic, they must be programmed. Adding conditions to a policy consist of two parts, a key name and an implementation of ladon.Condition:

// StringEqualCondition is an exemplary condition.
type StringEqualCondition struct {
	Equals string `json:"equals"`
}

// Fulfills returns true if the given value is a string and is the
// same as in StringEqualCondition.Equals
func (c *StringEqualCondition) Fulfills(value interface{}, _ *ladon.Request) bool {
	s, ok := value.(string)

	return ok && s == c.Equals
}

// GetName returns the condition's name.
func (c *StringEqualCondition) GetName() string {
	return "StringEqualCondition"
}

var pol = &ladon.DefaultPolicy{
    // ...
    Conditions: ladon.Conditions{
        "some-arbitrary-key": &StringEqualCondition{
            Equals: "the-value-should-be-this"
        }
    },
}

The default implementation of Policy supports JSON un-/marshalling. In JSON, this policy would look like:

{
  "conditions": {
    "some-arbitrary-key": {
        "type": "StringEqualCondition",
        "options": {
            "equals": "the-value-should-be-this"
        }
    }
  }
}

As you can see, type is the value that StringEqualCondition.GetName() is returning and options is used to set the value of StringEqualCondition.Equals.

This condition is fulfilled by (we will cover the warden in the next section)

var err = warden.IsAllowed(&ladon.Request{
    // ...
    Context: &ladon.Context{
        "some-arbitrary-key": "the-value-should-be-this",
    },
}

but not by

var err = warden.IsAllowed(&ladon.Request{
    // ...
    Context: &ladon.Context{
        "some-arbitrary-key": "some other value",
    },
}

and neither by:

var err = warden.IsAllowed(&ladon.Request{
    // ...
    Context: &ladon.Context{
        "same value but other key": "the-value-should-be-this",
    },
}

Ladon ships with a couple of default conditions:

The CIDR condition matches CIDR IP Ranges. Using this condition would look like this in JSON:

{
    "conditions": {
        "remoteIP": {
            "type": "CIDRCondition",
            "options": {
                "cidr": "192.168.0.1/16"
            }
        }
    }
}

and in Go:

var pol = &ladon.DefaultPolicy{
    Conditions: ladon.Conditions{
        "remoteIPAddress": &ladon.CIDRCondition{
            CIDR: "192.168.0.1/16",
        },
    },
}

In this case, we expect that the context of an access request contains a field "remoteIpAddress" matching the CIDR "192.168.0.1/16", for example "192.168.0.5".

Checks if the value passed in the access request's context is identical with the string that was given initially

var pol = &ladon.DefaultPolicy{
    Conditions: ladon.Conditions{
        "some-arbitrary-key": &ladon.StringEqualCondition{
            Equals: "the-value-should-be-this"
        }
    },
}

and would match in the following case:

var err = warden.IsAllowed(&ladon.Request{
    // ...
    Context: &ladon.Context{
         "some-arbitrary-key": "the-value-should-be-this",
    },
}

Checks if the access request's subject is identical with the string that was given initially

var pol = &ladon.DefaultPolicy{
    Conditions: ladon.Conditions{
        "some-arbitrary-key": &ladon.EqualsSubjectCondition{}
    },
}

and would match

var err = warden.IsAllowed(&ladon.Request{
    // ...
    Subject: "peter",
    Context: &ladon.Context{
         "some-arbitrary-key": "peter",
    },
}

but not:

var err = warden.IsAllowed(&ladon.Request{
    // ...
    Subject: "peter",
    Context: &ladon.Context{
         "some-arbitrary-key": "max",
    },
}

Checks if the value passed in the access request's context contains two-element arrays and that both elements in each pair are equal.

var pol = &ladon.DefaultPolicy{
    Conditions: ladon.Conditions{
        "some-arbitrary-key": &ladon.StringPairsEqualCondition{}
    },
}

and would match

var err = warden.IsAllowed(&ladon.Request{
    // ...
    Context: &ladon.Context{
         "some-arbitrary-key": [
             ["some-arbitrary-pair-value", "some-arbitrary-pair-value"],
             ["some-other-arbitrary-pair-value", "some-other-arbitrary-pair-value"],
         ]
    },
}

but not:

var err = warden.IsAllowed(&ladon.Request{
    // ...
    Context: &ladon.Context{
         "some-arbitrary-key": [
             ["some-arbitrary-pair-value", "some-other-arbitrary-pair-value"],
         ]
    },
}
Adding Custom Conditions

You can add custom conditions by appending it to ladon.ConditionFactories:

import "github.com/d3sw/ladon"

func main() {
    // ...

    ladon.ConditionFactories[new(CustomCondition).GetName()] = func() Condition {
        return new(CustomCondition)
    }

    // ...
}
Persistence

d3sw/Ladon implements interface ladon.Manager for RethinkDB besides the In-Memory option originally provided by ory/Ladon.

In-Memory

import (
	"github.com/d3sw/ladon"
	manager "github.com/d3sw/ladon/manager/memory"
)


func main() {
	warden := &ladon.Ladon{
		Manager: manager.NewMemoryManager(),
	}
	err := warden.Manager.Create(pol)

    // ...
}

RethinkDB

import "github.com/d3sw/ladon"
import manager "github.com/d3sw/ladon/manager/rdb"
import r "gopkg.in/gorethink/gorethink.v3"

func main() {
    var session *r.Session
	opts := r.ConnectOpts{
		Address: "127.0.0.1:28015",
	}
	session, e := r.Connect(opts)
	if e != nil {
		log.Fatalf("Could not connect to database: %s", err)
	}

    warden := ladon.Ladon{
        Manager: manager.NewRdbManager(session, "policies"),
    }

    // ...
}
Access Control (Warden)

Now that we have defined our policies, we can use the warden to check if a request is valid. ladon.Ladon, which is the default implementation for the ladon.Warden interface defines ladon.Ladon.IsAllowed() which will return nil if the access request can be granted and an error otherwise.

import "github.com/d3sw/ladon"

func main() {
    // ...

    if err := warden.IsAllowed(&ladon.Request{
        Subject: "peter",
        Action: "delete",
        Resource: "myrn:some.domain.com:resource:123",
        Context: ladon.Context{
            "ip": "127.0.0.1",
        },
    }); err != nil {
        log.Fatal("Access denied")
    }

    // ...
}

Examples

Check out ladon_test.go which includes a couple of policies and tests cases. You can run the code with go test -run=TestLadon -v .

Good to know

  • All checks are case sensitive because subject values could be case sensitive IDs.
  • If ladon.Ladon is not able to match a policy with the request, it will default to denying the request and return an error.

Ladon does not use reflection for matching conditions to their appropriate structs due to security considerations.

Useful commands

Create mocks

mockgen -package ladon_test -destination manager_mock_test.go github.com/d3sw/ladon Manager

Documentation

Index

Constants

View Source
const (
	Matchall = "all"
	Matchany = "any"
)
View Source
const AllowAccess = "allow"

AllowAccess should be used as effect for policies that allow access.

View Source
const DenyAccess = "deny"

DenyAccess should be used as effect for policies that deny access.

View Source
const (
	KeyRawRequest = "http-request"
)

Variables

View Source
var (
	// ErrRequestDenied is returned when an access request can not be satisfied by any policy.
	ErrRequestDenied = errors.WithStack(&errorWithContext{
		error:  errors.New("Request was denied by default"),
		code:   http.StatusForbidden,
		status: http.StatusText(http.StatusForbidden),
		reason: "The request was denied because no matching policy was found.",
	})

	// ErrRequestForcefullyDenied is returned when an access request is explicitly denied by a policy.
	ErrRequestForcefullyDenied = errors.WithStack(&errorWithContext{
		error:  errors.New("Request was forcefully denied"),
		code:   http.StatusForbidden,
		status: http.StatusText(http.StatusForbidden),
		reason: "The request was denied because a policy denied request.",
	})

	// ErrNotFound is returned when a resource can not be found.
	ErrNotFound = errors.WithStack(&errorWithContext{
		error:  errors.New("Resource could not be found"),
		code:   http.StatusNotFound,
		status: http.StatusText(http.StatusNotFound),
	})
)
View Source
var ConditionFactories = map[string]func() Condition{
	new(StringEqualCondition).GetName(): func() Condition {
		return new(StringEqualCondition)
	},
	new(CIDRCondition).GetName(): func() Condition {
		return new(CIDRCondition)
	},
	new(EqualsSubjectCondition).GetName(): func() Condition {
		return new(EqualsSubjectCondition)
	},
	new(StringPairsEqualCondition).GetName(): func() Condition {
		return new(StringPairsEqualCondition)
	},
	new(StringMatchCondition).GetName(): func() Condition {
		return new(StringMatchCondition)
	},
	new(BodyMatchCondition).GetName(): func() Condition {
		return new(BodyMatchCondition)
	},
	new(BodyArrayMatchCondition).GetName(): func() Condition {
		return new(BodyArrayMatchCondition)
	},
}

ConditionFactories is where you can add custom conditions

View Source
var DefaultMatcher = NewRegexpMatcher(512)
View Source
var (
	ErrPolicyNotFound = errors.New("policy not found")
)
View Source
var TestManagerPolicies = []*DefaultPolicy{
	{
		ID:          uuid.New(),
		Description: "description",
		Subjects:    []string{"user", "anonymous"},
		Effect:      AllowAccess,
		Resources:   []string{"article", "user"},
		Actions:     []string{"create", "update"},
		Conditions:  Conditions{},
	},
	{
		ID:          uuid.New(),
		Description: "description",
		Subjects:    []string{},
		Effect:      AllowAccess,
		Resources:   []string{"<article|user>"},
		Actions:     []string{"view"},
		Conditions:  Conditions{},
	},
	{
		ID:          uuid.New(),
		Description: "description",
		Subjects:    []string{},
		Effect:      AllowAccess,
		Resources:   []string{},
		Actions:     []string{"view"},
		Conditions:  Conditions{},
	},
	{
		ID:          uuid.New(),
		Description: "description",
		Subjects:    []string{},
		Effect:      AllowAccess,
		Resources:   []string{},
		Actions:     []string{},
		Conditions:  Conditions{},
	},
	{
		ID:          uuid.New(),
		Description: "description",
		Subjects:    []string{},
		Effect:      AllowAccess,
		Resources:   []string{"foo"},
		Actions:     []string{},
		Conditions:  Conditions{},
	},
	{
		ID:          uuid.New(),
		Description: "description",
		Subjects:    []string{"foo"},
		Effect:      AllowAccess,
		Resources:   []string{"foo"},
		Actions:     []string{},
		Conditions:  Conditions{},
	},
	{
		ID:          uuid.New(),
		Description: "description",
		Subjects:    []string{"foo"},
		Effect:      AllowAccess,
		Resources:   []string{},
		Actions:     []string{},
		Conditions:  Conditions{},
	},
	{
		ID:          uuid.New(),
		Description: "description",
		Effect:      AllowAccess,
		Conditions:  Conditions{},
	},
	{
		ID:          uuid.New(),
		Description: "description",
		Subjects:    []string{"<peter|max>"},
		Effect:      DenyAccess,
		Resources:   []string{"article", "user"},
		Actions:     []string{"view"},
		Conditions: Conditions{
			"owner": &EqualsSubjectCondition{},
		},
	},
	{
		ID:          uuid.New(),
		Description: "description",
		Subjects:    []string{"<user|max|anonymous>", "peter"},
		Effect:      DenyAccess,
		Resources:   []string{".*"},
		Actions:     []string{"disable"},
		Conditions: Conditions{
			"ip": &CIDRCondition{
				CIDR: "1234",
			},
			"owner": &EqualsSubjectCondition{},
		},
	},
	{
		ID:          uuid.New(),
		Description: "description",
		Subjects:    []string{"<.*>"},
		Effect:      AllowAccess,
		Resources:   []string{"<article|user>"},
		Actions:     []string{"view"},
		Conditions: Conditions{
			"ip": &CIDRCondition{
				CIDR: "1234",
			},
			"owner": &EqualsSubjectCondition{},
		},
	},
	{
		ID:          uuid.New(),
		Description: "description",
		Subjects:    []string{"<us[er]+>"},
		Effect:      AllowAccess,
		Resources:   []string{"<article|user>"},
		Actions:     []string{"view"},
		Conditions: Conditions{
			"ip": &CIDRCondition{
				CIDR: "1234",
			},
			"owner": &EqualsSubjectCondition{},
		},
	},
}

Functions

func AssertPolicyEqual

func AssertPolicyEqual(t *testing.T, expected, got Policy)

func Bool

func Bool(data []byte, err error) (bool, error)

func Int64

func Int64(data []byte, err error) (int64, error)

func JsonQuery

func JsonQuery(data []byte, query string) ([]byte, error)

func NewErrResourceNotFound

func NewErrResourceNotFound(err error) error

func String

func String(data []byte, err error) (string, error)

func TestHelperCreateGetDelete

func TestHelperCreateGetDelete(s Manager) func(t *testing.T)

func TestHelperFindPoliciesForSubject

func TestHelperFindPoliciesForSubject(k string, s Manager) func(t *testing.T)

func TestHelperGetErrors

func TestHelperGetErrors(s Manager) func(t *testing.T)

Types

type BodyArrayMatchCondition

type BodyArrayMatchCondition struct {
	Mode    string `json:"mode"`
	Path    string `json:"path"`
	Matches string `json:"matches"`
}

BodyArrayMatchCondition is a condition which is fulfilled if the value at the path in the body is an array and all/any of its elements match the regex pattern specified in BodyArrayMatchCondition

func (*BodyArrayMatchCondition) Fulfills

func (c *BodyArrayMatchCondition) Fulfills(_ interface{}, r *Request) bool

Fulfills returns true if the value at the path in the body is an array and all/any of its elements match the regex pattern specified in BodyMatchCondition

func (*BodyArrayMatchCondition) GetName

func (c *BodyArrayMatchCondition) GetName() string

GetName returns the condition's name.

type BodyMatchCondition

type BodyMatchCondition struct {
	Path    string `json:"path"`
	Matches string `json:"matches"`
}

BodyMatchCondition is a condition which is fulfilled if the value at the path in the body matches the regex pattern specified in BodyMatchCondition

func (*BodyMatchCondition) Fulfills

func (c *BodyMatchCondition) Fulfills(_ interface{}, r *Request) bool

Fulfills returns true if the value at the path in the body matches the regex pattern specified in BodyMatchCondition

func (*BodyMatchCondition) GetName

func (c *BodyMatchCondition) GetName() string

GetName returns the condition's name.

type CIDRCondition

type CIDRCondition struct {
	CIDR string `json:"cidr"`
}

CIDRCondition makes sure that the warden requests' IP address is in the given CIDR.

func (*CIDRCondition) Fulfills

func (c *CIDRCondition) Fulfills(value interface{}, _ *Request) bool

Fulfills returns true if the the request is fulfilled by the condition.

func (*CIDRCondition) GetName

func (c *CIDRCondition) GetName() string

GetName returns the condition's name.

type Condition

type Condition interface {
	// GetName returns the condition's name.
	GetName() string

	// Fulfills returns true if the request is fulfilled by the condition.
	Fulfills(interface{}, *Request) bool
}

Condition either do or do not fulfill an access request.

type Conditions

type Conditions map[string]Condition

Conditions is a collection of conditions.

func (Conditions) AddCondition

func (cs Conditions) AddCondition(key string, c Condition)

AddCondition adds a condition to the collection.

func (Conditions) MarshalJSON

func (cs Conditions) MarshalJSON() ([]byte, error)

MarshalJSON marshals a list of conditions to json.

func (Conditions) UnmarshalJSON

func (cs Conditions) UnmarshalJSON(data []byte) error

UnmarshalJSON unmarshals a list of conditions from json.

type Context

type Context map[string]interface{}

Context is used as request's context.

type DefaultPolicies

type DefaultPolicies struct {
	// in: body
	DefaultPolicies []*DefaultPolicy `json:"policies"`
}

swagger:response Policies

type DefaultPolicy

type DefaultPolicy struct {
	ID          string     `json:"id" gorethink:"id"`
	Description string     `json:"description" gorethink:"description"`
	Subjects    []string   `json:"subjects" gorethink:"subjects"`
	Effect      string     `json:"effect" gorethink:"effect"`
	Resources   []string   `json:"resources" gorethink:"resources"`
	Actions     []string   `json:"actions" gorethink:"actions"`
	Conditions  Conditions `json:"conditions" gorethink:"conditions"`
}

DefaultPolicy is the default implementation of the policy interface.

swagger:model Policy

func (*DefaultPolicy) AllowAccess

func (p *DefaultPolicy) AllowAccess() bool

AllowAccess returns true if the policy effect is allow, otherwise false.

func (*DefaultPolicy) AttachIdentity

func (p *DefaultPolicy) AttachIdentity(ids ...string) error

AttachIdentity adds identities to the Subjects

func (*DefaultPolicy) CheckID

func (p *DefaultPolicy) CheckID() (string, string, error)

func (*DefaultPolicy) DetachIdentity

func (p *DefaultPolicy) DetachIdentity(ids ...string) error

DetachIdentity removes a user,group,role or any other identity from the subject of the policy

func (*DefaultPolicy) GetActions

func (p *DefaultPolicy) GetActions() []string

GetActions returns the policies actions.

func (*DefaultPolicy) GetConditions

func (p *DefaultPolicy) GetConditions() Conditions

GetConditions returns the policies conditions.

func (*DefaultPolicy) GetDescription

func (p *DefaultPolicy) GetDescription() string

GetDescription returns the policies description.

func (*DefaultPolicy) GetEffect

func (p *DefaultPolicy) GetEffect() string

GetEffect returns the policies effect which might be 'allow' or 'deny'.

func (*DefaultPolicy) GetEndDelimiter

func (p *DefaultPolicy) GetEndDelimiter() byte

GetEndDelimiter returns the delimiter which identifies the end of a regular expression.

func (*DefaultPolicy) GetID

func (p *DefaultPolicy) GetID() string

GetID returns the policies id.

func (*DefaultPolicy) GetResources

func (p *DefaultPolicy) GetResources() []string

GetResources returns the policies resources.

func (*DefaultPolicy) GetStartDelimiter

func (p *DefaultPolicy) GetStartDelimiter() byte

GetStartDelimiter returns the delimiter which identifies the beginning of a regular expression.

func (*DefaultPolicy) GetSubjects

func (p *DefaultPolicy) GetSubjects() []string

GetSubjects returns the policies subjects.

func (*DefaultPolicy) HasIdentity

func (p *DefaultPolicy) HasIdentity(id string) bool

HasIdentity returns true if the provided identity is part of the policy i.e. contained in the subject.

func (*DefaultPolicy) UnmarshalJSON

func (p *DefaultPolicy) UnmarshalJSON(data []byte) error

UnmarshalJSON overwrite own policy with values of the given in policy in JSON format

func (*DefaultPolicy) Validate

func (p *DefaultPolicy) Validate() error

Validate validates properties and values of the policy

func (*DefaultPolicy) ValidateEffect

func (p *DefaultPolicy) ValidateEffect() error

ValidateEffect validates the effect

func (*DefaultPolicy) ValidateSubjects

func (p *DefaultPolicy) ValidateSubjects() error

ValidateSubjects validates each subject to make sure they are syntactically correct

type EqualsSubjectCondition

type EqualsSubjectCondition struct{}

EqualsSubjectCondition is a condition which is fulfilled if the request's subject is equal to the given value string

func (*EqualsSubjectCondition) Fulfills

func (c *EqualsSubjectCondition) Fulfills(value interface{}, r *Request) bool

Fulfills returns true if the request's subject is equal to the given value string

func (*EqualsSubjectCondition) GetName

func (c *EqualsSubjectCondition) GetName() string

GetName returns the condition's name.

type Ladon

type Ladon struct {
	Manager Manager
	Matcher matcher
}

Ladon is an implementation of Warden.

func (*Ladon) IsAllowed

func (l *Ladon) IsAllowed(r *Request) (err error)

IsAllowed returns nil if subject s has permission p on resource r with context c or an error otherwise.

type Manager

type Manager interface {

	// Create persists the policy.
	Create(policy Policy) error

	// Update updates an existing policy.
	Update(policy Policy) error

	// Get retrieves a policy.
	Get(id string) (Policy, error)

	// Delete removes a policy.
	Delete(id string) error

	// GetAll retrieves all policies.
	GetAll(limit, offset int64) (Policies, error)

	// FindRequestCandidates returns candidates that could match the request object. It either returns
	// a set that exactly matches the request, or a superset of it. If an error occurs, it returns nil and
	// the error.
	FindRequestCandidates(r *Request) (Policies, error)
}

Manager is responsible for managing and persisting policies.

type ManagerMigrator

type ManagerMigrator interface {
	Create(policy Policy) (err error)
	Migrate() (err error)
	GetManager() Manager
}

type Policies

type Policies []Policy

Policies is an array of policies.

type Policy

type Policy interface {
	// GetID returns the policies id.
	GetID() string

	// GetDescription returns the policies description.
	GetDescription() string

	// GetSubjects returns the policies subjects.
	GetSubjects() []string

	// AllowAccess returns true if the policy effect is allow, otherwise false.
	AllowAccess() bool

	// GetEffect returns the policies effect which might be 'allow' or 'deny'.
	GetEffect() string

	// GetResources returns the policies resources.
	GetResources() []string

	// GetActions returns the policies actions.
	GetActions() []string

	// GetConditions returns the policies conditions.
	GetConditions() Conditions

	// GetStartDelimiter returns the delimiter which identifies the beginning of a regular expression.
	GetStartDelimiter() byte

	// GetEndDelimiter returns the delimiter which identifies the end of a regular expression.
	GetEndDelimiter() byte
}

Policy represent a policy model.

type RegexpMatcher

type RegexpMatcher struct {
	*lru.Cache

	C map[string]*regexp.Regexp
}

func NewRegexpMatcher

func NewRegexpMatcher(size int) *RegexpMatcher

func (*RegexpMatcher) Matches

func (m *RegexpMatcher) Matches(p Policy, haystack []string, needle string) (bool, error)

Matches a needle with an array of regular expressions and returns true if a match was found.

type Request

type Request struct {
	// Resource is the resource that access is requested to.
	Resource string `json:"resource"`

	// Action is the action that is requested on the resource.
	Action string `json:"action"`

	// Subejct is the subject that is requesting access.
	Subjects []string `json:"subject"`

	// Context is the request's environmental context.
	Context Context `json:"context"`
}

Request is the warden's request object.

func (*Request) Validate

func (r *Request) Validate() error

Validate validates request is formatted correctly

type StringEqualCondition

type StringEqualCondition struct {
	Equals string `json:"equals"`
}

StringEqualCondition is a condition which is fulfilled if the given string value is the same as specified in StringEqualCondition

func (*StringEqualCondition) Fulfills

func (c *StringEqualCondition) Fulfills(value interface{}, _ *Request) bool

Fulfills returns true if the given value is a string and is the same as in StringEqualCondition.Equals

func (*StringEqualCondition) GetName

func (c *StringEqualCondition) GetName() string

GetName returns the condition's name.

type StringMatchCondition

type StringMatchCondition struct {
	Matches string `json:"matches"`
}

StringMatchCondition is a condition which is fulfilled if the given string value matches the regex pattern specified in StringMatchCondition

func (*StringMatchCondition) Fulfills

func (c *StringMatchCondition) Fulfills(value interface{}, _ *Request) bool

Fulfills returns true if the given value is a string and matches the regex pattern in StringMatchCondition.Matches

func (*StringMatchCondition) GetName

func (c *StringMatchCondition) GetName() string

GetName returns the condition's name.

type StringPairsEqualCondition

type StringPairsEqualCondition struct{}

StringPairsEqualCondition is a condition which is fulfilled if the given array of pairs contains two-element string arrays where both elements in the string array are equal

func (*StringPairsEqualCondition) Fulfills

func (c *StringPairsEqualCondition) Fulfills(value interface{}, _ *Request) bool

Fulfills returns true if the given value is an array of string arrays and each string array has exactly two values which are equal

func (*StringPairsEqualCondition) GetName

func (c *StringPairsEqualCondition) GetName() string

GetName returns the condition's name.

type Warden

type Warden interface {
	// IsAllowed returns nil if subject s can perform action a on resource r with context c or an error otherwise.
	//  if err := guard.IsAllowed(&Request{Resource: "article/1234", Action: "update", Subject: "peter"}); err != nil {
	//    return errors.New("Not allowed")
	//  }
	IsAllowed(r *Request) error
}

Warden is responsible for deciding if subject s can perform action a on resource r with context c.

Directories

Path Synopsis
Package compiler offers a regexp compiler which compiles regex templates to regexp.Regexp reg, err := compiler.CompileRegex("foo:bar.baz:<[0-9]{2,10}>", '<', '>') // if err != nil ...
Package compiler offers a regexp compiler which compiles regex templates to regexp.Regexp reg, err := compiler.CompileRegex("foo:bar.baz:<[0-9]{2,10}>", '<', '>') // if err != nil ...
manager
rdb

Jump to

Keyboard shortcuts

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