Giter VIP home page Giter VIP logo

authority_ecto's Introduction

Authority.Ecto

Hex.pm Build Status

Authority.Ecto helps you implement the Authority authentication spec for your application, using Ecto for persistence.

Read the documentation for more information.

Installation

Add authority_ecto to your list of dependencies in mix.exs:

def deps do
  [
    {:authority_ecto, "~> 0.1.3"}
  ]
end

Premium Support

Infinite Red offers premium support for this library and general web & mobile app design/development services. Get in touch here or email us at [email protected].

Infinite Red Logo

authority_ecto's People

Contributors

danielberkompas avatar rzane avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

rzane fadeojo

authority_ecto's Issues

Typespecs aren't quite right

So, the first problem is that this package is expecting a type t to be defined on both the token schema and user schema. Since Ecto.Schema doesn't automatically generate a type, this assumption isn't a very safe one.

So, I defined a type on each schema:

@type t :: %__MODULE__{}

But then, I get some violations:

lib/authority_ecto/templates/registration.ex:1: Function change_user/0 has no local return
lib/authority_ecto/templates/registration.ex:210: The call 'Elixir.MyApp.Accounts':change_user('nil',#{}) breaks the contract ('Elixir.MyApp.Accounts.User':t() | 'Elixir.MyApp.Accounts.Token':t(),map()) -> {'ok','Elixir.Ecto.Changeset':t()} | auth_failure()

put_secure_token/2

Authority.Ecto.Changeset.put_secure_token/2 would generate a secure, random token into the database.

# Generate a token, and hash it with HMAC before storing it 
# (should there be an authority function for unhashing before finding the user by token?)
put_secure_token(changeset, :token)

The original proposal mentions using HMAC to hash the field. It sounds to me like we might want to use an Ecto.Type

@rzane can you shed any light on why we should HMAC after generating the token?

Original: infinitered/authority#11

Store locking information on User Schema

Devise tracks this information using two columns:

  • failed_attempts (integer)
  • locked_at (datetime)

I'm curious why the attempts and locks tables are necessary, especially because it results in performing an extra query on every single request.

put_encrypted_password/3

Authority.Ecto.Changeset.put_encrypted_password/3 should hash the value in the source field and store the result in the destination field.

def put_encrypted_password(changeset, source, destination) do
  # ...
end

# Usage
put_encrypted_password(changeset, :password, :encrypted_password)

Ideally, you'd be able to choose the hashing algorithm. I'd prefer to do this through an extra optional argument rather than configuration./

Original: infinitered/authority#11

Accounts.get_token returns hashed token instead of raw token

Hi,
I'm not sure if this is an issue with Authority Ecto or the default Mithril code, but when I call Accounts.get_token it returns the hashed token from the database in the token struct instead of the raw token like when I call Accounts.tokenize. For example:

%MyApp.Accounts.Token{
   __meta__: #Ecto.Schema.Metadata<:loaded, "user_tokens">,
   expires_at: #DateTime<2018-06-17 10:31:32.000000Z>,
   id: "8daf165d-d9a2-4f4c-9416-0a97abefd7b4",
   inserted_at: #DateTime<2018-06-03 10:31:32.702569Z>,
   last_used_at: #DateTime<2018-06-03 10:31:32.702166Z>,
   purpose: :any,
   token: "49EE84AAFDC66FB2CD97088BE955A83DF710C8AE32C3A5A3BCEC3E047C66A908",
   updated_at: #DateTime<2018-06-03 10:31:32.702575Z>,
   user: #Ecto.Association.NotLoaded<association :user is not loaded>,
   user_id: "f63a2455-bd08-478c-8dae-0d429f68f319"
}

Instead of

%MyApp.Accounts.Token{
   __meta__: #Ecto.Schema.Metadata<:loaded, "user_tokens">,
   expires_at: #DateTime<2018-06-17 10:31:32Z>,
   id: "8daf165d-d9a2-4f4c-9416-0a97abefd7b4",
   inserted_at: #DateTime<2018-06-03 10:31:32.702569Z>,
   last_used_at: #DateTime<2018-06-03 10:31:32.702166Z>,
   purpose: :any,
   token: "2a559250-e30c-4c00-9cf1-0c9447958f0e",
   updated_at: #DateTime<2018-06-03 10:31:32.702575Z>,
   user: #Ecto.Association.NotLoaded<association :user is not loaded>,
   user_id: "f63a2455-bd08-478c-8dae-0d429f68f319"
 }

The result of this is that when I call Accounts.authenticate with the token struct from Accounts.get_token I get {:error, :invalid_token}.

My work around for the current Mithril codebase is to construct my own token struct in the same way the graphql layer does:

%Accounts.Token{token: token}

Avoid reading/deleting the locks on every request

Currently, if you call authenticate on every request you'll see the following queries in your logs:

  1. Get the user by token
  2. Check if there is a lock for the user
  3. Delete the locks for the user

Steps 2 and 3 should really only happen when the user signs in (aka tokenize).

put_token_expiration/4

Authority.Ecto.Changeset.put_token_expiration would populate a given expiry field with the correct value, based on the token's purpose.

def put_token_expiration(changeset, expiration_field, purpose_field, config) do
  # ...
end

# Set the expires_at on the Token
put_token_expiration(changeset, :expires_at, :purpose, recovery: {24, :hours}, any: {2, :weeks})

Ideally we'd do this without adding any additional dependencies. It'd be great if this package only relied on Authority and Ecto.

Original: infinitered/authority#11

Primary Key of UUID throws test error

Hello,
I've generated a project using mithril:
mix gen mithril chapel --accounts --ci semaphore --deploy heroku --ecto postgres --api graphql --websockets --gettext --email And then, in my infinite wisdom, I've decided to change to a uuid primary key on the users table. To do this, I've added this to the schema:

  defmacro __using__(_) do
    quote do
      use Ecto.Schema

      import Ecto.Changeset, warn: false
      import Chapel.Schema, warn: false
      import Authority.Ecto.Changeset, warn: false

      @primary_key {:id, :binary_id, autogenerate: true} <= Added this line
      @foreign_key_type :binary_id  <= And this one.
    end
  end

And altered the migration files to:

    create table(:users, primary_key: false) do
      add :id, :binary_id, primary_key: true

Then I run the tests using:

1) test .update_user/2 returns validation errors if passwords don't match (Chapel.AccountsTest)
     test/chapel/accounts/accounts_test.exs:111
     ** (ArgumentError) Postgrex expected an integer in -9223372036854775808..9223372036854775807, got <<159, 219, 108, 216, 200, 157, 78, 176, 171, 158, 70, 159, 199, 95, 205, 234>>. Please make sure the value you are passing matches the definition in your table or in your query or convert the value accordingly.
     stacktrace:
       (ecto) /home/justin/projects/elixir/chapel/deps/postgrex/lib/postgrex/type_module.ex:715: Ecto.Adapters.Postgres.TypeModule.encode_params/3
       (postgrex) lib/postgrex/query.ex:45: DBConnection.Query.Postgrex.Query.encode/3
       (db_connection) lib/db_connection.ex:1079: DBConnection.describe_run/5
       (db_connection) lib/db_connection.ex:1150: anonymous fn/4 in DBConnection.run_meter/5
       (db_connection) lib/db_connection.ex:1207: DBConnection.run_begin/3
       (db_connection) lib/db_connection.ex:592: DBConnection.prepare_execute/4
       (ecto) lib/ecto/adapters/postgres/connection.ex:86: Ecto.Adapters.Postgres.Connection.execute/4
       (ecto) lib/ecto/adapters/sql.ex:256: Ecto.Adapters.SQL.sql_call/6
       (ecto) lib/ecto/adapters/sql.ex:542: Ecto.Adapters.SQL.struct/8
       (ecto) lib/ecto/repo/schema.ex:547: Ecto.Repo.Schema.apply/4
       (ecto) lib/ecto/repo/schema.ex:213: anonymous fn/14 in Ecto.Repo.Schema.do_insert/4
       (chapel) test/support/accounts_factory.ex:40: Chapel.AccountsFactory.create_user/1
       test/chapel/accounts/accounts_test.exs:1: Chapel.AccountsTest.__ex_unit__/2

PS. I wasn't sure where this issue was best added, happy to move to another repo if needed.

validate_secure_password/2

Authority.Ecto.Changeset.validate_secure_password/2 would validate that a password meets minimum security requirements. Presumably, these would include length and symbol checks.

# Check that the password meets agreed-upon password strength checks
validate_secure_password(changeset, :password)

The checks could be configurable, or we could just assume the "best" ones and let you fall back on the built in Ecto functions if you don't like it.

Original: infinitered/authority#11

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.