All Projects → OvermindDL1 → permission_ex

OvermindDL1 / permission_ex

Licence: other
No description or website provided.

Programming Languages

elixir
2628 projects

Projects that are alternatives of or similar to permission ex

sftp client
An Elixir SFTP Client that wraps Erlang's ssh and ssh_sftp.
Stars: ✭ 29 (+26.09%)
Mutual labels:  elixir-library
fat ecto
Query mechanism for Ecto
Stars: ✭ 20 (-13.04%)
Mutual labels:  elixir-library
ecto autoslug field
Automatically create slugs for Ecto schemas.
Stars: ✭ 138 (+500%)
Mutual labels:  elixir-library
riemannx
A riemann client for elixir (TCP/UDP/TLS supported)
Stars: ✭ 23 (+0%)
Mutual labels:  elixir-library
pardall markdown
Reactive publishing framework, filesystem-based with support for Markdown, nested hierarchies, and instant content rebuilding. Written in Elixir.
Stars: ✭ 84 (+265.22%)
Mutual labels:  elixir-library
smppex
✉️ SMPP 3.4 protocol and framework implementation in Elixir
Stars: ✭ 86 (+273.91%)
Mutual labels:  elixir-library
simple graphql client
SimpleGraphqlClient is a graphql client, focused on simplicity and ease of use.
Stars: ✭ 17 (-26.09%)
Mutual labels:  elixir-library
ex spirit
No description or website provided.
Stars: ✭ 26 (+13.04%)
Mutual labels:  elixir-library
vim-ide-elixir
Highly opininated setup of vim plugins for Elixir development
Stars: ✭ 28 (+21.74%)
Mutual labels:  elixir-library
elixir-revisionair ecto
A Revisionair adapter based on Ecto. Allows you to persist and keep track of revisions of your data structures in any of Ecto's supported databases.
Stars: ✭ 18 (-21.74%)
Mutual labels:  elixir-library
sockerl
Sockerl is an advanced Erlang/Elixir socket framework for TCP protocols and provides fast, useful and easy-to-use API for implementing servers, clients and client connection pools.
Stars: ✭ 26 (+13.04%)
Mutual labels:  elixir-library
nested filter
Providing Map#drop (by key or value) and Map#take functionality for nested maps
Stars: ✭ 32 (+39.13%)
Mutual labels:  elixir-library
mix systemd
Library of mix tasks to generate a systemd unit file for an Elixir project
Stars: ✭ 48 (+108.7%)
Mutual labels:  elixir-library
emojix
Simple emoji library for Elixir 💩
Stars: ✭ 21 (-8.7%)
Mutual labels:  elixir-library
ex loader
Load a single beam file, apps (a set of beams), or an erlang release (a set of apps) to a node.
Stars: ✭ 12 (-47.83%)
Mutual labels:  elixir-library
director
Director is a production-ready supervisor and manager for Erlang/Elixir processes that focuses on speed, performance and flexibility.
Stars: ✭ 62 (+169.57%)
Mutual labels:  elixir-library
minerva
Elixir framework for easily writing koans.
Stars: ✭ 13 (-43.48%)
Mutual labels:  elixir-library
libsalty
Elixir bindings for libsodium (NIF)
Stars: ✭ 20 (-13.04%)
Mutual labels:  elixir-library

PermissionEx

A simple Struct-based Permission system for Elixir. Created to be used with Phoenix but has no requirement or any real integration with it as this is designed to be entirely generic.

Installation

Available on Hex, the package can be installed by adding permission_ex to the list of dependencies in mix.exs:

def deps do
  [{:permission_ex, "~> 0.6.0"}]
end

Features

This is the current feature set of what is done, planned, and thought about. If any feature is not done yet or if any feature wants to be added that is not on this list then please open an issue and/or pull request to have it get done faster.

  • Permission Matcher to test permissions against a requirement.
  • Admin Permission Matcher to pre-authorize before testing normal permissions.
  • This currently works well with the canada library, but is there anything that can be done to make it even more simple?
  • Maybe add some more Permission specialties, such as maybe a {:range, lower, upper} test, maybe a function call test?
  • Maybe add helpers for serializing the structs to/from json by using Poison.
  • Maybe add helpers to serialize the structs in other ways? If so then into what ways?
  • Maybe a deny Permission Matcher to hard deny before admin is tested.
  • Maybe add support to take a list of requirements and test each so all must have a match.
  • Maybe Create plugs to test permissions and either set a variable or kill/redirect the plug chain.

Usage

General usage will usually be something like reading either a tagged map or a specific permission set from, say, a database or elsewhere, then comparing it to a specific requirement.

For example, say you have this phoenix controller method:

def show(conn, _params) do
  conn
  |> render("index.html")
end

And if you have a permission set from the logged in user (or you can pre-fill an anonymous user permission set, or leave empty if anon should have no access to anything), say you have it on conn.assigns.perms and it is a tagged map, then you could test it like this:

def show(conn, _params) do
  if PermissionEx.test_tagged_permissions(MyApp.Perms.IndexPage{action: :show}, conn.assigns.perms) do
    conn
    |> render("index.html")
  else
    conn
    |> render("unauthorized.html")
  end
end

Examples

Please see PermissionEx for detailed examples.

All of the examples use these as the example structs:

defmodule PermissionEx.Test.Structs.User do
  @moduledoc false
  @derive [Poison.Encoder]
  defstruct name: nil
end

defmodule PermissionEx.Test.Structs.Page do
  @moduledoc false
  @derive [Poison.Encoder]
  defstruct action: nil
end

defmodule PermissionEx.Test.Structs.PageReq do
  @moduledoc false
  @derive [Poison.Encoder]
  defstruct action: nil
end

