Skip to content

Commit

Permalink
Add assertion extractor
Browse files Browse the repository at this point in the history
  • Loading branch information
chownces committed May 10, 2024
1 parent 92b20c5 commit 4f994a8
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 61 deletions.
32 changes: 32 additions & 0 deletions config/cadet.exs.example
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ config :cadet,
# # You may need to write your own claim extractor for other providers
# claim_extractor: Cadet.Auth.Providers.CognitoClaimExtractor
# }},

# # Example SAML authentication with NUS Student IdP
# "test_saml" =>
# {Cadet.Auth.Providers.SAML,
# %{assertion_extractor: Cadet.Auth.Providers.NusstuAssertionExtractor}},

"test" =>
{Cadet.Auth.Providers.Config,
[
Expand Down Expand Up @@ -142,3 +148,29 @@ config :cadet,
# You may also want to change the timezone used for scheduled jobs
# config :cadet, Cadet.Jobs.Scheduler,
# timezone: "Asia/Singapore",

# # Additional configuration for SAML authentication
# # For more details, see https://github.com/handnot2/samly
# config :samly, Samly.Provider,
# idp_id_from: :path_segment,
# service_providers: [
# %{
# id: "source-academy-backend",
# certfile: "example_path/certfile.pem",
# keyfile: "example_path/keyfile.pem"
# }
# ],
# identity_providers: [
# %{
# id: "student",
# sp_id: "source-academy-backend",
# base_url: "https://example_backend/sso",
# metadata_file: "student_idp_metadata.xml"
# },
# %{
# id: "staff",
# sp_id: "source-academy-backend",
# base_url: "https://example_backend/sso",
# metadata_file: "staff_idp_metadata.xml"
# }
# ]
35 changes: 33 additions & 2 deletions config/dev.secrets.exs.example
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ config :cadet,
# token_url: "https://github.com/login/oauth/access_token",
# user_api: "https://api.github.com/user"
# }},
"test_saml" => {Cadet.Auth.Providers.SimpleSAML, %{idp_id: "testidp"}},

# # Example SAML authentication with NUS Student IdP
# "test_saml" =>
# {Cadet.Auth.Providers.SAML,
# %{assertion_extractor: Cadet.Auth.Providers.NusstuAssertionExtractor}},

"test" =>
{Cadet.Auth.Providers.Config,
[
Expand Down Expand Up @@ -91,10 +96,36 @@ config :cadet,
config :openai,
# find it at https://platform.openai.com/account/api-keys
api_key: "the actual api key",
# For source academy deployment, leave this as empty string.Ingeneral could find it at https://platform.openai.com/account/org-settings under "Organization ID".
# For source academy deployment, leave this as empty string.Ingeneral could find it at https://platform.openai.com/account/org-settings under "Organization ID".
organization_key: "",
# optional, passed to [HTTPoison.Request](https://hexdocs.pm/httpoison/HTTPoison.Request.html) options
http_options: [recv_timeout: 170_0000]

config :sentry,
dsn: "https://public_key/sentry.io/somethingsomething"

# # Additional configuration for SAML authentication
# # For more details, see https://github.com/handnot2/samly
# config :samly, Samly.Provider,
# idp_id_from: :path_segment,
# service_providers: [
# %{
# id: "source-academy-backend",
# certfile: "example_path/certfile.pem",
# keyfile: "example_path/keyfile.pem"
# }
# ],
# identity_providers: [
# %{
# id: "student",
# sp_id: "source-academy-backend",
# base_url: "https://example_backend/sso",
# metadata_file: "student_idp_metadata.xml"
# },
# %{
# id: "staff",
# sp_id: "source-academy-backend",
# base_url: "https://example_backend/sso",
# metadata_file: "staff_idp_metadata.xml"
# }
# ]
15 changes: 15 additions & 0 deletions lib/cadet/auth/providers/saml/nusstf_assertion_extractor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule Cadet.Auth.Providers.NusstfAssertionExtractor do
@moduledoc """
Extracts fields from NUS Staff IdP SAML assertions.
"""

@behaviour Cadet.Auth.Providers.AssertionExtractor

def get_username(assertion) do
Map.get(assertion.attributes, "SamAccountName")
end

def get_name(assertion) do
Map.get(assertion.attributes, "DisplayName")
end
end
15 changes: 15 additions & 0 deletions lib/cadet/auth/providers/saml/nusstu_assertion_extractor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule Cadet.Auth.Providers.NusstuAssertionExtractor do
@moduledoc """
Extracts fields from NUS Student IdP SAML assertions.
"""

@behaviour Cadet.Auth.Providers.AssertionExtractor

def get_username(assertion) do
Map.get(assertion.attributes, "samaccountname")
end

def get_name(assertion) do
Map.get(assertion.attributes, "samaccountname")
end
end
48 changes: 48 additions & 0 deletions lib/cadet/auth/providers/saml/saml.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
defmodule Cadet.Auth.Providers.SAML do
@moduledoc """
Provides identity using SAML.
"""
alias Cadet.Auth.Provider
alias Samly.Assertion

Check warning on line 6 in lib/cadet/auth/providers/saml/saml.ex

View workflow job for this annotation

GitHub Actions / Build release

unused alias Assertion

@behaviour Provider

@type config :: %{assertion_extractor: module()}

@spec authorise(
any(),
Provider.code() | Plug.Conn.t(),
Provider.client_id(),
Provider.redirect_uri()
) ::
{:ok, %{token: Provider.token(), username: String.t()}}
| {:error, Provider.error(), String.t()}
def authorise(config, conn, _client_id, _redirect_uri) do
%{assertion_extractor: assertion_extractor} = config

with {:assertion, assertion} when not is_nil(assertion) <-
{:assertion, Samly.get_attribute(conn)} do
{:ok,
%{
token: Jason.encode!(%{name: assertion_extractor.get_name(assertion)}),
username: assertion_extractor.get_username(assertion)
}}
else
{:assertion, nil} -> {:error, :invalid_credentials, "Missing SAML assertion!"}
end
end

@spec get_name(any(), Provider.token()) ::
{:ok, String.t()} | {:error, Provider.error(), String.t()}
def get_name(_config, token) do
{:ok, Jason.decode!(token).name}
end
end

defmodule Cadet.Auth.Providers.AssertionExtractor do
@moduledoc """
A behaviour for modules that extract fields from SAML assertions.
"""
@callback get_username(Samly.Assertion) :: String.t() | nil
@callback get_name(Samly.Assertion) :: String.t() | nil
end
59 changes: 0 additions & 59 deletions lib/cadet/auth/providers/simplesaml.ex

This file was deleted.

0 comments on commit 4f994a8

Please sign in to comment.