@@ -381,7 +381,7 @@ config :pleroma, :ldap, | |||
base: System.get_env("LDAP_BASE") || "dc=example,dc=com", | |||
uid: System.get_env("LDAP_UID") || "cn" | |||
config :pleroma, :auth, oauth_consumer_enabled: false | |||
config :pleroma, :auth, oauth_consumer_enabled: System.get_env("OAUTH_CONSUMER_ENABLED") == "true" | |||
config :ueberauth, | |||
Ueberauth, | |||
@@ -0,0 +1,36 @@ | |||
# Pleroma: A lightweight social networking server | |||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> | |||
# SPDX-License-Identifier: AGPL-3.0-only | |||
defmodule Pleroma.Registration do | |||
use Ecto.Schema | |||
import Ecto.Changeset | |||
alias Pleroma.Registration | |||
alias Pleroma.Repo | |||
alias Pleroma.User | |||
schema "registrations" do | |||
belongs_to(:user, User, type: Pleroma.FlakeId) | |||
field(:provider, :string) | |||
field(:uid, :string) | |||
field(:info, :map, default: %{}) | |||
timestamps() | |||
end | |||
def changeset(registration, params \\ %{}) do | |||
registration | |||
|> cast(params, [:user_id, :provider, :uid, :info]) | |||
|> foreign_key_constraint(:user_id) | |||
|> unique_constraint(:uid, name: :registrations_provider_uid_index) | |||
end | |||
def get_by_provider_uid(provider, uid) do | |||
Repo.get_by(Registration, | |||
provider: to_string(provider), | |||
uid: to_string(uid) | |||
) | |||
end | |||
end |
@@ -13,6 +13,7 @@ defmodule Pleroma.User do | |||
alias Pleroma.Formatter | |||
alias Pleroma.Notification | |||
alias Pleroma.Object | |||
alias Pleroma.Registration | |||
alias Pleroma.Repo | |||
alias Pleroma.User | |||
alias Pleroma.Web | |||
@@ -41,8 +42,6 @@ defmodule Pleroma.User do | |||
field(:email, :string) | |||
field(:name, :string) | |||
field(:nickname, :string) | |||
field(:auth_provider, :string) | |||
field(:auth_provider_uid, :string) | |||
field(:password_hash, :string) | |||
field(:password, :string, virtual: true) | |||
field(:password_confirmation, :string, virtual: true) | |||
@@ -56,6 +55,7 @@ defmodule Pleroma.User do | |||
field(:bookmarks, {:array, :string}, default: []) | |||
field(:last_refreshed_at, :naive_datetime) | |||
has_many(:notifications, Notification) | |||
has_many(:registrations, Registration) | |||
embeds_one(:info, Pleroma.User.Info) | |||
timestamps() | |||
@@ -210,13 +210,12 @@ defmodule Pleroma.User do | |||
end | |||
# TODO: FIXME (WIP): | |||
def oauth_register_changeset(struct, params \\ %{}) do | |||
def external_registration_changeset(struct, params \\ %{}) do | |||
info_change = User.Info.confirmation_changeset(%User.Info{}, :confirmed) | |||
changeset = | |||
struct | |||
|> cast(params, [:email, :nickname, :name, :bio, :auth_provider, :auth_provider_uid]) | |||
|> validate_required([:auth_provider, :auth_provider_uid]) | |||
|> cast(params, [:email, :nickname, :name, :bio]) | |||
|> unique_constraint(:email) | |||
|> unique_constraint(:nickname) | |||
|> validate_exclusion(:nickname, Pleroma.Config.get([Pleroma.User, :restricted_nicknames])) | |||
@@ -544,13 +543,6 @@ defmodule Pleroma.User do | |||
get_by_nickname(nickname_or_email) || get_by_email(nickname_or_email) | |||
end | |||
def get_by_auth_provider_uid(auth_provider, auth_provider_uid), | |||
do: | |||
Repo.get_by(User, | |||
auth_provider: to_string(auth_provider), | |||
auth_provider_uid: to_string(auth_provider_uid) | |||
) | |||
def get_cached_user_info(user) do | |||
key = "user_info:#{user.id}" | |||
Cachex.fetch!(:user_cache, key, fn _ -> user_info(user) end) | |||
@@ -15,10 +15,10 @@ defmodule Pleroma.Web.Auth.Authenticator do | |||
@callback get_user(Plug.Conn.t(), Map.t()) :: {:ok, User.t()} | {:error, any()} | |||
def get_user(plug, params), do: implementation().get_user(plug, params) | |||
@callback get_or_create_user_by_oauth(Plug.Conn.t(), Map.t()) :: | |||
@callback get_by_external_registration(Plug.Conn.t(), Map.t()) :: | |||
{:ok, User.t()} | {:error, any()} | |||
def get_or_create_user_by_oauth(plug, params), | |||
do: implementation().get_or_create_user_by_oauth(plug, params) | |||
def get_by_external_registration(plug, params), | |||
do: implementation().get_by_external_registration(plug, params) | |||
@callback handle_error(Plug.Conn.t(), any()) :: any() | |||
def handle_error(plug, error), do: implementation().handle_error(plug, error) | |||
@@ -40,7 +40,7 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do | |||
end | |||
end | |||
def get_or_create_user_by_oauth(conn, params), do: get_user(conn, params) | |||
def get_by_external_registration(conn, params), do: get_user(conn, params) | |||
def handle_error(%Plug.Conn{} = _conn, error) do | |||
error | |||
@@ -5,6 +5,8 @@ | |||
defmodule Pleroma.Web.Auth.PleromaAuthenticator do | |||
alias Comeonin.Pbkdf2 | |||
alias Pleroma.User | |||
alias Pleroma.Registration | |||
alias Pleroma.Repo | |||
@behaviour Pleroma.Web.Auth.Authenticator | |||
@@ -27,20 +29,21 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do | |||
end | |||
end | |||
def get_or_create_user_by_oauth( | |||
def get_by_external_registration( | |||
%Plug.Conn{assigns: %{ueberauth_auth: %{provider: provider, uid: uid} = auth}}, | |||
_params | |||
) do | |||
user = User.get_by_auth_provider_uid(provider, uid) | |||
registration = Registration.get_by_provider_uid(provider, uid) | |||
if user do | |||
if registration do | |||
user = Repo.preload(registration, :user).user | |||
{:ok, user} | |||
else | |||
info = auth.info | |||
email = info.email | |||
nickname = info.nickname | |||
# TODO: FIXME: connect to existing (non-oauth) account (need a UI flow for that) / generate a random nickname? | |||
# Note: nullifying email in case this email is already taken | |||
email = | |||
if email && User.get_by_email(email) do | |||
nil | |||
@@ -48,31 +51,39 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do | |||
end | |||
# Note: generating a random numeric suffix to nickname in case this nickname is already taken | |||
nickname = | |||
if nickname && User.get_by_nickname(nickname) do | |||
nil | |||
"#{nickname}_#{:os.system_time()}" | |||
else | |||
nickname | |||
end | |||
new_user = | |||
User.oauth_register_changeset( | |||
%User{}, | |||
%{ | |||
auth_provider: to_string(provider), | |||
auth_provider_uid: to_string(uid), | |||
name: info.name, | |||
bio: info.description, | |||
email: email, | |||
nickname: nickname | |||
} | |||
) | |||
Pleroma.Repo.insert(new_user) | |||
with {:ok, new_user} <- | |||
User.external_registration_changeset( | |||
%User{}, | |||
%{ | |||
name: info.name, | |||
bio: info.description, | |||
email: email, | |||
nickname: nickname | |||
} | |||
) | |||
|> Repo.insert(), | |||
{:ok, _} <- | |||
Registration.changeset(%Registration{}, %{ | |||
user_id: new_user.id, | |||
provider: to_string(provider), | |||
uid: to_string(uid), | |||
info: %{nickname: info.nickname, email: info.email} | |||
}) | |||
|> Repo.insert() do | |||
{:ok, new_user} | |||
end | |||
end | |||
end | |||
def get_or_create_user_by_oauth(%Plug.Conn{} = _conn, _params), | |||
def get_by_external_registration(%Plug.Conn{} = _conn, _params), | |||
do: {:error, :missing_credentials} | |||
def handle_error(%Plug.Conn{} = _conn, error) do | |||
@@ -47,7 +47,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do | |||
conn, | |||
%{"client_id" => client_id, "redirect_uri" => redirect_uri} = params | |||
) do | |||
with {:ok, user} <- Authenticator.get_or_create_user_by_oauth(conn, params) do | |||
with {:ok, user} <- Authenticator.get_by_external_registration(conn, params) do | |||
do_create_authorization( | |||
conn, | |||
%{ | |||
@@ -1,12 +0,0 @@ | |||
defmodule Pleroma.Repo.Migrations.AddAuthProviderAndAuthProviderUidToUsers do | |||
use Ecto.Migration | |||
def change do | |||
alter table(:users) do | |||
add :auth_provider, :string | |||
add :auth_provider_uid, :string | |||
end | |||
create unique_index(:users, [:auth_provider, :auth_provider_uid]) | |||
end | |||
end |
@@ -0,0 +1,16 @@ | |||
defmodule Pleroma.Repo.Migrations.CreateRegistrations do | |||
use Ecto.Migration | |||
def change do | |||
create table(:registrations) do | |||
add :user_id, references(:users, type: :uuid, on_delete: :delete_all) | |||
add :provider, :string | |||
add :uid, :string | |||
add :info, :map, default: %{} | |||
timestamps() | |||
end | |||
create unique_index(:registrations, [:provider, :uid]) | |||
end | |||
end |