-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
improvement: add apple strategy (#750)
* improvement: add apple strategy * fix: update types and formatter * fix: add secret values to config * fix: sort new fields * fix: sort new types * fix: properly set allow_nil for apple secrets * fix: credo and sobelow warnings --------- Co-authored-by: James Harton <[email protected]>
- Loading branch information
Showing
7 changed files
with
174 additions
and
0 deletions.
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,29 @@ | ||
defmodule AshAuthentication.Strategy.Apple do | ||
alias __MODULE__.{Dsl, Verifier} | ||
|
||
@moduledoc """ | ||
Strategy for authenticating using [Apple Sign In](https://developer.apple.com/sign-in-with-apple/) | ||
This strategy builds on-top of `AshAuthentication.Strategy.Oidc` and | ||
[`assent`](https://hex.pm/packages/assent). | ||
In order to use Apple Sign In you need to provide the following minimum configuration: | ||
- `client_id` | ||
- `team_id` | ||
- `private_key_id` | ||
- `private_key_path` | ||
- `redirect_uri` | ||
## More documentation: | ||
- The [Apple Sign In Documentation](https://developer.apple.com/documentation/sign_in_with_apple). | ||
- The [OIDC documentation](`AshAuthentication.Strategy.Oidc`) | ||
""" | ||
|
||
alias AshAuthentication.Strategy.{Custom, Oidc} | ||
|
||
use Custom, entity: Dsl.dsl() | ||
|
||
defdelegate transform(strategy, dsl_state), to: Oidc | ||
defdelegate verify(strategy, dsl_state), to: Verifier | ||
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,95 @@ | ||
defmodule AshAuthentication.Strategy.Apple.Dsl do | ||
@moduledoc false | ||
|
||
alias AshAuthentication.Strategy.{Custom, Oidc} | ||
|
||
@doc false | ||
@spec dsl :: Custom.entity() | ||
def dsl do | ||
secret_type = AshAuthentication.Dsl.secret_type() | ||
|
||
Oidc.Dsl.dsl() | ||
|> Map.merge(%{ | ||
name: :apple, | ||
args: [{:optional, :name, :apple}], | ||
describe: """ | ||
Provides a pre-configured authentication strategy for [Apple Sign In](https://developer.apple.com/sign-in-with-apple/). | ||
This strategy is built using the `:oidc` strategy, and thus provides all the same | ||
configuration options should you need them. | ||
## More documentation: | ||
- The [Apple Sign In Documentation](https://developer.apple.com/documentation/sign_in_with_apple). | ||
- The [OIDC documentation](`AshAuthentication.Strategy.Oidc`) | ||
#### Strategy defaults: | ||
#{strategy_override_docs(Assent.Strategy.Apple)} | ||
""", | ||
auto_set_fields: strategy_fields(Assent.Strategy.Apple, icon: :apple), | ||
schema: patch_schema(secret_type) | ||
}) | ||
end | ||
|
||
defp patch_schema(secret_type) do | ||
Oidc.Dsl.dsl() | ||
|> Map.get(:schema, []) | ||
|> Keyword.merge( | ||
team_id: [ | ||
type: secret_type, | ||
doc: "The Apple team ID associated with the application.", | ||
required: true | ||
], | ||
private_key_id: [ | ||
type: secret_type, | ||
doc: "The private key ID used for signing the JWT token.", | ||
required: true | ||
], | ||
private_key_path: [ | ||
type: secret_type, | ||
doc: "The path to the private key file used for signing the JWT token.", | ||
required: true | ||
] | ||
) | ||
end | ||
|
||
defp strategy_fields(strategy, params) do | ||
strategy.default_config([]) | ||
|> Enum.map(fn | ||
{:client_authentication_method, method} -> | ||
{:client_authentication_method, String.to_existing_atom(method)} | ||
|
||
{:openid_configuration, config} -> | ||
{:openid_configuration, atomize_keys(config)} | ||
|
||
{key, value} -> | ||
{key, value} | ||
end) | ||
|> Keyword.put(:assent_strategy, strategy) | ||
|> Keyword.merge(params) | ||
end | ||
|
||
# sobelow_skip ["DOS.StringToAtom"] | ||
defp atomize_keys(map) do | ||
map | ||
|> Enum.map(fn {key, value} -> {String.to_atom(key), value} end) | ||
|> Enum.into(%{}) | ||
end | ||
|
||
defp strategy_override_docs(strategy) do | ||
defaults = | ||
strategy.default_config([]) | ||
|> Enum.map_join( | ||
".\n", | ||
fn {key, value} -> | ||
" * `#{inspect(key)}` is set to `#{inspect(value)}`" | ||
end | ||
) | ||
|
||
""" | ||
The following defaults are applied: | ||
#{defaults}. | ||
""" | ||
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,19 @@ | ||
defmodule AshAuthentication.Strategy.Apple.Verifier do | ||
@moduledoc """ | ||
DSL verifier for Apple strategy. | ||
""" | ||
|
||
alias AshAuthentication.Strategy.OAuth2 | ||
import AshAuthentication.Validations | ||
|
||
@doc false | ||
@spec verify(OAuth2.t(), map) :: :ok | {:error, Exception.t()} | ||
def verify(strategy, _dsl_state) do | ||
with :ok <- validate_secret(strategy, :client_id), | ||
:ok <- validate_secret(strategy, :team_id), | ||
:ok <- validate_secret(strategy, :private_key_id), | ||
:ok <- validate_secret(strategy, :private_key_path) do | ||
validate_secret(strategy, :redirect_uri) | ||
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
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