diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..81dcaf00 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +########################################################################## +# GO BUILDER +########################################################################## +FROM golang:1.13-buster AS builder + +WORKDIR /build/scim + +COPY . ./ + +RUN make build + +########################################################################## +# FINAL IMAGE +########################################################################## +FROM debian:buster-slim + +# copy binary +COPY --from=builder /build/scim/bin/linux_amd64/scim /usr/bin/scim + +# copy public files +COPY --from=builder /build/scim/public /usr/share/scim/public + +# run +CMD ["/usr/bin/scim"] diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..05a7af4c --- /dev/null +++ b/Makefile @@ -0,0 +1,60 @@ +.PHONY: all build deps binary test doc + +OK_COLOR=\033[32;01m +NO_COLOR=\033[0m +ERROR_COLOR=\033[31;01m +WARN_COLOR=\033[33;01m + +NOW = $(shell date -u '+%Y%m%d%I%M%S') + +DOCKER := docker +GO := go +GO_ENV := $(shell $(GO) env GOOS GOARCH) +GOOS ?= $(word 1,$(GO_ENV)) +GOARCH ?= $(word 2,$(GO_ENV)) +GOFLAGS ?= $(GOFLAGS:) +ROOT_DIR := $(realpath .) + +# GOOS/GOARCH of the build host, used to determine whether we're cross-compiling or not +BUILDER_GOOS_GOARCH="$(GOOS)_$(GOARCH)" + +ifneq ($(GOOS), darwin) + EXTLDFLAGS = # EXTLDFLAGS = -extldflags "-lm -lstdc++ -static" +else + EXTLDFLAGS = +endif + +GO_LINKER_FLAGS ?= --ldflags \ + '$(EXTLDFLAGS) -s -w ' + +all: build + +build: deps binary + +deps: + @echo "$(OK_COLOR)==> Fetching dependencies...$(NO_COLOR)" + $(GO) mod download + +binary: + @echo "$(OK_COLOR)==> Building binary ($(GOOS)/$(GOARCH))...$(NO_COLOR)" + $(GO) build -a $(GOFLAGS) $(GO_LINKER_FLAGS) -o bin/$(GOOS)_$(GOARCH)/scim + +test: deps + @echo "$(OK_COLOR)==> Running tests...$(NO_COLOR)" + $(GO) test $(GOFLAGS) -race ./... + +doc: + mkdir -p /tmp/tmpgoroot/doc + rm -rf /tmp/tmpgopath/src/github.com/imulab/go-scim + mkdir -p /tmp/tmpgopath/src/github.com/imulab/go-scim + tar -c --exclude='.git' --exclude='tmp' . | tar -x -C /tmp/tmpgopath/src/github.com/imulab/go-scim + @echo "$(OK_COLOR)==> Open http://localhost:6060/pkg/github.com/imulab/go-scim$(NO_COLOR)" + GOROOT=/tmp/tmpgoroot/ GOPATH=/tmp/tmpgopath/ godoc -http=localhost:6060 + +docker: + @echo "$(OK_COLOR)==> Building image scim:latest$(NO_COLOR)" + docker build -t scim:latest . + +compose: + @echo "$(OK_COLOR)==> Starting local stack$(NO_COLOR)" + docker-compose up \ No newline at end of file diff --git a/README.md b/README.md index b245d972..2c19bc2e 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,30 @@ -# GoSCIM - - + > GoSCIM aims to be a fully featured implementation of [SCIM v2](http://www.simplecloud.info/) specification. It provides opinion-free and extensible building blocks, as well as an opinionated server implementation. -## T.L.D.R +## :rocket: TLDR + +###### *Requirements:* [Docker](https://docs.docker.com/get-started/) and [Docker Compose](https://docs.docker.com/compose/gettingstarted/) ```bash -make -docker-compose up --build +# Builds docker image and starts local docker-compose stack +make docker compose ``` -## Project structure +## :file_folder: Project structure Since v1, the project has grown into three independent modules. -- `github.com/imulab/go-scim/pkg/v2` module evolved from most of the original building blocks. This module provides -customizable, extensible and opinion free implementation of the SCIM specification. -- `github.com/imulab/go-scim/mongo/v2` module evolved from the original mongo package. This module provides persistence -capabilities to MongoDB. -- `github.com/imulab/go-scim` module evolved from the original example server implementation. It is now a __opinionated__ -personal server implementation that depends on the above two modules. +- [pkg module](https://github.com/imulab/go-scim/tree/master/pkg/v2) evolved from most of the original building blocks. +This module provides customizable, extensible and opinion free implementation of the SCIM specification. +- [mongo module](https://github.com/imulab/go-scim/tree/master/mongo/v2) evolved from the original mongo package. +This module provides persistence capabilities to MongoDB. +- [server module](https://github.com/imulab/go-scim) evolved from the original example server implementation. It is now +an __opinionated__ personal server implementation that depends on the above two modules. -Documentation for the [pkg](https://github.com/imulab/go-scim/tree/master/pkg/v2) and [mongo](https://github.com/imulab/go-scim/tree/master/mongo/v2) module can be viewed in their respective directories. +Documentation for the individual modules can be viewed in their respective directories and godoc badge links. -## End of v1 +## :no_entry_sign: End of v1 Due to limited time and resource and a drastic new design in v2, the building blocks and mongo package from v1 will no longer be maintained. The `github.com/imulab/go-scim` will go on as an opinionated personal implementation, which may or diff --git a/cmd/api/context.go b/cmd/api/context.go index 72affec2..abe3fe00 100644 --- a/cmd/api/context.go +++ b/cmd/api/context.go @@ -2,6 +2,7 @@ package api import ( "context" + "github.com/imulab/go-scim/cmd/internal/groupsync" scimmongo "github.com/imulab/go-scim/mongo/v2" "github.com/imulab/go-scim/pkg/v2/db" "github.com/imulab/go-scim/pkg/v2/service" @@ -348,6 +349,10 @@ func (ctx *applicationContext) RabbitMQChannel() *amqp.Channel { ctx.logInitFailure("rabbit channel", err) panic(err) } + if err := groupsync.DeclareQueue(c); err != nil { + ctx.logInitFailure("rabbit channel", err) + panic(err) + } ctx.rabbitMqChannel = c ctx.logInitialized("rabbit channel") } diff --git a/cmd/groupsync/consumer.go b/cmd/groupsync/consumer.go index 1bfff1b8..725f1b3d 100644 --- a/cmd/groupsync/consumer.go +++ b/cmd/groupsync/consumer.go @@ -35,10 +35,12 @@ func (c *consumer) Start(ctx context.Context) (safeExit chan struct{}, err error nil, ) if err != nil { - c.logger.Err(err).Msg("Failed to consume message") + c.logger.Err(err).Msg("failed to consume message") return } + c.logger.Info().Msg("group sync consumer starts to listen for messages") + safeExit = make(chan struct{}, 1) go func() { diff --git a/cmd/groupsync/context.go b/cmd/groupsync/context.go index 396d30c9..aecde596 100644 --- a/cmd/groupsync/context.go +++ b/cmd/groupsync/context.go @@ -2,6 +2,7 @@ package groupsync import ( "context" + gs "github.com/imulab/go-scim/cmd/internal/groupsync" scimmongo "github.com/imulab/go-scim/mongo/v2" "github.com/imulab/go-scim/pkg/v2/db" "github.com/imulab/go-scim/pkg/v2/groupsync" @@ -177,6 +178,10 @@ func (ctx *applicationContext) RabbitMQChannel() *amqp.Channel { ctx.logInitFailure("rabbit channel", err) panic(err) } + if err := gs.DeclareQueue(c); err != nil { + ctx.logInitFailure("rabbit channel", err) + panic(err) + } ctx.rabbitMqChannel = c ctx.logInitialized("rabbit channel") } diff --git a/cmd/internal/groupsync/rabbit.go b/cmd/internal/groupsync/rabbit.go index e1536b7d..388b4d36 100644 --- a/cmd/internal/groupsync/rabbit.go +++ b/cmd/internal/groupsync/rabbit.go @@ -1,7 +1,22 @@ package groupsync +import "github.com/streadway/amqp" + // Queue name in RabbitMQ, used by consumer and producer to exchange message. const RabbitQueueName = "group_sync" // Exchange name in RabbitMQ const RabbitExchangeName = "" + +// Declare a queue in RabbitMQ named RabbitQueueName. +func DeclareQueue(ch *amqp.Channel) error { + _, err := ch.QueueDeclare( + RabbitQueueName, + true, + false, + false, + false, + nil, + ) + return err +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..04210d2d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,107 @@ +version: "3" +services: + mediainit: + image: alpine:3.10 + entrypoint: /bin/sh -c "chown -v nobody:nogroup /data/db && chmod -v 777 /data/db" + container_name: mediainit + restart: "no" + volumes: + - 'mongo_data:/data/db' + + db: + image: "bitnami/mongodb:latest" + environment: + - MONGODB_EXTRA_FLAGS=--wiredTigerCacheSizeGB=2 --bind_ip_all + - MONGODB_USERNAME=user + - MONGODB_PASSWORD=password123 + - MONGODB_DATABASE=scim_database + volumes: + - 'mongo_data:/data/db' + ports: + - '27017:27017' + networks: + - app-tier + + rabbit: + image: "bitnami/rabbitmq:latest" + environment: + - RABBITMQ_USERNAME=user + - RABBITMQ_PASSWORD=password123 + - RABBITMQ_NODE_NAME=user@rabbit + ports: + - '4369:4369' + - '5672:5672' + - '25672:25672' + - '15672:15672' + networks: + - app-tier + volumes: + - 'rabbitmq_data:/bitnami' + + group: + image: "scim:latest" + build: + context: . + command: ["/usr/bin/scim", "group-sync"] + environment: + - REQUEUE_LIMIT=1 + - MONGO_HOST=db + - MONGO_PORT=27017 + - MONGO_USERNAME=user + - MONGO_PASSWORD=password123 + - MONGO_DATABASE=scim_database + - MONGO_OPT=authMechanism=SCRAM-SHA-1 + - RABBIT_HOST=rabbit + - RABBIT_PORT=5672 + - RABBIT_USERNAME=user + - RABBIT_PASSWORD=password123 + - SERVICE_PROVIDER_CONFIG=/usr/share/scim/public/service_provider_config.json + - SCHEMAS_DIR=/usr/share/scim/public/schemas + - USER_RESOURCE_TYPE=/usr/share/scim/public/resource_types/user_resource_type.json + - GROUP_RESOURCE_TYPE=/usr/share/scim/public/resource_types/group_resource_type.json + - MONGO_METADATA_DIR=/usr/share/scim/public/mongo_metadata + networks: + - app-tier + depends_on: + - db + - rabbit + + server: + image: "scim:latest" + build: + context: . + command: ["/usr/bin/scim", "api"] + environment: + - HTTP_PORT=5000 + - MONGO_HOST=db + - MONGO_PORT=27017 + - MONGO_USERNAME=user + - MONGO_PASSWORD=password123 + - MONGO_DATABASE=scim_database + - MONGO_OPT=authMechanism=SCRAM-SHA-1 + - RABBIT_HOST=rabbit + - RABBIT_PORT=5672 + - RABBIT_USERNAME=user + - RABBIT_PASSWORD=password123 + - SERVICE_PROVIDER_CONFIG=/usr/share/scim/public/service_provider_config.json + - SCHEMAS_DIR=/usr/share/scim/public/schemas + - USER_RESOURCE_TYPE=/usr/share/scim/public/resource_types/user_resource_type.json + - GROUP_RESOURCE_TYPE=/usr/share/scim/public/resource_types/group_resource_type.json + - MONGO_METADATA_DIR=/usr/share/scim/public/mongo_metadata + ports: + - "5000:5000" + networks: + - app-tier + depends_on: + - db + - rabbit + +volumes: + rabbitmq_data: + driver: local + mongo_data: + driver: local + +networks: + app-tier: + driver: bridge \ No newline at end of file diff --git a/godoc.sh b/godoc.sh deleted file mode 100755 index 5eb460be..00000000 --- a/godoc.sh +++ /dev/null @@ -1,8 +0,0 @@ -#/bin/bash - -mkdir -p /tmp/tmpgoroot/doc -rm -rf /tmp/tmpgopath/src/github.com/imulab/go-scim -mkdir -p /tmp/tmpgopath/src/github.com/imulab/go-scim -tar -c --exclude='.git' --exclude='tmp' . | tar -x -C /tmp/tmpgopath/src/github.com/imulab/go-scim -echo -e "open http://localhost:6060/pkg/github.com/imulab/go-scim\n" -GOROOT=/tmp/tmpgoroot/ GOPATH=/tmp/tmpgopath/ godoc -http=localhost:6060 \ No newline at end of file diff --git a/mongo/v2/README.md b/mongo/v2/README.md index cccc1140..05a4edd4 100644 --- a/mongo/v2/README.md +++ b/mongo/v2/README.md @@ -1,8 +1,19 @@ # MongoDB Module +[![GoDoc](https://godoc.org/github.com/imulab/go-scim/mongo/v2?status.svg)](https://godoc.org/github.com/imulab/go-scim/mongo/v2) + This module provides the capability to persist SCIM resources in MongoDB. -## Persistence +## :bulb: Usage + +To get this package: + +```bash +# make sure Go 1.13 +go get github.com/imulab/go-scim/mongo/v2 +``` + +## :floppy_disk: Persistence This basic `db.DB` implementation in this module assumes one-to-one mapping between a SCIM resource type and a MongoDB collection. @@ -46,7 +57,7 @@ specifies the path name from the document root. Use `ReadMetadata` to register b The module utilizes the atomicity of MongoDB and safely performs modification operations without explicitly locking the resource. `Replace` and `Delete` operations would only perform data modification if the `id` and `meta.version` fields -matches the record in MongoDB. If no match was found, a `preCondition` error is returned to indicate some current process +matches the record in MongoDB. If no match was found, a `conflict` error is returned to indicate some current process must have modified the resource in between. ### Projection @@ -57,10 +68,10 @@ This is done intentionally, as `db.DB` is not a client facing component with res parameters supplied should have been pre-sanitized so that it does not contradict with the `returned` property. There are also cases where callers may wish to carry out operations after the query on fields not requested by the client. -In this case, callers can use `DBOptions.IgnoreProjection()` to disable projection altogether so the database always +In this case, callers can use `Options.IgnoreProjection()` to disable projection altogether so the database always return the full version of the resource. -## Serialization +## :black_nib: Serialization This module provides direct serialization and de-deserialization between SCIM resource and MongoDB BSON format, without the transition of an intermediary data format. @@ -68,7 +79,7 @@ the transition of an intermediary data format. The serialization of the less significant components like filter, sort, pagination and projection are still being converted to `bson.D`, before being serialized to BSON and sent to MongoDB. -## Testing +## :construction: Testing This module uses [org/dockertest](https://github.com/ory/dockertest) to setup testing docker containers at test run time. The environment variables to customize the local docker connection are: diff --git a/pkg/v2/README.md b/pkg/v2/README.md index 4b0f9eb2..aa099f1a 100644 --- a/pkg/v2/README.md +++ b/pkg/v2/README.md @@ -1,5 +1,7 @@ # SCIM +[![GoDoc](https://godoc.org/github.com/imulab/go-scim/pkg/v2?status.svg)](https://godoc.org/github.com/imulab/go-scim/pkg/v2) + This module implements features described in [RFC 7643 - SCIM: Core Schema](https://tools.ietf.org/html/rfc7643) and [RFC 7644 - SCIM: Protocol](https://tools.ietf.org/html/rfc7644), along with custom features that address specific implementation difficulties. @@ -19,7 +21,7 @@ It is not the goal of this package to enable every possible use case, or to prov > > We apologize for any inconvenience caused by this decision. The original v1 can still be checked out via tags. -## Usage +## :bulb: Usage To get this package: @@ -28,7 +30,7 @@ To get this package: go get github.com/imulab/go-scim/pkg/v2 ``` -## Features in v2 +## :gift: Features in v2 - :free: Reflection free operations on resources - :mailbox_with_mail: Property subscribers @@ -37,7 +39,7 @@ go get github.com/imulab/go-scim/pkg/v2 - :thumbsup: Robust SCIM path and filter parsing - :fast_forward: Resource filters to allow for custom resource processing -## Project Structure +## :file_folder: Project Structure Features in this module are separated into different directories: - `spec` directory implements the foundation of SCIM resource type definition @@ -52,7 +54,7 @@ Features in this module are separated into different directories: For detailed documentation, please check out README of individual directories, or GoDoc. -## Road Map +## :bullettrain_side: Road Map After delivering the v2.0.0 which will cover most features, efforts will be directed toward: - ResourceType(s) and Schema(s) endpoints (see [issue 40](https://github.com/imulab/go-scim/issues/40))