benonymus

benonymus

Hey I a trying to make a login system for my phoenix app, but I am having an error on successful login attempt:
# protocol Enumerable not implemented for %Userteam1.Web.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: 1, inserted_at: ~N[2018-08-19 09:10:38.661295], name: "bence", password: nil, password_hash: "$2b$12$EEH/mgGuM1GyKHkUSIJG..THKJ6W/0iN/tWH6FiikZ4dRjGqPwt3G", role: #Ecto.Association.NotLoaded<association :role is not loaded>, role_id: 1, team: #Ecto.Association.NotLoaded<association :team is not loaded>, team_id: nil, updated_at: ~N[2018-08-19 09:10:38.661303]}. This protocol is implemented for: DBConnection.PrepareStream, DBConnection.Stream, Date.Range, Ecto.Adapters.SQL.Stream, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, List, Map, MapSet, Postgrex.Stream, Range, Stream

my controller for login looks like this:

def create(conn, %{"session" => %{"name" => name, "password" => password}}) do
    case Userteam1.Web.name_password_auth(name, password) do
      {:ok, user} ->
        IO.inspect(user)

        conn
        |> put_flash(:info, "Successfully signed in")
        |> Guardian.encode_and_sign(user)
        |> redirect(to: user_path(conn, :index))

      {:error, _reason} ->
        conn
        |> put_flash(:error, "Invalid name or password")
        |> render("new.html")
    end
  end

and my schema that it is trying to load looks like this:

  schema "users" do
    field(:name, :string)
    field(:password_hash, :string)
    field(:password, :string, virtual: true)
    belongs_to(:role, Userteam1.Role)
    belongs_to(:team, Userteam1.Team)
    timestamps()
  end

How can this be fixed?

Showing Posts 1 to 10

NobbZ

NobbZ

Guardian.encode_and_sign/4 does not return a Plug.Conn.t, nor anything that would implement the Enumerable protocol.

Please give the Getting Started of guardian another read and try to incorporate the things you learned there into your application.

benonymus

benonymus OP

ok found something, I changed it into this:
|> Guardian.Plug.sign_in(user)
but no I am having a new error:
(Guardian.Plug.UnauthenticatedError) {:error, :secret_not_found}

stephane

stephane

Did you config guardian ? (config.exs)

config :my_app, MyApp.Guardian,
       issuer: "my_app",
       secret_key: "Secret key. You can use `mix guardian.gen.secret` to get one"
benonymus

benonymus OP

missed to change this part, thanks

7stud

7stud

I’ve got the same error (so frustrating!):

Protocol.UndefinedError at POST /login

protocol Enumerable not implemented for %Dog.UserManager.User{meta: #Ecto.Schema.Metadata<:loaded, “users”>, id: 3, inserted_at: ~N[2019-07-15 05:56:22], password: “$argon2id$v=19$m=131072,t=8,p=4$jinhp9gEDVENO2PIdm5zkg$ovideTURD59gCoqtE6UUuYZ/32YMnpgppuRf0NFAJ/k”, updated_at: ~N[2019-07-15 05:56:22], username: “me”}. This protocol is implemented for: Ecto.Adapters.SQL.Stream, Postgrex.Stream, DBConnection.Stream, DBConnection.PrepareStream, HashSet, Range, Map, Function, List, Stream, Date.Range, HashDict, GenEvent.Stream, MapSet, File.Stream, IO.Stream

The stack trace seems to point to my SessionController:

* elixir /home/build/elixir/lib/elixir/lib/enum.ex:1Enumerable.impl_for!/1
* elixir /home/build/elixir/lib/elixir/lib/enum.ex:141Enumerable.reduce/3
* elixir lib/enum.ex:3015Enum.reverse/1
* elixir lib/enum.ex:2647Enum.to_list/1
* elixir lib/map.ex:181Map.new_from_enum/1
* guardian lib/guardian.ex:573Guardian.encode_and_sign/4
* guardian lib/guardian/plug.ex:208Guardian.Plug.sign_in/5
* lib/dog_web/controllers/session_controller.ex:29DogWeb.SessionController.login_reply/2
* lib/dog_web/controllers/session_controller.ex:1DogWeb.SessionController.action/2
* lib/dog_web/controllers/session_controller.ex:1DogWeb.SessionController.phoenix_controller_pipeline/2
* phoenix lib/phoenix/router.ex:288Phoenix.Router.__call__/2
* lib/dog_web/endpoint.ex:1DogWeb.Endpoint.plug_builder_call/2
* lib/plug/debugger.ex:122DogWeb.Endpoint."call (overridable 3)"/2
* lib/dog_web/endpoint.ex:1DogWeb.Endpoint.call/2
* phoenix lib/phoenix/endpoint/cowboy2_handler.ex:40Phoenix.Endpoint.Cowboy2Handler.init/2
* cowboy /Users/7stud/phoenix_apps/dog/deps/cowboy/src/cowboy_handler.erl:41:cowboy_handler.execute/2
* cowboy /Users/7stud/phoenix_apps/dog/deps/cowboy/src/cowboy_stream_h.erl:296:cowboy_stream_h.execute/3
* cowboy /Users/7stud/phoenix_apps/dog/deps/cowboy/src/cowboy_stream_h.erl:274:cowboy_stream_h.request_process/3

Here’s my SessionController:

defmodule DogWeb.SessionController do
  use DogWeb, :controller
  alias Dog.{UserManager, UserManager.User, UserManager.Guardian}

