GithubHelp home page GithubHelp logo

fabbricadigitale / scimd Goto Github PK

View Code? Open in Web Editor NEW
5.0 4.0 1.0 630 KB

SCIM v2 golang implementation

License: MIT License

Go 96.29% ANTLR 0.61% Makefile 0.51% JavaScript 2.51% Dockerfile 0.09%
scim identity-management rfc-7643 rfc-7644 scim-2 schema user-management

scimd's Introduction

scimd

scimd's People

Contributors

alelb avatar leodido avatar leogr avatar marcomenoni avatar samechelon avatar skryja avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

lapd-golang

scimd's Issues

Harness test suite

I already setup it.

PR #46 contains some tests for static resource service endpoints.

Task

Implement the examples written here.

Failing of validation tag "required" on int, bool and string type fields

With validation tag "required" on bool type fields if you don't give that field value true, the test using Validator.Struct() it will return this error :
'ResourceType.SchemaExtensions[0].Required' Error:Field validation for 'Required' failed on the 'required' tag

Fixed temporarily 6f23992 removing the required validation tag

Subattributes of a complex excludedAttribute aren't excluded

Because the attributes are flattened the subattributes of a complex excludedAttribute cannot be differentiated, so they remain in the resulting set (ref).

GET \v2\User\...excludedAttributes=urn:something:User:name

included/default attributes
urn:something:User:name
urn:something:User:name.familyName
urn:something:User:email.value

excluded attributes
urn:something:User:name

resulting set = included/default attributes - excluded attributes
urn:something:User:name.familyName
urn:something:User:email.value

Fix toResource method

It makes so much assumptions for my tastes.

Infact it breaks when meta contains only resourceType and not all the other subattributes this method assumes always exist.

Custom validator for attribute notation

Create a custom validator that checks a give string matches the attribute notation.

Use the Path parser already in place (within api/attr directory).

When done, test it.

When tests will pass use it within the PR #29.

Code review

