Skip to content

Commit

Permalink
Merge pull request #225 from Hanspagh/develop
Browse files Browse the repository at this point in the history
add azure auth provider
  • Loading branch information
mruoss authored Mar 8, 2023
2 parents 8d6934d + 1155d12 commit 1d9d183
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

<!-- ### Added | Changed | Deprecated | Removed | Fixed | Security -->

### Added
- Azure auth provider #225

<!--------------------- Don't add new entries after this line --------------------->

## [2.1.1] - 2023-03-02
Expand Down
2 changes: 1 addition & 1 deletion lib/k8s/client/mint_http_provider.ex
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ defmodule K8s.Client.MintHTTPProvider do
@spec get_content_type(keyword()) :: binary | nil
defp get_content_type(headers) do
case List.keyfind(headers, "content-type", 0) do
{_key, content_type} -> content_type
{_key, content_type} -> content_type |> String.split(";") |> List.first()
_ -> nil
end
end
Expand Down
91 changes: 91 additions & 0 deletions lib/k8s/conn/auth/azure.ex
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
44 changes: 44 additions & 0 deletions test/k8s/conn/auth/azure_test.exs
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

0 comments on commit 1d9d183

Please sign in to comment.