  def new(conn, _) do
    changeset = UserManager.change_user(%User{})
    maybe_user = Guardian.Plug.current_resource(conn)
    if maybe_user do
      redirect(conn, to: "/secret")
    else
      render(conn, "new.html",
             changeset: changeset,
             action: Routes.session_path(conn, :login)
      ) 
    end
  end

  def login(conn, 
            %{"user" => %{"username" => username,
                          "password" => password}})
  do
    UserManager.authenticate_user(username, password)
    |> login_reply(conn)
  end

  def login_reply({:ok, user}, conn) do
    conn
    |> put_flash(:info, "Welcome back!")
    |> Guardian.Plug.sign_in(Guardian, user)
    |> redirect(to: "/secret")
  end
  def login_reply({:error, reason}, conn) do
    conn
    |> put_flash(:error, to_string(reason))
    |> new(%{})
  end

  def logout(conn, _) do
    conn
    |> Guardian.Plug.sign_out(Guardian)
    |> redirect(to: "/login")
  end

end

I checked the Guardian.Plug docs for the sign_in() function:

sign_in(conn, impl, resource, claims \\ %{}, opts \\ []) 

sign_in(
  Plug.Conn.t(),
  module(),
  any(),
  Guardian.Token.claims(),
  Guardian.options()
) :: Plug.Conn.t()

And, I"m calling sign_in() with the correct types for the arguments. I’m stuck.

Here’s my config.exs:

use Mix.Config

config :dog,
  ecto_repos: [Dog.Repo]

config :dog, Dog.Repo,
  datbase: "dog",
  username: "7stud",
  password: "",
  hostname: "localhost",
  port: "5432"

config :dog, Dog.UserManager.Guardian,
  issuer: "dog",
  secret_key: "e8UPW0Doh0iBonm8ZK0RJVzaAA8r+Jgw4t3lVEoB1SiByke/V9cxcz//1iPkpVrq"

# Configures the endpoint
config :dog, DogWeb.Endpoint,
  url: [host: "localhost"],
  secret_key_base: "xpVFSaAFJZ8xUEhWLrzT/sTvL/Z6y+mSvfobiKiKanWexNwL2Wj2EbRXr7V9fQSj",
  render_errors: [view: DogWeb.ErrorView, accepts: ~w(html json)],
  pubsub: [name: Dog.PubSub, adapter: Phoenix.PubSub.PG2]

# Configures Elixir's Logger
config :logger, :console,
  format: "$time $metadata[$level] $message\n",
  metadata: [:request_id]

# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason

# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"

I’m using a UserManager context for the public interface:

defmodule Dog.UserManager do
  @repo Dog.Repo
  alias Dog.UserManager.User
  alias Argon2

  import Ecto.Query, only: [from: 2]

  def list_users() do
    @repo.all(User)
  end

  def get_user(id) do
    @repo.get!(User, id)
  end

  def change_user(%User{}=user) do
    User.changeset(user, %{})
  end

  def insert_user(attrs) do
    %User{}
    |> User.changeset(attrs)
    |> @repo.insert()
  end

  def delete_user(%User{}=user) do
    @repo.delete(user)
  end