defmodule PermissionEx.Test.Structs.PagePerm do
  @moduledoc false
  @derive [Poison.Encoder]
  defstruct action: nil
end

Testing a specific permission: PermissionEx.test_permission/2

The required permission is the first argument, the allowed permission is on the right.

  • Normal usage would be something like:

    permissions = [:show, :edit] # From somewhere else
    PermissionEx.test_permission(:show, permissions) # => true
    PermissionEx.test_permission(:admin, permissions) # => true
  • Identical things match:

    PermissionEx.test_permission(:anything_identical, :anything_identical) # => true
    PermissionEx.test_permission("anything identical", "anything identical") # => true
  • Anything matches the atom :_:

    PermissionEx.test_permission(:_, :_) # => true
    PermissionEx.test_permission(:_, :anything) # => true
    PermissionEx.test_permission(:anything, :_) # => true
  • If the permission is a [:any | permissions] then each permission in the list will be tested individually for if they match the requirement, and if any test true then this will be true:

    PermissionEx.test_permission(:show, [:any]) # => false
    PermissionEx.test_permission(:show, [:any, :show]) # => true
    PermissionEx.test_permission(:show, [:any, :show, :edit]) # => true
    PermissionEx.test_permission(:show, [:any, :edit, :show]) # => true
    PermissionEx.test_permission(:show, [:any, :edit, :otherwise]) # => false
  • If an atom and binary fail to match, they will be tested again with the required atom being to_string'd, good for if loading from JSON or so, such as in:

    PermissionEx.test_permission(:show, ["any", :edit, :show]) # => true
    PermissionEx.test_permission(:show, ["any", "edit", "show"]) # => true
    PermissionEx.test_permission(:show, "show") # => true

Testing a permission set against a requirement struct: PermissionEx.test_permissions/2

You can test a struct requirement against a permission map or list or maps or even against override values such as in:

  • Via an override, where true or :_ allows the entire requirement, and where false, nil, an empty list [], or an empty map or struct %{} return false:

    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, :_) # => true
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, true) # => true
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, false) # => false
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, nil) # => false
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, []) # => false
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %{}) # => false
  • Or via a map or struct, structs tend to be better if the default values for the struct align with the needs better, if anything in a map is missing that a requirement tests for then it will return false:

    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %{action: :_}) # => true
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %{action: true}) # => false
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %{action: [:any, :edit, :show]}) # => true
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %PermissionEx.Test.Structs.Page{}) # => false
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %PermissionEx.Test.Structs.Page{action: :edit}) # => false
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %PermissionEx.Test.Structs.Page{action: :show}) # => true
  • Or a list of any of the above, any overrides, maps, or structs:

    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, [true]) # => true
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, [false]) # => false
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, [%{action: :edit}]) # => false
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, [%{action: :show}]) # => true
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, [%PermissionEx.Test.Structs.Page{action: :edit}]) # => false
    PermissionEx.test_permissions(%PermissionEx.Test.Structs.Page{action: :show}, [%PermissionEx.Test.Structs.Page{action: :show}]) # => true

Testing a tagged permission set against a requirement struct: PermissionEx.test_tagged_permissions/2

You can test a struct requirement against a map of permissions keyed on the requirement structs :__struct__ value.

There is also an override key of :admin, this is another tagged permission map or an override that is tested before the main permissions are tested.

  • The permission map is just a map of the permission sets, so for example:

    PermissionEx.test_tagged_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %{PermissionEx.Test.Structs.Page => %{}}) # => false
    PermissionEx.test_tagged_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %{PermissionEx.Test.Structs.Page => %PermissionEx.Test.Structs.Page{action: :show}}) # =>true
    PermissionEx.test_tagged_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %{PermissionEx.Test.Structs.Page => %PermissionEx.Test.Structs.Page{action: :_}}) # => true
    PermissionEx.test_tagged_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %{PermissionEx.Test.Structs.Page => %PermissionEx.Test.Structs.Page{action: nil}}) # => false
  • Do note, the permission map is keyed on the requirement struct, not on the struct of its value, this allows you to define a different struct for the permission side that could have certain default values to be set to what you want, such as in:

    PermissionEx.test_tagged_permissions(%PermissionEx.Test.Structs.PageReq{action: :show}, %{PermissionEx.Test.Structs.PageReq => [%PermissionEx.Test.Structs.PagePerm{action: :_}]}) # => true
    PermissionEx.test_tagged_permissions(%PermissionEx.Test.Structs.PageReq{action: :show}, %{PermissionEx.Test.Structs.PagePerm => [%PermissionEx.Test.Structs.PagePerm{action: :_}]}) # => false
  • If there is an :admin key on the struct, then it is checked first, this allows you to set up easy overrides for all or specific matches:

    # Can override and allow absolutely everything by just setting admin: true
    PermissionEx.test_tagged_permissions(%PermissionEx.Test.Structs.Page{}, %{admin: true}) # => true
    
    # Or can set it on a specific struct, it will not affect others then:
    PermissionEx.test_tagged_permissions(%PermissionEx.Test.Structs.Page{}, %{admin: %{PermissionEx.Test.Structs.Page => true}}) # => true
    
    PermissionEx.test_tagged_permissions(%PermissionEx.Test.Structs.User{}, %{admin: %{PermissionEx.Test.Structs.Page => true}}) # => false
    
    # Can do fine-tuned matching as well if an override is needed, it will not allow non-matches
    PermissionEx.test_tagged_permissions(%PermissionEx.Test.Structs.Page{action: :show}, %{admin: %{PermissionEx.Test.Structs.Page => %{action: :show}}}) # => true
    PermissionEx.test_tagged_permissions(%PermissionEx.Test.Structs.Page{action: :edit}, %{admin: %{PermissionEx.Test.Structs.Page => %{action: :show}}}) # => false
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].