Coder Social home page Coder Social logo

conductor's Introduction

Conductor

Build Status Hex.pm

Simple package for api authorization.

When is this package good

  • when you need to restrict access to most endpoints when exposing some to third party developers
  • when you don't want to spam your controllers with plugs for every action
  • when you must respond according to existing permission system (e.g. scopes in jwt)

When is this package not good

  • when you need authentication
  • when you need authorization for html pages
  • when you need advanced permissions management system

Installation

def deps do
  [{:conductor, "~> 0.4.0"}]
end

Conductor macro

Basically, this:

defmodule Controller do
  use Conductor # Important! It needs to be before use Phoenix.Controller
  use Phoenix.Controller

  def index(conn, _params),  do: #...

  def show(conn, _params),   do: #...

  @authorize scope: "scope1"
  def create(conn, _params), do: #...

  @authorize scope: {"scope1", "scope2"}
  def update(conn, _params), do: #...

  @authorize scope: "scope2"
  def delete(conn, _params), do: #...
end

will be compiled to this:

defmodule Controller do
  use Conductor
  use Phoenix.Controller

  plug Conductor.Plugs.Authorize, ["scope1"] when action in [:create]
  plug Conductor.Plugs.Authorize, [{"scope1", "scope2"}] when action in [:update]
  plug Conductor.Plugs.Authorize, ["scope2"] when action in [:delete]
  plug Conductor.Plugs.Authorize, [] when not action in [:create, :update, :delete]

  def index(conn, _params),  do: #...
  def show(conn, _params),   do: #...
  def create(conn, _params), do: #...
  def update(conn, _params), do: #...
  def delete(conn, _params), do: #...
end

Root scope

You can register scope that will have full access everywhere

  config :conductor,
    root_scopes: ["admin"]

Adding scopes

  conn |> Plug.Conn.assign(:scopes, ["scope1, scope2"])

Public access

defmodule Router do
  pipeline :public do
    plug Conductor.Plugs.SkipAuthorization
  end

  scope "/public", MyApp do
    pipe_through [:public]

    get "/something", SomethingController, :something
  end
end

Authorization failures

To avoid confusion with random 403 response codes that come from nowhere, Conductor will raise error on authorization failure as default.

This can be changed by following config

  config :conductor,
    on_auth_failure: :send_resp

Example

  #config
  config :conductor,
    root_scopes: ["root_scope"],
    on_auth_failure: :send_resp

  #router
  pipeline :public do
    plug Conductor.Plugs.SkipAuthorization
  end

  scope "/", Example do
    get "/2", Controller, :action2
    get "/3", Controller, :action3
    get "/4", Controller, :action4
    get "/5", Controller, :action5
  end

  scope "/", Example do
    pipe_through [:public]

    get "/1", Controller, :action1
  end

  #conns
  conn1 = Phoenix.ConnTest.build_conn()
  conn2 = conn1 |> Plug.Conn.assign(:scopes, ["scope1"])
  conn3 = conn1 |> Plug.Conn.assign(:scopes, ["scope1", "scope2"])
  conn4 = conn1 |> Plug.Conn.assign(:scopes, ["root_scope"])

  #endpoints
  @authorize scope: "scope1"
  def action1(conn, _params), do: conn |> send_resp(200, "")

  @authorize scope: "scope2"
  def action2(conn, _params), do: conn |> send_resp(200, "")

  @authorize scope: {"scope1", "scope2}
  def action3(conn, _params), do: conn |> send_resp(200, "")

  def action4(conn, _params), do: conn |> send_resp(200, "")

  @authorize scopes: ["other", "unused"]
  def action5(conn, _params), do: conn |> send_resp(200, "")
    | conn1 | conn2 | conn3 | conn4

------- | :---: | :---: | :---: | :---: action1 | 200 | 200 | 200 | 200 action2 | 403 | 200 | 200 | 200 action3 | 403 | 403 | 200 | 200 action4 | 403 | 403 | 403 | 200 action5 | 403 | 403 | 403 | 200

Customization

Global

  • Failure response status code

      # config/config.exs
      config :conductor, :failure_status, 418
  • Failure response body

      # view
      defmodule MyApp.Web.ExampleView do
        use MyApp.Web, :view
    
        def render("403.json", _assigns) do
          %{message: "Forbidden"}
        end
      end
    
      # config/config.exs
      config :conductor, :failure_template, {MyApp.Web.ExampleView, "403.json"}

License

Copyright 2017-2021 Tobiasz Małecki [email protected]

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

conductor's People

Contributors

amatalai avatar michaldolata avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

conductor's Issues

Render custom view

I really like this package as Authorization module with check user scopes (in my project from JWT token).
But I have few ideas to new features in Conductor.

1. Add custom HTTP status

config :conductor, error_status: 401

2. Custom view render as body

Now body returned in an unauthorized request is empty. Is it possible to add an option in config with render function? I think about simple

def render(conn, "my_unauthorized.json") do ... end

3. Default config, dynamic config in single Endpoint

The description above is ideal for additional behavior of Conductor. You can also add new field in @authorize param in endpoint with view: MyApp.Error.render(....) or status: 401 -> in this single endpoint we could set different settings.

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.