ExScimEcto
Ecto-based storage adapter for ExScim. Provides persistent storage for SCIM Users and Groups backed by any Ecto-compatible database.
Installation
Add ex_scim_ecto to your dependencies:
def deps do
[
{:ex_scim_ecto, "~> 0.1"}
]
endConfiguration
Basic setup
config :ex_scim,
storage_strategy: ExScimEcto.StorageAdapter,
storage_repo: MyApp.Repo,
user_model: MyApp.Accounts.User,
group_model: MyApp.Groups.GroupPreloading associations
config :ex_scim,
storage_repo: MyApp.Repo,
user_model: {MyApp.Accounts.User, preload: [:roles, :organizations]},
group_model: {MyApp.Groups.Group, preload: [:members]}Custom lookup key
By default, resources are looked up by :id. To use a different column:
config :ex_scim,
user_model: {MyApp.Accounts.User, lookup_key: :resource_id},
group_model: {MyApp.Groups.Group, lookup_key: :uuid}Filter mapping
Map SCIM complex attribute paths to database columns:
config :ex_scim,
user_model: {MyApp.Accounts.User,
filter_mapping: %{
"emails.value" => :email,
"name.givenName" => :given_name
}}
For association-based filtering (e.g. filtering on a has_many relation):
config :ex_scim,
user_model: {MyApp.Accounts.User,
preload: [:user_emails],
filter_mapping: %{
"emails.value" => {:assoc, :user_emails, :value},
"emails.type" => {:assoc, :user_emails, :type}
}}Multi-tenant scoping
Scope all queries by a tenant discriminator column:
config :ex_scim,
user_model: {MyApp.Accounts.User, tenant_key: :organization_id},
group_model: {MyApp.Groups.Group, tenant_key: :organization_id}Field mapping
Map domain fields to database columns with value transformation:
config :ex_scim,
user_model: {MyApp.Accounts.User,
field_mapping: %{
active: {:status,
fn true -> "active"; false -> "inactive" end,
fn "active" -> true; _ -> false end}
}}
Each entry is domain_field => {db_field, to_storage_fn, from_storage_fn}.
Ecto schema requirements
Your Ecto schema must define a changeset/2 function that the adapter will call for inserts and updates:
defmodule MyApp.Accounts.User do
use Ecto.Schema
schema "users" do
field :user_name, :string
field :display_name, :string
# ...
timestamps()
end
def changeset(user, attrs) do
user
|> cast(attrs, [:user_name, :display_name])
|> validate_required([:user_name])
end
end