@@ -5,9 +5,9 @@ defmodule CadetWeb.AuthController do
55 use CadetWeb , :controller
66 use PhoenixSwagger
77
8- alias Cadet.Accounts
9- alias Cadet.Accounts.User
8+ alias Cadet . { Accounts , Accounts.User }
109 alias Cadet.Auth . { Guardian , Provider }
10+ alias Cadet.TokenExchange
1111
1212 @ doc """
1313 Receives a /login request with valid attributes.
@@ -85,9 +85,87 @@ defmodule CadetWeb.AuthController do
8585 send_resp ( conn , :bad_request , "Missing parameter" )
8686 end
8787
88- @ spec create_user_and_tokens ( Provider . authorise_params ( ) ) ::
89- { :ok , % { access_token: String . t ( ) , refresh_token: String . t ( ) } } | Plug.Conn . t ( )
90- defp create_user_and_tokens (
88+ @ doc """
89+ Exchanges a short-lived code for access and refresh tokens.
90+ """
91+ def exchange (
92+ conn ,
93+ % {
94+ "code" => code ,
95+ "provider" => provider
96+ }
97+ ) do
98+ case TokenExchange . get_by_code ( code ) do
99+ { :error , _message } ->
100+ conn
101+ |> put_status ( :forbidden )
102+ |> text ( "Invalid code" )
103+
104+ { :ok , struct } ->
105+ tokens = generate_tokens ( struct . user )
106+
107+ { _provider , % { client_post_exchange_redirect_url: client_post_exchange_redirect_url } } =
108+ Application . get_env ( :cadet , :identity_providers , % { } ) [ provider ]
109+
110+ conn
111+ |> put_resp_header (
112+ "location" ,
113+ URI . encode (
114+ client_post_exchange_redirect_url <>
115+ "?access_token=" <> tokens . access_token <> "&refresh_token=" <> tokens . refresh_token
116+ )
117+ )
118+ |> send_resp ( 302 , "" )
119+ |> halt ( )
120+ end
121+ end
122+
123+ @ doc """
124+ Alternate callback URL which redirect to VSCode via deeplinking.
125+ """
126+ def saml_redirect_vscode (
127+ conn ,
128+ % {
129+ "provider" => provider
130+ }
131+ ) do
132+ code_ttl = 60
133+
134+ case create_user ( % {
135+ conn: conn ,
136+ provider_instance: provider ,
137+ code: nil ,
138+ client_id: nil ,
139+ redirect_uri: nil
140+ } ) do
141+ { :ok , user } ->
142+ code = generate_code ( )
143+
144+ TokenExchange . insert ( % {
145+ code: code ,
146+ generated_at: Timex . now ( ) ,
147+ expires_at: Timex . add ( Timex . now ( ) , Timex.Duration . from_seconds ( code_ttl ) ) ,
148+ user_id: user . id
149+ } )
150+
151+ { _provider , % { vscode_redirect_url_prefix: vscode_redirect_url_prefix } } =
152+ Application . get_env ( :cadet , :identity_providers , % { } ) [ provider ]
153+
154+ conn
155+ |> put_resp_header (
156+ "location" ,
157+ vscode_redirect_url_prefix <> "?provider=" <> provider <> "&code=" <> code
158+ )
159+ |> send_resp ( 302 , "" )
160+ |> halt ( )
161+
162+ conn ->
163+ conn
164+ end
165+ end
166+
167+ @ spec create_user ( Provider . authorise_params ( ) ) :: { :ok , User . t ( ) } | Plug.Conn . t ( )
168+ defp create_user (
91169 params = % {
92170 conn: conn ,
93171 provider_instance: provider
@@ -96,7 +174,7 @@ defmodule CadetWeb.AuthController do
96174 with { :authorise , { :ok , % { token: token , username: username } } } <-
97175 { :authorise , Provider . authorise ( params ) } ,
98176 { :signin , { :ok , user } } <- { :signin , Accounts . sign_in ( username , token , provider ) } do
99- { :ok , generate_tokens ( user ) }
177+ { :ok , user }
100178 else
101179 { :authorise , { :error , :upstream , reason } } ->
102180 conn
@@ -121,6 +199,18 @@ defmodule CadetWeb.AuthController do
121199 end
122200 end
123201
202+ @ spec create_user_and_tokens ( Provider . authorise_params ( ) ) ::
203+ { :ok , % { access_token: String . t ( ) , refresh_token: String . t ( ) } } | Plug.Conn . t ( )
204+ defp create_user_and_tokens ( params ) do
205+ case create_user ( params ) do
206+ { :ok , user } ->
207+ { :ok , generate_tokens ( user ) }
208+
209+ conn ->
210+ conn
211+ end
212+ end
213+
124214 @ doc """
125215 Receives a /refresh request with valid attribute.
126216
@@ -170,6 +260,14 @@ defmodule CadetWeb.AuthController do
170260 % { access_token: access_token , refresh_token: refresh_token }
171261 end
172262
263+ @ spec generate_code :: String . t ( )
264+ defp generate_code do
265+ 16
266+ |> :crypto . strong_rand_bytes ( )
267+ |> Base . url_encode64 ( padding: false )
268+ |> String . slice ( 0 , 22 )
269+ end
270+
173271 swagger_path :create do
174272 post ( "/auth/login" )
175273
0 commit comments