Packages
oidcc
3.0.1
3.7.2
3.7.1
3.7.0
3.6.0
3.5.2
3.5.1
3.5.0
retired
3.4.0
3.3.0
3.2.6
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.2.0-beta.3
3.2.0-beta.2
retired
3.2.0-beta.1
retired
3.1.2
3.1.2-beta.1
retired
3.1.1
retired
3.1.0
retired
3.1.0-beta.2
retired
3.1.0-beta.1
retired
3.0.2
3.0.1
retired
3.0.0
retired
3.0.0-rc.6
retired
3.0.0-rc.5
retired
3.0.0-rc.4
retired
3.0.0-rc.3
retired
3.0.0-rc.2
retired
3.0.0-rc.1
retired
3.0.0-alpha.5
retired
3.0.0-alpha.4
retired
3.0.0-alpha.3
retired
3.0.0-alpha.2
retired
3.0.0-alpha.1
retired
2.0.0-alpha.2
retired
2.0.0-alpha.1
retired
1.8.1
retired
1.8.0
retired
1.7.0
retired
1.6.0
retired
1.5.1
retired
1.5.0
retired
1.4.0
retired
1.3.0
retired
1.2.1
retired
1.2.0
retired
1.1.0
retired
1.0.1
retired
1.0.0
retired
OpenID Connect client library for the BEAM.
Retired package: Security issue - DoS Vulnerability, see https://github.com/erlef/oidcc/security/advisories/GHSA-mj35-2rgf-cv8p
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
src/oidcc_provider_configuration.erl
%%%-------------------------------------------------------------------
%% @doc Tooling to load and parse Openid Configuration
%%
%% <h2>Records</h2>
%%
%% To use the record, import the definition:
%%
%% ```
%% -include_lib(["oidcc/include/oidcc_provider_configuration.hrl"]).
%% '''
%%
%% <h2>Telemetry</h2>
%%
%% See {@link 'Elixir.Oidcc.ProviderConfiguration'}
%% @end
%% @since 3.0.0
%%%-------------------------------------------------------------------
-module(oidcc_provider_configuration).
-feature(maybe_expr, enable).
-include("oidcc_provider_configuration.hrl").
-export([decode_configuration/1]).
-export([load_configuration/2]).
-export([load_jwks/2]).
-export_type([error/0]).
-export_type([opts/0]).
-export_type([t/0]).
-type opts() :: #{
fallback_expiry => timeout(),
request_opts => oidcc_http_util:request_opts()
}.
%% Configure configuration loading / parsing
%%
%% <h2>Parameters</h2>
%%
%% <ul>
%% <li>`fallback_expiry' - How long to keep configuration cached if the server doesn't specify expiry</li>
%% <li>`request_opts' - config for HTTP request</li>
%% </ul>
-type t() ::
#oidcc_provider_configuration{
issuer :: uri_string:uri_string(),
authorization_endpoint :: uri_string:uri_string(),
token_endpoint :: uri_string:uri_string() | undefined,
userinfo_endpoint :: uri_string:uri_string() | undefined,
jwks_uri :: uri_string:uri_string() | undefined,
registration_endpoint :: uri_string:uri_string() | undefined,
scopes_supported :: [binary()] | undefined,
response_types_supported :: [binary()],
response_modes_supported :: [binary()],
grant_types_supported :: [binary()],
acr_values_supported :: [binary()] | undefined,
subject_types_supported :: [pairwise | public],
id_token_signing_alg_values_supported :: [binary()],
id_token_encryption_alg_values_supported ::
[binary()] | undefined,
id_token_encryption_enc_values_supported ::
[binary()] | undefined,
userinfo_signing_alg_values_supported :: [binary()] | undefined,
userinfo_encryption_alg_values_supported ::
[binary()] | undefined,
userinfo_encryption_enc_values_supported ::
[binary()] | undefined,
request_object_signing_alg_values_supported ::
[binary()] | undefined,
request_object_encryption_alg_values_supported ::
[binary()] | undefined,
request_object_encryption_enc_values_supported ::
[binary()] | undefined,
token_endpoint_auth_methods_supported :: [binary()],
token_endpoint_auth_signing_alg_values_supported ::
[binary()] | undefined,
display_values_supported :: [binary()] | undefined,
claim_types_supported :: [normal | aggregated | distributed],
claims_supported :: [binary()] | undefined,
service_documentation :: uri_string:uri_string() | undefined,
claims_locales_supported :: [binary()] | undefined,
ui_locales_supported :: [binary()] | undefined,
claims_parameter_supported :: boolean(),
request_parameter_supported :: boolean(),
request_uri_parameter_supported :: boolean(),
require_request_uri_registration :: boolean(),
op_policy_uri :: uri_string:uri_string() | undefined,
op_tos_uri :: uri_string:uri_string() | undefined,
revocation_endpoint :: uri_string:uri_string() | undefined,
revocation_endpoint_auth_methods_supported :: [binary()],
revocation_endpoint_auth_signing_alg_values_supported ::
[binary()] | undefined,
introspection_endpoint :: uri_string:uri_string() | undefined,
introspection_endpoint_auth_methods_supported :: [binary()],
introspection_endpoint_auth_signing_alg_values_supported ::
[binary()] | undefined,
code_challenge_methods_supported :: [binary()] | undefined,
end_session_endpoint :: uri_string:uri_string() | undefined,
extra_fields :: #{binary() => term()}
}.
%% Record containing OpenID and OAuth 2.0 Configuration
%%
%% See [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata],
%% [https://datatracker.ietf.org/doc/html/draft-jones-oauth-discovery-01#section-4.1] and
%% [https://openid.net/specs/openid-connect-rpinitiated-1_0.html#OPMetadata]
%%
%% All unrecognized fields are stored in `extra_fields'.
-type error() ::
invalid_content_type
| {issuer_mismatch, Issuer :: binary()}
| oidcc_decode_util:error()
| oidcc_http_util:error().
-define(DEFAULT_CONFIG_EXPIRY, timer:minutes(15)).
-telemetry_event(#{
event => [oidcc, load_configuration, start],
description => <<"Emitted at the start of loading the provider configuration">>,
measurements => <<"#{system_time => non_neg_integer()}">>,
metadata => <<"#{issuer => uri_string:uri_string()}">>
}).
-telemetry_event(#{
event => [oidcc, load_configuration, stop],
description => <<"Emitted at the end of loading the provider configuration">>,
measurements => <<"#{duration => integer(), monotonic_time => integer()}">>,
metadata => <<"#{issuer => uri_string:uri_string()}">>
}).
-telemetry_event(#{
event => [oidcc, load_configuration, exception],
description => <<"Emitted at the end of loading the provider configuration">>,
measurements => <<"#{duration => integer(), monotonic_time => integer()}">>,
metadata => <<"#{issuer => uri_string:uri_string()}">>
}).
-telemetry_event(#{
event => [oidcc, load_jwks, start],
description => <<"Emitted at the start of loading the provider jwks">>,
measurements => <<"#{system_time => non_neg_integer()}">>,
metadata => <<"#{jwks_uri => uri_string:uri_string()}">>
}).
-telemetry_event(#{
event => [oidcc, load_jwks, stop],
description => <<"Emitted at the end of loading the provider jwks">>,
measurements => <<"#{duration => integer(), monotonic_time => integer()}">>,
metadata => <<"#{jwks_uri => uri_string:uri_string()}">>
}).
-telemetry_event(#{
event => [oidcc, load_jwks, exception],
description => <<"Emitted at the end of loading the provider jwks">>,
measurements => <<"#{duration => integer(), monotonic_time => integer()}">>,
metadata => <<"#{jwks_uri => uri_string:uri_string()}">>
}).
%% @doc Load OpenID Configuration into a {@link oidcc_provider_configuration:t()} record
%%
%% <h2>Examples</h2>
%%
%% ```
%% {ok, #oidcc_provider_configuration{}} =
%% oidcc_provider_configuration:load_configuration("https://accounts.google.com").
%% '''
%% @end
%% @since 3.0.0
-spec load_configuration(Issuer, Opts) ->
{ok, {Configuration :: t(), Expiry :: pos_integer()}} | {error, error()}
when
Issuer :: uri_string:uri_string(),
Opts :: opts().
load_configuration(Issuer0, Opts) ->
Issuer = binary:list_to_bin([Issuer0]),
TelemetryOpts = #{topic => [oidcc, load_configuration], extra_meta => #{issuer => Issuer}},
RequestOpts = maps:get(request_opts, Opts, #{}),
RequestUrl = uri_string:resolve(".well-known/openid-configuration", Issuer),
Request = {RequestUrl, []},
maybe
{ok, {{json, ConfigurationMap}, Headers}} ?=
oidcc_http_util:request(get, Request, TelemetryOpts, RequestOpts),
Expiry = headers_to_deadline(Headers, Opts),
{ok, #oidcc_provider_configuration{issuer = Issuer} = Configuration} ?=
decode_configuration(ConfigurationMap),
{ok, {Configuration, Expiry}}
else
{ok, #oidcc_provider_configuration{issuer = DifferentIssuer}} ->
{error, {issuer_mismatch, DifferentIssuer}};
{error, Reason} ->
{error, Reason};
{ok, {{_Format, _Body}, _Headers}} ->
{error, invalid_content_type}
end.
%% @doc Load JWKs into a {@link jose_jwk:key()} record
%%
%% <h2>Examples</h2>
%%
%% ```
%% {ok, #jose_jwk{}} =
%% oidcc_provider_configuration:load_jwks("https://www.googleapis.com/oauth2/v3/certs").
%% '''
%% @end
%% @since 3.0.0
-spec load_jwks(JwksUri, Opts) ->
{ok, {Jwks :: jose_jwk:key(), Expiry :: pos_integer()}} | {error, term()}
when
JwksUri :: uri_string:uri_string(),
Opts :: opts().
load_jwks(JwksUri, Opts) ->
TelemetryOpts = #{topic => [oidcc, load_jwks], extra_meta => #{jwks_uri => JwksUri}},
RequestOpts = maps:get(request_opts, Opts, #{}),
maybe
{ok, {{json, JwksBinary}, Headers}} ?=
oidcc_http_util:request(get, {JwksUri, []}, TelemetryOpts, RequestOpts),
Expiry = headers_to_deadline(Headers, Opts),
Jwks = jose_jwk:from(JwksBinary),
{ok, {Jwks, Expiry}}
else
{error, Reason} -> {error, Reason};
{ok, {{_Format, _Body}, _Headers}} -> {error, invalid_content_type}
end.
%% @doc Decode JSON into a {@link oidcc_provider_configuration:t()} record
%%
%% <h2>Examples</h2>
%%
%% ```
%% {ok, {{"HTTP/1.1",200,"OK"}, _Headers, Body}} =
%% httpc:request("https://accounts.google.com/.well-known/openid-configuration"),
%%
%% {ok, DecodedJson} = your_json_lib:decode(Body),
%%
%% {ok, #oidcc_provider_configuration{}} =
%% oidcc_provider_configuration:decode_configuration(DecodedJson).
%% '''
%% @end
%% @since 3.0.0
-spec decode_configuration(Configuration :: map()) -> {ok, t()} | {error, error()}.
decode_configuration(Configuration) ->
maybe
{ok, {
#{
issuer := Issuer,
authorization_endpoint := AuthorizationEndpoint,
authorization_endpoint := AuthorizationEndpoint,
token_endpoint := TokenEndpoint,
userinfo_endpoint := UserinfoEndpoint,
jwks_uri := JwksUri,
registration_endpoint := RegistrationEndpoint,
scopes_supported := ScopesSupported,
response_types_supported := ResponseTypesSupported,
response_modes_supported := ResponseModesSupported,
grant_types_supported := GrantTypesSupported,
acr_values_supported := AcrValuesSupported,
subject_types_supported := SubjectTypesSupported,
id_token_signing_alg_values_supported := IdTokenSigningAlgValuesSupported,
id_token_encryption_alg_values_supported := IdTokenEncryptionAlgValuesSupported,
id_token_encryption_enc_values_supported := IdTokenEncryptionEncValuesSupported,
userinfo_signing_alg_values_supported := UserinfoSigningAlgValuesSupported,
userinfo_encryption_alg_values_supported := UserinfoEncryptionAlgValuesSupported,
userinfo_encryption_enc_values_supported := UserinfoEncryptionEncValuesSupported,
request_object_signing_alg_values_supported :=
RequestObjectSigningAlgValuesSupported,
request_object_encryption_alg_values_supported :=
RequestObjectEncryptionAlgValuesSupported,
request_object_encryption_enc_values_supported :=
RequestObjectEncryptionEncValuesSupported,
token_endpoint_auth_methods_supported := TokenEndpointAuthMethodsSupported,
token_endpoint_auth_signing_alg_values_supported :=
TokenEndpointAuthSigningAlgValuesSupported,
display_values_supported := DisplayValuesSupported,
claim_types_supported := ClaimTypesSupported,
claims_supported := ClaimsSupported,
service_documentation := ServiceDocumentation,
claims_locales_supported := ClaimsLocalesSupported,
ui_locales_supported := UiLocalesSupported,
claims_parameter_supported := ClaimsParameterSupported,
request_parameter_supported := RequestParameterSupported,
request_uri_parameter_supported := RequestUriParameterSupported,
require_request_uri_registration := RequireRequestUriRegistration,
op_policy_uri := OpPolicyUri,
op_tos_uri := OpTosUri,
revocation_endpoint := RevocationEndpoint,
revocation_endpoint_auth_methods_supported :=
RevocationEndpointAuthMethodsSupported,
revocation_endpoint_auth_signing_alg_values_supported :=
RevocationEndpointAuthSigningAlgValuesSupported,
introspection_endpoint := IntrospectionEndpoint,
introspection_endpoint_auth_methods_supported :=
IntrospectionEndpointAuthMethodsSupported,
introspection_endpoint_auth_signing_alg_values_supported :=
IntrospectionEndpointAuthSigningAlgValuesSupported,
code_challenge_methods_supported := CodeChallengeMethodsSupported,
end_session_endpoint := EndSessionEndpoint
},
ExtraFields
}} ?=
oidcc_decode_util:extract(
Configuration,
[
{required, issuer, fun oidcc_decode_util:parse_setting_uri/2},
{required, authorization_endpoint, fun oidcc_decode_util:parse_setting_uri/2},
{optional, token_endpoint, undefined,
fun oidcc_decode_util:parse_setting_uri/2},
{optional, userinfo_endpoint, undefined,
fun oidcc_decode_util:parse_setting_uri_https/2},
{required, jwks_uri, fun oidcc_decode_util:parse_setting_uri/2},
{optional, registration_endpoint, undefined,
fun oidcc_decode_util:parse_setting_uri/2},
{required, scopes_supported, fun parse_scopes_supported/2},
{required, response_types_supported,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, response_modes_supported, [<<"query">>, <<"fragment">>],
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, grant_types_supported, [<<"authorization_code">>, <<"implicit">>],
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, acr_values_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{required, subject_types_supported, fun parse_subject_types_supported/2},
{required, id_token_signing_alg_values_supported,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, id_token_encryption_alg_values_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, id_token_encryption_enc_values_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, userinfo_signing_alg_values_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, userinfo_encryption_alg_values_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, userinfo_encryption_enc_values_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, request_object_signing_alg_values_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, request_object_encryption_alg_values_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, request_object_encryption_enc_values_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, token_endpoint_auth_methods_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, token_endpoint_auth_signing_alg_values_supported, undefined,
fun parse_token_signing_alg_values_no_none/2},
{optional, display_values_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, claim_types_supported, [normal], fun parse_claim_types_supported/2},
{optional, claims_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, service_documentation, undefined,
fun oidcc_decode_util:parse_setting_uri/2},
{optional, claims_locales_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, ui_locales_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, claims_parameter_supported, false,
fun oidcc_decode_util:parse_setting_boolean/2},
{optional, request_parameter_supported, false,
fun oidcc_decode_util:parse_setting_boolean/2},
{optional, request_uri_parameter_supported, true,
fun oidcc_decode_util:parse_setting_boolean/2},
{optional, require_request_uri_registration, false,
fun oidcc_decode_util:parse_setting_boolean/2},
{optional, op_policy_uri, undefined, fun oidcc_decode_util:parse_setting_uri/2},
{optional, op_tos_uri, undefined, fun oidcc_decode_util:parse_setting_uri/2},
{optional, revocation_endpoint, undefined,
fun oidcc_decode_util:parse_setting_uri/2},
{optional, revocation_endpoint_auth_methods_supported,
[<<"client_secret_basic">>],
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, revocation_endpoint_auth_signing_alg_values_supported, undefined,
fun parse_token_signing_alg_values_no_none/2},
{optional, introspection_endpoint, undefined,
fun oidcc_decode_util:parse_setting_uri/2},
{optional, introspection_endpoint_auth_methods_supported,
[<<"client_secret_basic">>],
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, introspection_endpoint_auth_signing_alg_values_supported, undefined,
fun parse_token_signing_alg_values_no_none/2},
{optional, code_challenge_methods_supported, undefined,
fun oidcc_decode_util:parse_setting_binary_list/2},
{optional, end_session_endpoint, undefined,
fun oidcc_decode_util:parse_setting_uri_https/2}
],
#{}
),
{ok, #oidcc_provider_configuration{
issuer = Issuer,
authorization_endpoint = AuthorizationEndpoint,
token_endpoint = TokenEndpoint,
userinfo_endpoint = UserinfoEndpoint,
jwks_uri = JwksUri,
registration_endpoint = RegistrationEndpoint,
scopes_supported = ScopesSupported,
response_types_supported = ResponseTypesSupported,
response_modes_supported = ResponseModesSupported,
grant_types_supported = GrantTypesSupported,
acr_values_supported = AcrValuesSupported,
subject_types_supported = SubjectTypesSupported,
id_token_signing_alg_values_supported =
IdTokenSigningAlgValuesSupported,
id_token_encryption_alg_values_supported =
IdTokenEncryptionAlgValuesSupported,
id_token_encryption_enc_values_supported =
IdTokenEncryptionEncValuesSupported,
userinfo_signing_alg_values_supported =
UserinfoSigningAlgValuesSupported,
userinfo_encryption_alg_values_supported =
UserinfoEncryptionAlgValuesSupported,
userinfo_encryption_enc_values_supported =
UserinfoEncryptionEncValuesSupported,
request_object_signing_alg_values_supported =
RequestObjectSigningAlgValuesSupported,
request_object_encryption_alg_values_supported =
RequestObjectEncryptionAlgValuesSupported,
request_object_encryption_enc_values_supported =
RequestObjectEncryptionEncValuesSupported,
token_endpoint_auth_methods_supported =
TokenEndpointAuthMethodsSupported,
token_endpoint_auth_signing_alg_values_supported =
TokenEndpointAuthSigningAlgValuesSupported,
display_values_supported = DisplayValuesSupported,
claim_types_supported = ClaimTypesSupported,
claims_supported = ClaimsSupported,
service_documentation = ServiceDocumentation,
claims_locales_supported = ClaimsLocalesSupported,
ui_locales_supported = UiLocalesSupported,
claims_parameter_supported = ClaimsParameterSupported,
request_parameter_supported = RequestParameterSupported,
request_uri_parameter_supported =
RequestUriParameterSupported,
require_request_uri_registration =
RequireRequestUriRegistration,
op_policy_uri = OpPolicyUri,
op_tos_uri = OpTosUri,
revocation_endpoint = RevocationEndpoint,
revocation_endpoint_auth_methods_supported =
RevocationEndpointAuthMethodsSupported,
revocation_endpoint_auth_signing_alg_values_supported =
RevocationEndpointAuthSigningAlgValuesSupported,
introspection_endpoint = IntrospectionEndpoint,
introspection_endpoint_auth_methods_supported =
IntrospectionEndpointAuthMethodsSupported,
introspection_endpoint_auth_signing_alg_values_supported =
IntrospectionEndpointAuthSigningAlgValuesSupported,
code_challenge_methods_supported =
CodeChallengeMethodsSupported,
end_session_endpoint = EndSessionEndpoint,
extra_fields = ExtraFields
}}
end.
-spec headers_to_deadline(Headers, Opts) -> pos_integer() when
Headers :: [{Header :: binary(), Value :: binary()}], Opts :: opts().
headers_to_deadline(Headers, Opts) ->
DefaultExpiry = maps:get(fallback_expiry, Opts, ?DEFAULT_CONFIG_EXPIRY),
case proplists:lookup("cache-control", Headers) of
{"cache-control", Cache} ->
try
cache_deadline(Cache, DefaultExpiry)
catch
_:_ ->
DefaultExpiry
end;
none ->
DefaultExpiry
end.
-spec cache_deadline(Cache :: iodata(), Fallback :: pos_integer()) -> pos_integer().
cache_deadline(Cache, Fallback) ->
Entries =
binary:split(iolist_to_binary(Cache), [<<",">>, <<"=">>, <<" ">>], [global, trim_all]),
MaxAge =
fun
(<<"0">>, Res) ->
Res;
(Entry, true) ->
erlang:convert_time_unit(binary_to_integer(Entry), second, millisecond);
(<<"max-age">>, _) ->
true;
(_, Res) ->
Res
end,
lists:foldl(MaxAge, Fallback, Entries).
-spec parse_scopes_supported(Setting :: term(), Field :: atom()) ->
{ok, [binary()]} | {error, error()}.
parse_scopes_supported(Setting, Field) ->
case oidcc_decode_util:parse_setting_binary_list(Setting, Field) of
{ok, Scopes} ->
case lists:member(<<"openid">>, Scopes) of
true ->
{ok, Scopes};
false ->
{error, {invalid_config_property, {scopes_including_openid, Field}}}
end;
{error, Reason} ->
{error, Reason}
end.
-spec parse_subject_types_supported(Setting :: term(), Field :: atom()) ->
{ok, [binary()]} | {error, error()}.
parse_subject_types_supported(Setting, Field) ->
oidcc_decode_util:parse_setting_list_enum(
Setting,
Field,
fun
(<<"pairwise">>) ->
{ok, pairwise};
(<<"public">>) ->
{ok, public};
(_SubjectType) ->
error
end
).
-spec parse_token_signing_alg_values_no_none(Setting :: term(), Field :: atom()) ->
{ok, [binary()]} | {error, error()}.
parse_token_signing_alg_values_no_none(Setting, Field) ->
case oidcc_decode_util:parse_setting_binary_list(Setting, Field) of
{ok, SigningAlgValues} ->
case
lists:any(
fun
(<<"none">>) ->
true;
(_) ->
false
end,
SigningAlgValues
)
of
false ->
{ok, SigningAlgValues};
true ->
{error, {invalid_config_property, {alg_no_none, Field}}}
end;
{error, Reason} ->
{error, Reason}
end.
-spec parse_claim_types_supported(Setting :: term(), Field :: atom()) ->
{ok, [binary()]} | {error, error()}.
parse_claim_types_supported(Setting, Field) ->
oidcc_decode_util:parse_setting_list_enum(
Setting,
Field,
fun
(<<"normal">>) ->
{ok, normal};
(<<"aggregated">>) ->
{ok, aggregated};
(<<"distributed">>) ->
{ok, distributed};
(_ClaimType) ->
error
end
).