auth against sha512-crypt password hashes, upgrade to pbkdf2
[akkoma] / test / plugs / authentication_plug_test.exs
1 defmodule Pleroma.Plugs.AuthenticationPlugTest do
2 use Pleroma.Web.ConnCase, async: true
3
4 alias Pleroma.Plugs.AuthenticationPlug
5 alias Pleroma.User
6
7 defp fetch_nil(_name) do
8 {:ok, nil}
9 end
10
11 @user %User{
12 id: 1,
13 name: "dude",
14 password_hash: Comeonin.Pbkdf2.hashpwsalt("guy")
15 }
16
17 @deactivated %User{
18 id: 1,
19 name: "dude",
20 password_hash: Comeonin.Pbkdf2.hashpwsalt("guy"),
21 info: %{"deactivated" => true}
22 }
23
24 @legacy %User{
25 id: 1,
26 name: "dude",
27 password_hash:
28 "$6$9psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"
29 }
30
31 @session_opts [
32 store: :cookie,
33 key: "_test",
34 signing_salt: "cooldude"
35 ]
36
37 defp fetch_user(_name) do
38 {:ok, @user}
39 end
40
41 defp basic_auth_enc(username, password) do
42 "Basic " <> Base.encode64("#{username}:#{password}")
43 end
44
45 describe "without an authorization header" do
46 test "it halts the application" do
47 conn =
48 build_conn()
49 |> Plug.Session.call(Plug.Session.init(@session_opts))
50 |> fetch_session
51 |> AuthenticationPlug.call(%{})
52
53 assert conn.status == 403
54 assert conn.halted == true
55 end
56
57 test "it assigns a nil user if the 'optional' option is used" do
58 conn =
59 build_conn()
60 |> Plug.Session.call(Plug.Session.init(@session_opts))
61 |> fetch_session
62 |> AuthenticationPlug.call(%{optional: true})
63
64 assert %{user: nil} == conn.assigns
65 end
66 end
67
68 describe "with an authorization header for a nonexisting user" do
69 test "it halts the application" do
70 conn =
71 build_conn()
72 |> Plug.Session.call(Plug.Session.init(@session_opts))
73 |> fetch_session
74 |> AuthenticationPlug.call(%{fetcher: &fetch_nil/1})
75
76 assert conn.status == 403
77 assert conn.halted == true
78 end
79
80 test "it assigns a nil user if the 'optional' option is used" do
81 conn =
82 build_conn()
83 |> Plug.Session.call(Plug.Session.init(@session_opts))
84 |> fetch_session
85 |> AuthenticationPlug.call(%{optional: true, fetcher: &fetch_nil/1})
86
87 assert %{user: nil} == conn.assigns
88 end
89 end
90
91 describe "with an incorrect authorization header for a enxisting user" do
92 test "it halts the application" do
93 opts = %{
94 fetcher: &fetch_user/1
95 }
96
97 header = basic_auth_enc("dude", "man")
98
99 conn =
100 build_conn()
101 |> Plug.Session.call(Plug.Session.init(@session_opts))
102 |> fetch_session
103 |> put_req_header("authorization", header)
104 |> AuthenticationPlug.call(opts)
105
106 assert conn.status == 403
107 assert conn.halted == true
108 end
109
110 test "it assigns a nil user if the 'optional' option is used" do
111 opts = %{
112 optional: true,
113 fetcher: &fetch_user/1
114 }
115
116 header = basic_auth_enc("dude", "man")
117
118 conn =
119 build_conn()
120 |> Plug.Session.call(Plug.Session.init(@session_opts))
121 |> fetch_session
122 |> put_req_header("authorization", header)
123 |> AuthenticationPlug.call(opts)
124
125 assert %{user: nil} == conn.assigns
126 end
127 end
128
129 describe "with a correct authorization header for an existing user" do
130 test "it assigns the user", %{conn: conn} do
131 opts = %{
132 optional: true,
133 fetcher: &fetch_user/1
134 }
135
136 header = basic_auth_enc("dude", "guy")
137
138 conn =
139 conn
140 |> Plug.Session.call(Plug.Session.init(@session_opts))
141 |> fetch_session
142 |> put_req_header("authorization", header)
143 |> AuthenticationPlug.call(opts)
144
145 assert %{user: @user} == conn.assigns
146 assert get_session(conn, :user_id) == @user.id
147 assert conn.halted == false
148 end
149
150 test "it assigns legacy user", %{conn: conn} do
151 opts = %{
152 optional: true,
153 fetcher: fn _ -> {:ok, @legacy} end,
154 update_legacy_password: false
155 }
156
157 header = basic_auth_enc("dude", "password")
158
159 conn =
160 conn
161 |> Plug.Session.call(Plug.Session.init(@session_opts))
162 |> fetch_session
163 |> put_req_header("authorization", header)
164 |> AuthenticationPlug.call(opts)
165
166 assert %{user: @legacy} == conn.assigns
167 assert get_session(conn, :user_id) == @legacy.id
168 assert conn.halted == false
169 end
170 end
171
172 describe "with a correct authorization header for an deactiviated user" do
173 test "it halts the appication", %{conn: conn} do
174 opts = %{
175 optional: false,
176 fetcher: fn _ -> @deactivated end
177 }
178
179 header = basic_auth_enc("dude", "guy")
180
181 conn =
182 conn
183 |> Plug.Session.call(Plug.Session.init(@session_opts))
184 |> fetch_session
185 |> put_req_header("authorization", header)
186 |> AuthenticationPlug.call(opts)
187
188 assert conn.status == 403
189 assert conn.halted == true
190 end
191 end
192
193 describe "with a user_id in the session for an existing user" do
194 test "it assigns the user", %{conn: conn} do
195 opts = %{
196 optional: true,
197 fetcher: &fetch_user/1
198 }
199
200 header = basic_auth_enc("dude", "THIS IS WRONG")
201
202 conn =
203 conn
204 |> Plug.Session.call(Plug.Session.init(@session_opts))
205 |> fetch_session
206 |> put_session(:user_id, @user.id)
207 |> put_req_header("authorization", header)
208 |> AuthenticationPlug.call(opts)
209
210 assert %{user: @user} == conn.assigns
211 assert get_session(conn, :user_id) == @user.id
212 assert conn.halted == false
213 end
214 end
215
216 describe "with an assigned user" do
217 test "it does nothing, returning the incoming conn", %{conn: conn} do
218 conn =
219 conn
220 |> assign(:user, @user)
221
222 conn_result = AuthenticationPlug.call(conn, %{})
223
224 assert conn == conn_result
225 end
226 end
227 end