In order to release a beta version, here there is a list of task to be completed:

  • complete server handlers - 0

  • API validation - 1

  • compare password - 2

  • change password + enabling/disabling it - 3

  • check pagination and sorting - 4

  • error handling (validators, API) - 5

  • complete unit test

  • test harness (API) (#69)

  • test concurrency

  • setup CI + coverage

  • PATCH (optional)

  • CLI (commands, flags)

  • root search (POST)

  • etag

  • enabling/disabling filtering

  • enabling/disabling sorting

@leodido, @leogr, @samechelon feel free to add/remove tasks to/from this list.

Packages interdependencies

The current situation is:

  • messages needs core
  • schemas needs core
  • resources needs core and schemas

Questions:

  1. What are best practices to avoid import cycles?
  2. Should a package avoid to import a package that's parent in path?

Refs #9

Enforce that attribute names match the rules

Hey @samechelon, use the custom validator attrname to validate that the attribute names respect the rules.

So you have to populate with validate:attrname the structs that require it.

Pay attention that for non scalar fields you have to use special keywords provided by the go-validator library (eg., dive).

When you've done with this first sub-task, please provide the tests.
Note that tests for resource structs already exists, so augment them.

FYI @leogr

Review data types API

I propose to rename IsAssigned.

We should also rename IsMultiValued into IsMultiValue since the complementar method is IsSingular.

Endpoint for authenticated subject alias

How to handle the authenticated subject alias (eg., /Me endpoint) - Section 3.11 @ RFC7644

  • Permanent redirect (308) to /User
  • Process directly with Location header pointing to the aliased resource (ie., User)
  • Both way but configurable

Copying from my notes at PR #46.

cc @fabbricadigitale/openinnovation

Inconsistency of meta attributes definition with the logic of projection

RFC 7643 @ section 3.1 mandates that the meta attributes have a "returned" characteristic equal to "default".

This contrasts with the logic of attribute inclusion (and exclusion, ie. projection).

Namely,

attributes  A multi-valued list of strings indicating the names of
      resource attributes to return in the response, overriding the set
      of attributes that would be returned by default.

Ref.

attributes  When specified, the default list of attributes SHALL be
           overridden,

Ref.

Our projection logic follows the RFC logic.

So, at the end when we specify to include only some attributes we lose the meta ones.
This causes panics in the code since within the storage/mongo/adapater.go::toResource() method we expect/assume the dd["meta"] cannot be nil.

cc @leogr @alelb @samechelon

About $ref attribute and relations between resources

Referring to the specific case of the Users-Groups relationship, I would like to focus on the relationship between resources in general.

The User resource has a "groups" attribute that represents a list of all the groups to which the user belongs. Note that this is an attribute with mutability readOnly.
The possibility of adding a relationship is left to the Gruop resource which has a list of "members" with a mutability readWrite.

Currently, the part of logic that for a new group member, adding this information to the corresponding User resource is missing.

I'm thinking about two solutions:

  1. the information is stored in the user resource, so in the Create Group something must be activated so the corresponding User resource is changed.

  2. the membership information is kept only in the Group resource and every time the user resource is requested the relationship in the Group resource is searched.

I think the latter is the most suitable in a mongodb context.

Please @leodido @leogr tell me what you think.

Excluding attribute's sub-attribute will exclude every sub-attribute of that attribute

Excluding an attribute's subattribute will exclude every other subattribute of that attribute

eg., HERE

TEST RESULT
The test's result in this case will be positive, so it will pass, even though should be negative, it shouldn't pass, because the excluded subattribute is urn:ietf:params:scim:schemas:core:2.0:User:emails.value, while making a check on another subattribute of email that should be present among the email attribute's subattributes.

Patch critical insights

In order to posticipate patch implementation I take note of potential critical issues.

  • The path attribute could be a valuePath expression. The ABNF syntax rule is PATH = attrPath / valuePath [subAttr]. There is no way to access to subAttr from valuePath (#38).

  • It's to evaluate attribute mutability before to perform patch operations.

  • If patch operation introduces an attribute of a new schema, the client may implicit modify the schemas attribute by adding the related schema URN.

  • A patch can perform more than one operation. Operations are applied sequentially in order they appear in the operations array. The sequence is atomic, so if a single operation fails, the original scim resource have to be restored.

For add, set and replace notes refer to RFC.

Bulk operations

It is an optional server feature, we could implement it later.

The following is a draft of api's messages:

package messages

const BULK_REQUEST_URN = "urn:ietf:params:scim:api:messages:2.0:BulkRequest"
const BULK_RESPONSE_URN = "urn:ietf:params:scim:api:messages:2.0:BulkResponse"

type bulk struct {
	Schemas    []string `json:"schemas"`
	Operations []struct {
		Method  string `json:"method"`
		Path    string `json:"path"`
		BulkID  string `json:"bulkId,omitempty"`
		Version string `json:"version,omitempty"`
		Data    struct {
			Schemas     []string `json:"schemas"`
			DisplayName string   `json:"displayName"`
			Members     []struct {
				Type  string `json:"type"`
				Value string `json:"value"`
			} `json:"members"`
		} `json:"data"`
	} `json:"Operations"`
}

type BulkRequest struct {
	bulk
	FailOnErrors int `json:"failOnErrors,omitempty"`
}

type BulkResponse struct {
	bulk
	FailOnErrors int `json:"failOnErrors,omitempty"`
}

Server handlers

In order to complete server handlers, here a list of TODO:

  • API for update (PUT) resources
    Notice that PUT MUST NOT be used to create new resources

  • Search, Put and Delete handlers

  • field validation when posting a resource.
    @leodido note that we can decorate field of the struct CommonAttribute with `binding:"required" etc, but we cannot do the same with the datatype.Complex resource data.

  • add in create and update api the business logic to retrieve the resource just created/updated

to be continued

Test configuration phase

I have push'd configuration phase for the upcoming server to the feature/server branch.

Tests have to be done.

Phase 1

  • call config() func and test that it returns a ServiceProviderConfig instance
  • test a SchemaRepository instance containing x Schema instances has been created
  • test a ResourceTypeRepository instance containing y ResourceType instances has been created

Legend

x := Number of JSON files within default/schemas directory
y := Number of JSON files within default/resources directory

Phase 2

Note that this step requires some parametrization (path of service provider config JSON) of the config function.

  • test panics when wrong path
  • test panics with unmarshalling errors
  • test panics with validation errors

Per RFC 7643 attribute name could include '$' but not at beginning

So:

  • $ref is ambiguous or is a special case
  • Within filtering grammar '$' is not present at beginning nor in the middle (so it's not possibile to use $ref nor myCu$stomAttr as attr path).

Thus, I think the presence of $ in the RFC is a typo. For those reason, since #28 it has been removed from implementation.

Refs:

Auth features

Features like credentials validation, password recovery and account locking should be included in scimd? or these should be handled by another module with direct access to the identity store?

Attribute Path API

It's need an API thats for a given attribute path returns the related set of schema attributes.

Count parameter default (min and/or max) for paginations

We need a way to define the default count for pagination.

Probably this have to act also as an hard-cap (ie., maximum).

Currently the service provider configuration does not specify this.

How we want to implement this server configuration step?

cc @fabbricadigitale/openinnovation

Unassigned and Null values for Structured Resources

Currently Structured Resources does not implement Unassigned and Null rules.

The main issue is that we can assign nil to scalar attribute of a struct.
In case of nested struct (eg. Meta) we could embed by-pointer, but it seems overkilling in case of scalars.

However, may be we do not need Unassigned and Null for attributes of these resources (ie. Schema, ResourceType, and ServiceProviderConfig. If we can confirm that then we can close this issue and document this special case.

ABNF rules and case insensitivity of attribute names

As per https://tools.ietf.org/html/rfc7643#section-2.1, attribute names MUST conform to the following ABNF rules:

               ATTRNAME   = ALPHA *(nameChar)
               nameChar   = "$" / "-" / "_" / DIGIT / ALPHA

Furthermore, ABNF strings are case insensitive so all attribute names should be case insensitive too, but it's difficult to achieve because implementation should:

  • Validate the attr name by the above ABNF rules (eg. within schemas.core.Attribute)
  • Also accepting a case-insensitive match when unmarshalling
  • Ensure that no naming collision occurs with the same set of attrs (eg. fooBaz and foobaz)
  • Querying by path should consider case insensitivity
    ...other?

Maybe wont'fix?

Fix validation tests

cc @leodido @samechelon @skryja

--- FAIL: TestResourceTypeValidation (0.00s)
        Error Trace:    resource_type_test.go:59
	Error:      	"Key: 'ResourceType.Common.Schemas' Error:Field validation for 'Schemas' failed on the 'gt' tag
	            	Key: 'ResourceType.Common.ID' Error:Field validation for 'ID' failed on the 'required' tag
	            	Key: 'ResourceType.Common.Meta.Location' Error:Field validation for 'Location' failed on the 'uri' tag
	            	Key: 'ResourceType.Common.Meta.ResourceType' Error:Field validation for 'ResourceType' failed on the 'required' tag
	            	Key: 'ResourceType.Common.Meta.Created' Error:Field validation for 'Created' failed on the 'required' tag
	            	Key: 'ResourceType.Common.Meta.LastModified' Error:Field validation for 'LastModified' failed on the 'required' tag
	            	Key: 'ResourceType.Name' Error:Field validation for 'Name' failed on the 'required' tag
	            	Key: 'ResourceType.Endpoint' Error:Field validation for 'Endpoint' failed on the 'startswith' tag
	            	Key: 'ResourceType.Schema' Error:Field validation for 'Schema' failed on the 'required' tag" should have 3 item(s), but has 9
--- FAIL: TestServiceProviderConfigValidation (0.00s)
        Error Trace:    service_provider_config_test.go:77
	Error:      	"Key: 'ServiceProviderConfig.Common.Schemas' Error:Field validation for 'Schemas' failed on the 'gt' tag
	            	Key: 'ServiceProviderConfig.Common.ID' Error:Field validation for 'ID' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.Common.Meta.Location' Error:Field validation for 'Location' failed on the 'uri' tag
	            	Key: 'ServiceProviderConfig.Common.Meta.ResourceType' Error:Field validation for 'ResourceType' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.Common.Meta.Created' Error:Field validation for 'Created' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.Common.Meta.LastModified' Error:Field validation for 'LastModified' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.Patch.Supported' Error:Field validation for 'Supported' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.Bulk.Supported' Error:Field validation for 'Supported' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.Bulk.MaxOperations' Error:Field validation for 'MaxOperations' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.Bulk.MaxPayloadSize' Error:Field validation for 'MaxPayloadSize' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.Filter.Supported' Error:Field validation for 'Supported' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.Filter.MaxResults' Error:Field validation for 'MaxResults' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.ChangePassword.Supported' Error:Field validation for 'Supported' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.Sort.Supported' Error:Field validation for 'Supported' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.Etag.Supported' Error:Field validation for 'Supported' failed on the 'required' tag
	            	Key: 'ServiceProviderConfig.AuthenticationSchemes' Error:Field validation for 'AuthenticationSchemes' failed on the 'required' tag" should have 10 item(s), but has 16

Canonical form of "not" operator in filtering syntax

RFC7644 is ambiguous about the not trailing space.

ABNF rule say:
FILTER = attrExp / logExp / valuePath / *1"not" "(" FILTER ")" (ie. no trailing space)

But examples have spaces:

filter=userType ne "Employee" and not (emails co "example.com" or emails.value co "example.org")

Currently, the implementation includes a trailing space thus we're assuming that not () is the canonical form, even the parser matches both not () and not().

Maybe it's not problematic.

Resource Interface

Structured and Mapped Resources are different but should be identical for consumers.

For instance, ListResponse needs to use both but currently cannot.

Also, a Resource Interface could totally de-couple core and resource packages.

Since core needs to use Resource Interface it should be defined in the same package, then core could implement it for Structured and resource for Mapped.
Furthermore, third-party could use it to implement other kinds of resource.

However, the two kinds are using attributes in different ways actually I have no clear ideas how the interface should be.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.