  def authenticate_user(username, plain_text_password) do
    query = from u in User, where: u.username == ^username
    case @repo.one(query) do
      nil ->
        Argon2.no_user_verify()
        {:error, :invalid_credentials}
      user ->
        if Argon2.verify_pass(plain_text_password, user.password) do
          {:ok, user}
        else
          {:error, :invalid_credentials}
        end
    end
  end


end

Here’s my directory structure:

~/phoenix_apps/dog$ tree lib
lib
├── dog
│   ├── application.ex
│   ├── repo.ex
│   └── user_manager
│       ├── error_handler.ex
│       ├── guardian.ex
│       ├── pipeline.ex
│       ├── user.ex
│       └── user_manager.ex
├── dog.ex
├── dog_web
│   ├── channels
│   │   └── user_socket.ex
│   ├── controllers
│   │   ├── page_controller.ex
│   │   └── session_controller.ex
│   ├── endpoint.ex
│   ├── gettext.ex
│   ├── router.ex
│   ├── templates
│   │   ├── layout
│   │   │   └── app.html.eex
│   │   ├── page
│   │   │   ├── index.html.eex
│   │   │   └── protected.html
│   │   └── session
│   │       └── new.html.eex
│   └── views
│       ├── error_helpers.ex
│       ├── error_view.ex
│       ├── layout_view.ex
│       ├── page_view.ex
│       └── session_view.ex
└── dog_web.ex

idi527

idi527

Your app actually fails at this line: guardian/lib/guardian.ex at 9ed23acbef1ddfde5a79c139570fada9399b0877 · ueberauth/guardian · GitHub

Looks like you are passing your user as claims.

7stud

7stud

  1. How do you know that?

  2. As far as I can tell, I’m passing the default for claims, which is %{}:

 conn
    |> put_flash(:info, "Welcome back!")
    |> Guardian.Plug.sign_in(Guardian, user)

put_flash() returns a conn, so I am calling:

Guardian.Plug.sign_in(conn, Guardian, user)

and based on the definition of sign_in():

sign_in(conn, impl, resource, claims \\ %{}, opts \\ [])

I’m actually calling:

Guardian.Plug.sign_in(conn, Guardian, user, %{}, [])

idi527

idi527

How do you know that?

See the stacktrace:

* elixir /home/build/elixir/lib/elixir/lib/enum.ex:1Enumerable.impl_for!/1
* elixir /home/build/elixir/lib/elixir/lib/enum.ex:141Enumerable.reduce/3
* elixir lib/enum.ex:3015Enum.reverse/1
* elixir lib/enum.ex:2647Enum.to_list/1
* elixir lib/map.ex:181Map.new_from_enum/1
* guardian lib/guardian.ex:573Guardian.encode_and_sign/4 # <-- this is where user=claims 
* guardian lib/guardian/plug.ex:208Guardian.Plug.sign_in/5
* lib/dog_web/controllers/session_controller.ex:29DogWeb.SessionController.login_reply/2

Try passing all arguments to sign_in without relying on the defaults, something strange is going on:

conn
|> put_flash(:info, "Welcome back!")
|> Guardian.Plug.sign_in(Guardian, user, %{}, [])
7stud

7stud

I tried this:

  def login_reply({:ok, user}, conn) do
    put_flash(conn, :info, "Welcome back!")
    new_conn = Guardian.Plug.sign_in(conn, Guaridan, user, %{}, [])
    redirect(new_conn, to: "/secret")
  end
  def login_reply({:error, reason}, conn) do
    conn
    |> put_flash(:error, to_string(reason))
    |> new(%{})
  end

And, I got this warning:


~/phoenix_apps/dog$ mix phx.server

warning: function Dog.UserManager.Guardian.Plug.sign_in/5 is undefined or private. Did you mean one of:

      * sign_in/2
      * sign_in/3
      * sign_in/4

  lib/dog_web/controllers/session_controller.ex:28

...
...

In iex:

~/phoenix_apps/dog$ iex -S mix
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.8.2) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> h Guardian.Plug.sign_in                  

          def sign_in(conn, impl, resource, claims \\ %{}, opts \\ [])          

  @spec sign_in(
          Plug.Conn.t(),
          module(),
          any(),
          Guardian.Token.claims(),
          Guardian.options()
        ) :: Plug.Conn.t()

iex(2)>

That looks like 5 arguments to me! So, I decided to pick the two most important arguments, and go with that:

new_conn = Guardian.Plug.sign_in(conn, user)

That got rid of the Enumerable error. Now, I’ve got a routing error that I’m working on.

idi527

idi527

Dog.UserManager.Guardian.Plug != Guardian.Plug

Seems like you’ve confused one with the other because of

alias Dog.{UserManager, UserManager.User, UserManager.Guardian}

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews