-
-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #225 from Hanspagh/develop
add azure auth provider
- Loading branch information
Showing
4 changed files
with
139 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
defmodule K8s.Conn.Auth.Azure do | ||
@moduledoc """ | ||
`auth-provider` for azure | ||
""" | ||
alias K8s.Conn.RequestOptions | ||
|
||
require Logger | ||
@behaviour K8s.Conn.Auth | ||
|
||
defstruct [:token] | ||
|
||
@type t :: %__MODULE__{ | ||
token: String.t() | ||
} | ||
|
||
@impl true | ||
@spec create(map, String.t()) :: {:ok, t} | :skip | ||
def create( | ||
%{ | ||
"auth-provider" => %{ | ||
"config" => %{ | ||
"access-token" => token, | ||
"tenant-id" => tenant, | ||
"expires-on" => expires_on, | ||
"refresh-token" => refresh_token, | ||
"client-id" => client_id, | ||
"apiserver-id" => apiserver_id | ||
}, | ||
"name" => "azure" | ||
} | ||
}, | ||
_ | ||
) do | ||
if DateTime.diff(DateTime.utc_now(), parse_expires(expires_on)) >= 0 do | ||
Logger.info( | ||
"Azure token expired, using refresh token get new access, this will stop working when refresh token expires" | ||
) | ||
|
||
{:ok, %__MODULE__{token: refresh_token(tenant, refresh_token, client_id, apiserver_id)}} | ||
else | ||
{:ok, %__MODULE__{token: token}} | ||
end | ||
end | ||
|
||
def create(_, _), do: :skip | ||
|
||
@spec parse_expires(String.t()) :: DateTime.t() | ||
defp parse_expires(expires_on) do | ||
case Integer.parse(expires_on) do | ||
{expires_on, _} -> DateTime.from_unix!(expires_on) | ||
:error -> DateTime.from_iso8601(expires_on) | ||
end | ||
end | ||
|
||
@spec refresh_token(String.t(), String.t(), String.t(), String.t()) :: String.t() | ||
def refresh_token(tenant, refresh_token, client_id, _apiserver_id) do | ||
payload = | ||
URI.encode_query(%{ | ||
"client_id" => client_id, | ||
"grant_type" => "refresh_token", | ||
"refresh_token" => refresh_token | ||
}) | ||
|
||
{:ok, res} = | ||
K8s.Client.MintHTTPProvider.request( | ||
:post, | ||
URI.new!("https://login.microsoftonline.com/#{tenant}/oauth2/v2.0/token"), | ||
payload, | ||
[ | ||
{ | ||
"Content-Type", | ||
"application/x-www-form-urlencoded" | ||
} | ||
], | ||
ssl: [] | ||
) | ||
|
||
Map.get(res, "access_token") | ||
end | ||
|
||
defimpl RequestOptions, for: __MODULE__ do | ||
@spec generate(K8s.Conn.Auth.Azure.t()) :: RequestOptions.generate_t() | ||
def generate(%K8s.Conn.Auth.Azure{token: token}) do | ||
{:ok, | ||
%RequestOptions{ | ||
headers: [{:Authorization, "Bearer #{token}"}], | ||
ssl_options: [] | ||
}} | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
defmodule K8s.Conn.Auth.AzureTest do | ||
@moduledoc false | ||
use ExUnit.Case, async: true | ||
|
||
alias K8s.Conn | ||
alias K8s.Conn.Auth.Azure | ||
|
||
describe "create/2" do | ||
test "creates a Azure struct from data" do | ||
non_expired_unix_ts = DateTime.utc_now() |> DateTime.add(10, :minute) |> DateTime.to_unix() | ||
|
||
auth = %{ | ||
"auth-provider" => %{ | ||
"config" => %{ | ||
"access-token" => "xxx", | ||
"apiserver-id" => "service_id", | ||
"client-id" => "client_id", | ||
"expires-on" => "#{non_expired_unix_ts}", | ||
"refresh-token" => "yyy", | ||
"tenant-id" => "tenant" | ||
}, | ||
"name" => "azure" | ||
} | ||
} | ||
|
||
assert {:ok, | ||
%Azure{ | ||
token: "xxx" | ||
}} = Azure.create(auth, nil) | ||
end | ||
end | ||
|
||
test "creates http request signing options" do | ||
provider = %Azure{ | ||
token: "xxx" | ||
} | ||
|
||
{:ok, %Conn.RequestOptions{headers: headers, ssl_options: ssl_options}} = | ||
Conn.RequestOptions.generate(provider) | ||
|
||
assert headers == [{:Authorization, "Bearer xxx"}] | ||
assert ssl_options == [] | ||
end | ||
end |