Skip to content

Commit 172bf2a

Browse files
q-uinticamys
andauthored
Various QOL changes. (#169)
* Various QOL changes. * Move filter package out of internal. * Expose filter validator. * feat: create server instance using constructor, use interface-based logger * fix: update server construction code * fix: correct resource type auto renaming * fix: correct resource type auto renaming * docs: correct the example in the docs * feat: change server constructor to accept mandatory arguments * Arrange code + tidy. * Fix typo. * Fix merge conflict. * Add note about backwards compatibility. * Fix typo README. --------- Co-authored-by: Dmitrii Prisacari <[email protected]>
1 parent df55fde commit 172bf2a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+981
-543
lines changed

.github/workflows/pull_request.yml

+10-10
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,37 @@ jobs:
33
arrange:
44
runs-on: ubuntu-latest
55
steps:
6-
- uses: actions/checkout@v2
7-
- uses: actions/setup-go@v2
6+
- uses: actions/checkout@v4
7+
- uses: actions/setup-go@v5
88
with:
99
go-version: '1.16'
10-
- run: go get github.com/jdeflander/goarrange
10+
- run: go install github.com/jdeflander/goarrange@v1.0.0
1111
working-directory: ${{ runner.temp }}
1212
- run: test -z "$(goarrange run -r -d)"
1313

1414
lint:
1515
runs-on: ubuntu-latest
1616
steps:
17-
- uses: actions/checkout@v2
18-
- uses: golangci/golangci-lint-action@v2
17+
- uses: actions/checkout@v4
18+
- uses: golangci/golangci-lint-action@v4
1919
with:
20-
version: v1.39
20+
version: 'v1.56.2'
2121
args: -E misspell,godot,whitespace
2222

2323
test:
2424
runs-on: ubuntu-latest
2525
steps:
26-
- uses: actions/checkout@v2
27-
- uses: actions/setup-go@v2
26+
- uses: actions/checkout@v4
27+
- uses: actions/setup-go@v5
2828
with:
2929
go-version: '1.16'
3030
- run: go test -v ./...
3131

3232
tidy:
3333
runs-on: ubuntu-latest
3434
steps:
35-
- uses: actions/checkout@v2
36-
- uses: actions/setup-go@v2
35+
- uses: actions/checkout@v4
36+
- uses: actions/setup-go@v5
3737
with:
3838
go-version: '1.16'
3939
- run: go mod tidy

Makefile

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
.PHONY: all arrange tidy lint test
2+
3+
all: arrange tidy lint test
4+
5+
arrange:
6+
@echo "Arranging files..."
7+
@go fmt ./...
8+
@goarrange run -r
9+
10+
tidy:
11+
@echo "Tidying up..."
12+
@go mod tidy
13+
14+
lint:
15+
@echo "Linting files..."
16+
@go vet ./...
17+
@golangci-lint run ./... -E misspell,godot,whitespace
18+
19+
test:
20+
@echo "Running tests..."
21+
@go test ./... -cover

README.md

+61-10
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,56 @@
33
[![GoVersion](https://img.shields.io/github/go-mod/go-version/elimity-com/scim.svg)](https://github.com/elimity-com/scim)
44
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/elimity-com/scim)
55

6-
76
[![Tag](https://img.shields.io/github/tag/elimity-com/scim.svg)](https://gitHub.com/elimity-com/scim/releases)
87

9-
This is an open source implementation of the [SCIM v2.0](http://www.simplecloud.info/#Specification) specification for use in Golang.
8+
This is an open source implementation of the [SCIM v2.0](http://www.simplecloud.info/#Specification) specification for
9+
use in Golang.
1010
SCIM defines a flexible schema mechanism and REST API for managing identity data.
11-
The goal is to reduce the complexity of user management operations by providing patterns for exchanging schemas using HTTP.
11+
The goal is to reduce the complexity of user management operations by providing patterns for exchanging schemas using
12+
HTTP.
1213

1314
In this implementation it is easy to add *custom* schemas and extensions with the provided structures.
1415
Incoming resources will be *validated* by their corresponding schemas before being passed on to their callbacks.
1516

1617
The following features are supported:
18+
1719
- GET for `/Schemas`, `/ServiceProviderConfig` and `/ResourceTypes`
1820
- CRUD (POST/GET/PUT/DELETE and PATCH) for your own resource types (i.e. `/Users`, `/Groups`, `/Employees`, ...)
1921

2022
Other optional features such as sorting, bulk, etc. are **not** supported in this version.
2123

2224
## Installation
25+
2326
Assuming you already have a (recent) version of Go installed, you can get the code with go get:
27+
2428
```bash
2529
$ go get github.com/elimity-com/scim
2630
```
2731

2832
## Usage
33+
2934
**!** errors are ignored for simplicity.
35+
3036
### 1. Create a service provider configuration.
37+
3138
[RFC Config](https://tools.ietf.org/html/rfc7643#section-5) |
3239
[Example Config](https://tools.ietf.org/html/rfc7643#section-8.5)
40+
3341
```go
3442
config := scim.ServiceProviderConfig{
3543
DocumentationURI: optional.NewString("www.example.com/scim"),
3644
}
3745
```
46+
3847
**!** no additional features/operations are supported in this version.
3948

4049
### 2. Create all supported schemas and extensions.
50+
4151
[RFC Schema](https://tools.ietf.org/html/rfc7643#section-2) |
4252
[User Schema](https://tools.ietf.org/html/rfc7643#section-4.1) |
4353
[Group Schema](https://tools.ietf.org/html/rfc7643#section-4.2) |
4454
[Extension Schema](https://tools.ietf.org/html/rfc7643#section-4.3)
55+
4556
```go
4657
schema := schema.Schema{
4758
ID: "urn:ietf:params:scim:schemas:core:2.0:User",
@@ -72,18 +83,23 @@ extension := schema.Schema{
7283
```
7384

7485
### 3. Create all resource types and their callbacks.
86+
7587
[RFC Resource Type](https://tools.ietf.org/html/rfc7643#section-6) |
7688
[Example Resource Type](https://tools.ietf.org/html/rfc7643#section-8.6)
7789

7890
#### 3.1 Callback (implementation of `ResourceHandler`)
91+
7992
[Simple In Memory Example](resource_handler_test.go)
93+
8094
```go
8195
var userResourceHandler scim.ResourceHandler
8296
// initialize w/ own implementation
8397
```
98+
8499
**!** each resource type should have its own resource handler.
85100

86101
#### 3.2 Resource Type
102+
87103
```go
88104
resourceTypes := []ResourceType{
89105
{
@@ -101,44 +117,79 @@ resourceTypes := []ResourceType{
101117
```
102118

103119
### 4. Create Server
120+
104121
```go
105-
server := Server{
106-
Config: config,
122+
serverArgs := &ServerArgs{
123+
ServiceProviderConfig: config,
107124
ResourceTypes: resourceTypes,
108125
}
126+
127+
serverOpts := []ServerOption{
128+
WithLogger(logger), // optional, default is no logging
129+
}
130+
131+
server, err := NewServer(serverArgs, serverOpts...)
132+
```
133+
134+
## Backwards Compatibility
135+
136+
Even though the SCIM package has been running in some production environments, it is still in an early stage, and not
137+
all features are supported. So be aware that a change in the minor version could break your implementation. We will not
138+
make any breaking changes that takes hours to fix, but some functions might change name or signature.
139+
140+
This was the case for `v0.1` to `v0.2.0`.
141+
142+
## String Values for Attributes
143+
144+
By default, the SCIM server will NOT use the `string` type for all attributes, since this is NOT compliant with the
145+
SCIM specification. It is still possible to enable this behavior by toggling a flag within the `schema` package.
146+
147+
```go
148+
import "github.com/elimity-com/scim/schema"
149+
150+
schema.SetAllowStringValues(true)
109151
```
110152

111153
## Addition Checks/Tests
154+
112155
Not everything can be checked by the SCIM server itself.
113156
Below are some things listed that we expect that the implementation covers.
114157

115158
**!** this list is currently incomplete!
116159

117-
We want to keep this list as short as possible.
160+
We want to keep this list as short as possible.
118161
If you have ideas how we could enforce these rules in the server itself do not hesitate to open
119162
[an issue](https://github.com/elimity-com/scim/issues/new) or a PR.
163+
120164
### Mutability
165+
121166
#### Immutable Attributes
167+
122168
*PUT Handler*: If one or more values are already set for the attribute, the input value(s) MUST match.
169+
123170
#### WriteOnly Attributes
171+
124172
*ALL Handlers*: Attribute values SHALL NOT be returned. \
125173
Note: These attributes usually also has a returned setting of "never".
126174

127175
## Contributing
176+
128177
[![Contributors](https://img.shields.io/github/contributors/elimity-com/scim.svg)](https://gitHub.com/elimity-com/scim/contributors/)
129178

130179
We are happy to review pull requests,
131180
but please first discuss the change you wish to make via issue, email,
132181
or any other method with the owners of this repository before making a change.
133182

134183
If you would like to propose a change please ensure the following:
135-
- All checks of GitHub Actions are passing ([GolangCI-Lint](https://github.com/golangci/golangci-lint): `misspell`, `godot` and `whitespace`)
184+
185+
- All checks of GitHub Actions are
186+
passing ([GolangCI-Lint](https://github.com/golangci/golangci-lint): `misspell`, `godot` and `whitespace`)
136187
- All already existing tests are passing.
137188
- You have written tests that cover the code you are making, make sure to include edge cases.
138189
- There is documentation for at least all public functions you have added.
139190
- New public functions and structures are kept to a minimum.
140191
- The same practices are applied (such as the anatomy of methods, names, etc.)
141192
- Your changes are compliant with SCIM v2.0 (released as
142-
[RFC7642](https://tools.ietf.org/html/rfc7642),
143-
[RFC7643](https://tools.ietf.org/html/rfc7643) and
144-
[RFC7644](https://tools.ietf.org/html/rfc7644) under [IETF](https://ietf.org/)).
193+
[RFC7642](https://tools.ietf.org/html/rfc7642),
194+
[RFC7643](https://tools.ietf.org/html/rfc7643) and
195+
[RFC7644](https://tools.ietf.org/html/rfc7644) under [IETF](https://ietf.org/)).

examples_test.go

+42-10
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,53 @@
11
package scim
22

33
import (
4-
"log"
4+
logger "log"
55
"net/http"
66
)
77

88
func ExampleNewServer() {
9-
log.Fatal(http.ListenAndServe(":7643", Server{
10-
Config: ServiceProviderConfig{},
11-
ResourceTypes: nil,
12-
}))
9+
args := &ServerArgs{
10+
ServiceProviderConfig: &ServiceProviderConfig{},
11+
ResourceTypes: []ResourceType{},
12+
}
13+
server, err := NewServer(args)
14+
if err != nil {
15+
logger.Fatal(err)
16+
}
17+
logger.Fatal(http.ListenAndServe(":7643", server))
1318
}
1419

1520
func ExampleNewServer_basePath() {
16-
http.Handle("/scim/", http.StripPrefix("/scim", Server{
17-
Config: ServiceProviderConfig{},
18-
ResourceTypes: nil,
19-
}))
20-
log.Fatal(http.ListenAndServe(":7643", nil))
21+
args := &ServerArgs{
22+
ServiceProviderConfig: &ServiceProviderConfig{},
23+
ResourceTypes: []ResourceType{},
24+
}
25+
server, err := NewServer(args)
26+
if err != nil {
27+
logger.Fatal(err)
28+
}
29+
// You can host the SCIM server on a custom path, make sure to strip the prefix, so only `/v2/` is left.
30+
http.Handle("/scim/", http.StripPrefix("/scim", server))
31+
logger.Fatal(http.ListenAndServe(":7643", nil))
32+
}
33+
34+
func ExampleNewServer_logger() {
35+
loggingMiddleware := func(next http.Handler) http.Handler {
36+
fn := func(w http.ResponseWriter, r *http.Request) {
37+
logger.Println(r.Method, r.URL.Path)
38+
39+
next.ServeHTTP(w, r)
40+
}
41+
42+
return http.HandlerFunc(fn)
43+
}
44+
args := &ServerArgs{
45+
ServiceProviderConfig: &ServiceProviderConfig{},
46+
ResourceTypes: []ResourceType{},
47+
}
48+
server, err := NewServer(args)
49+
if err != nil {
50+
logger.Fatal(err)
51+
}
52+
logger.Fatal(http.ListenAndServe(":7643", loggingMiddleware(server)))
2153
}
File renamed without changes.

internal/filter/filter_test.go filter/filter_test.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package filter_test
22

33
import (
4-
internal "github.com/elimity-com/scim/internal/filter"
4+
"github.com/elimity-com/scim/filter"
55
"github.com/elimity-com/scim/schema"
66
"testing"
77
)
@@ -25,7 +25,7 @@ func TestPathValidator_Validate(t *testing.T) {
2525
`urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeNumber`,
2626
`urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager.displayName`,
2727
} {
28-
validator, err := internal.NewPathValidator(f, schema.CoreUserSchema(), schema.ExtensionEnterpriseUser())
28+
validator, err := filter.NewPathValidator(f, schema.CoreUserSchema(), schema.ExtensionEnterpriseUser())
2929
if err != nil {
3030
t.Fatal(err)
3131
}
@@ -47,7 +47,7 @@ func TestPathValidator_Validate(t *testing.T) {
4747
`urn:ietf:params:scim:schemas:core:2.0:User:employeeNumber`,
4848
`urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:userName`,
4949
} {
50-
validator, err := internal.NewPathValidator(f, schema.CoreUserSchema(), schema.ExtensionEnterpriseUser())
50+
validator, err := filter.NewPathValidator(f, schema.CoreUserSchema(), schema.ExtensionEnterpriseUser())
5151
if err != nil {
5252
t.Fatal(err)
5353
}
@@ -92,7 +92,7 @@ func TestValidator_PassesFilter(t *testing.T) {
9292
},
9393
},
9494
} {
95-
validator, err := internal.NewValidator(test.filter, schema.CoreUserSchema())
95+
validator, err := filter.NewValidator(test.filter, schema.CoreUserSchema())
9696
if err != nil {
9797
t.Fatal(err)
9898
}
@@ -137,7 +137,7 @@ func TestValidator_PassesFilter(t *testing.T) {
137137
userSchema := schema.CoreUserSchema()
138138
userSchema.Attributes = append(userSchema.Attributes, schema.SchemasAttributes())
139139
userSchema.Attributes = append(userSchema.Attributes, schema.CommonAttributes()...)
140-
validator, err := internal.NewValidator(test.filter, userSchema)
140+
validator, err := filter.NewValidator(test.filter, userSchema)
141141
if err != nil {
142142
t.Fatal(err)
143143
}
@@ -168,7 +168,7 @@ func TestValidator_PassesFilter(t *testing.T) {
168168
filter: `urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:organization eq "Elimity"`,
169169
},
170170
} {
171-
validator, err := internal.NewValidator(test.filter, schema.ExtensionEnterpriseUser())
171+
validator, err := filter.NewValidator(test.filter, schema.ExtensionEnterpriseUser())
172172
if err != nil {
173173
t.Fatal(err)
174174
}
@@ -212,7 +212,7 @@ func TestValidator_Validate(t *testing.T) {
212212
`userType eq "Employee" and emails[type eq "work" and value co "@example.com"]`,
213213
`emails[type eq "work" and value co "@example.com"] or ims[type eq "xmpp" and value co "@foo.com"]`,
214214
} {
215-
validator, err := internal.NewValidator(f, userSchema)
215+
validator, err := filter.NewValidator(f, userSchema)
216216
if err != nil {
217217
t.Fatal(err)
218218
}
File renamed without changes.
File renamed without changes.

internal/filter/op_boolean_test.go filter/op_boolean_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package filter_test
22

33
import (
44
"fmt"
5-
internal "github.com/elimity-com/scim/internal/filter"
5+
internal "github.com/elimity-com/scim/filter"
66
"github.com/elimity-com/scim/schema"
77
"github.com/scim2/filter-parser/v2"
88
"testing"
File renamed without changes.

internal/filter/op_datetime_test.go filter/op_datetime_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package filter_test
22

33
import (
44
"fmt"
5-
internal "github.com/elimity-com/scim/internal/filter"
5+
internal "github.com/elimity-com/scim/filter"
66
"github.com/elimity-com/scim/schema"
77
"github.com/scim2/filter-parser/v2"
88
"testing"
File renamed without changes.

internal/filter/op_decimal_test.go filter/op_decimal_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package filter_test
22

33
import (
44
"fmt"
5-
internal "github.com/elimity-com/scim/internal/filter"
5+
internal "github.com/elimity-com/scim/filter"
66
"github.com/elimity-com/scim/schema"
77
"github.com/scim2/filter-parser/v2"
88
"testing"
File renamed without changes.

0 commit comments

Comments
 (0)