Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
5c144ac
add AZ support
StrawnSC May 16, 2022
340e37d
Merge pull request #105 from StrawnSC/az-aca
StrawnSC May 16, 2022
a637114
bump version, add history, fix style
StrawnSC May 16, 2022
5d85708
auto-register Microsoft.App RP
StrawnSC May 16, 2022
f51df48
autoregister on containerapp and env create
StrawnSC May 16, 2022
a51745a
Finished auth microsoft.
May 18, 2022
dac8c2f
Added prototypes of other identity providers.
May 18, 2022
522e6dd
Added param help.
May 18, 2022
9be335b
Added error handling for no easy auth case.
May 18, 2022
0eca228
Adding cmds & tests for Container app certs & domains (#107)
lil131 May 19, 2022
8185b3f
Merge branch 'containerapp-0.3.5' into autoregister-msft.app
StrawnSC May 19, 2022
59369f7
Added auth update and show.
May 19, 2022
1185d69
Moved utils to utils. Removed CLIErrors from old code. Removed commen…
May 19, 2022
ea0283d
fixes for CI
StrawnSC May 19, 2022
9a85503
use capps RP constant
StrawnSC May 19, 2022
6f2943c
Merge pull request #106 from StrawnSC/autoregister-msft.app
StrawnSC May 19, 2022
430cee2
rerecord tests; add credscan suppressions
StrawnSC May 19, 2022
873e531
Fixed style issues. Fixed sdk version.
May 19, 2022
5c87013
more CI fixes
StrawnSC May 19, 2022
8ad4ae0
Fixed merge conflicts.
May 19, 2022
11aeb5e
Updated history. Changed constant values instead of using python meth…
May 19, 2022
873a15f
Added help text for subgroups with examples.
May 19, 2022
e7137ff
Updated util. Fixed style issues.
May 19, 2022
8d31890
Merge pull request #108 from haroonf/authconfig
StrawnSC May 19, 2022
433433a
Revert "Add auth subgroups" (#109)
runefa May 19, 2022
90bfb2a
use new microsoft.graph API
StrawnSC May 4, 2022
baf9342
wip
StrawnSC May 20, 2022
d4f6cec
remove unused function
StrawnSC May 20, 2022
054db9b
Removed AuthClient sdk.
May 20, 2022
bbc1842
Added back AuthConfig.
May 20, 2022
8d31f6a
Removed old references. Limited oidc provider secret name. Fixed warn…
May 20, 2022
de354e6
Fixed facebook show bug.
May 20, 2022
87099c6
adding hostname tests with ASD
lil131 May 20, 2022
8f31760
fix location & add more test cases
lil131 May 20, 2022
b7f37a1
minor changes
lil131 May 20, 2022
699d2fc
rm redundant whitespaces
lil131 May 20, 2022
2ba057f
mark custom domain test as live_only
lil131 May 20, 2022
e3b3a59
Fixed error handling.
May 20, 2022
cf297ae
rm yaml files
lil131 May 21, 2022
2d39def
Merge pull request #110 from StrawnSC/microsoft.graph
StrawnSC May 22, 2022
4739052
add breaking change history note
StrawnSC May 22, 2022
a6fb46d
Merge pull request #112 from lil131/location-fix
StrawnSC May 22, 2022
1e977dd
Merge branch 'containerapp-0.3.5' into authconfig
StrawnSC May 22, 2022
e5237b6
bug fix in 'az containerapp auth update'
StrawnSC May 22, 2022
4b9eaab
Merge pull request #111 from haroonf/authconfig
StrawnSC May 22, 2022
8124269
remove dependencies on core CLI role module functions
StrawnSC May 22, 2022
0ae7357
remove 'BREAKING CHANGE' from history entry
StrawnSC May 23, 2022
6c86217
resolve PR comments
StrawnSC May 23, 2022
b671136
add test recording and remove live_only
StrawnSC May 23, 2022
881dbd8
make live only test live_only again
StrawnSC May 23, 2022
59eb990
remove unnecessary option lists
StrawnSC May 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Added auth update and show.
  • Loading branch information
Haroon Feisal committed May 19, 2022
commit 59369f744807fbedbbe732e04b59d0b7e46c8fce
4 changes: 2 additions & 2 deletions src/containerapp/azext_containerapp/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@
MSA_SECRET_SETTING_NAME = "MSA_PROVIDER_AUTHENTICATION_SECRET".lower().replace("_", "-")
TWITTER_SECRET_SETTING_NAME = "TWITTER_PROVIDER_AUTHENTICATION_SECRET".lower().replace("_", "-")
APPLE_SECRET_SETTING_NAME = "APPLE_PROVIDER_AUTHENTICATION_SECRET".lower().replace("_", "-")
TRUE_STRING = "true"
FALSE_STRING = "false"
UNAUTHENTICATED_CLIENT_ACTION = ['RedirectToLoginPage', 'AllowAnonymous', 'RejectWith401', 'RejectWith404']
FORWARD_PROXY_CONVENTION = ['NoProxy', 'Standard', 'Custom']
58 changes: 27 additions & 31 deletions src/containerapp/azext_containerapp/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from ._validators import (validate_memory, validate_cpu, validate_managed_env_name_or_id, validate_registry_server,
validate_registry_user, validate_registry_pass, validate_target_port, validate_ingress)

from ._constants import UNAUTHENTICATED_CLIENT_ACTION, FORWARD_PROXY_CONVENTION

def load_arguments(self, _):

Expand Down Expand Up @@ -262,34 +262,30 @@ def load_arguments(self, _):
c.argument('client_id', options_list=['--client-id'], help='The Client ID of the app used for login.')
c.argument('client_secret', options_list=['--client-secret'], help='The client secret.')
c.argument('client_secret_setting_name', options_list=['--client-secret-name'], help='The app setting name that contains the client secret of the relying party application.')
c.argument('issuer', options_list=['--issuer'],
help='The OpenID Connect Issuer URI that represents the entity which issues access tokens for this application.')
c.argument('allowed_token_audiences', options_list=['--allowed-token-audiences', '--allowed-audiences'],
help='The configuration settings of the allowed list of audiences from which to validate the JWT token.')
c.argument('client_secret_certificate_thumbprint', options_list=['--thumbprint', '--client-secret-certificate-thumbprint'],
help='Alternative to AAD Client Secret, thumbprint of a certificate used for signing purposes')
c.argument('client_secret_certificate_san', options_list=['--san', '--client-secret-certificate-san'],
help='Alternative to AAD Client Secret and thumbprint, subject alternative name of a certificate used for signing purposes')
c.argument('client_secret_certificate_issuer', options_list=['--certificate-issuer', '--client-secret-certificate-issuer'],
help='Alternative to AAD Client Secret and thumbprint, issuer of a certificate used for signing purposes')
c.argument('issuer', options_list=['--issuer'], help='The OpenID Connect Issuer URI that represents the entity which issues access tokens for this application.')
c.argument('allowed_token_audiences', options_list=['--allowed-token-audiences', '--allowed-audiences'], help='The configuration settings of the allowed list of audiences from which to validate the JWT token.')
c.argument('client_secret_certificate_thumbprint', options_list=['--thumbprint', '--client-secret-certificate-thumbprint'], help='Alternative to AAD Client Secret, thumbprint of a certificate used for signing purposes')
c.argument('client_secret_certificate_san', options_list=['--san', '--client-secret-certificate-san'], help='Alternative to AAD Client Secret and thumbprint, subject alternative name of a certificate used for signing purposes')
c.argument('client_secret_certificate_issuer', options_list=['--certificate-issuer', '--client-secret-certificate-issuer'], help='Alternative to AAD Client Secret and thumbprint, issuer of a certificate used for signing purposes')
c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true')
c.argument('tenant_id', options_list=['--tenant-id'],
help='The tenant id of the application.')
c.argument('app_id', options_list=['--app-id'],
help='The App ID of the app used for login.')
c.argument('app_secret', options_list=['--app-secret'],
help='The app secret.')
c.argument('app_secret_setting_name', options_list=['--app-secret-setting-name', '--secret-setting'],
help='The app setting name that contains the app secret.')
c.argument('graph_api_version', options_list=['--graph-api-version'],
help='The version of the Facebook api to be used while logging in.')
c.argument('scopes', options_list=['--scopes'],
help='A list of the scopes that should be requested while authenticating.')
c.argument('consumer_key', options_list=['--consumer-key'],
help='The OAuth 1.0a consumer key of the Twitter application used for sign-in.')
c.argument('consumer_secret', options_list=['--consumer-secret'],
help='The consumer secret.')
c.argument('provider_name', options_list=['--provider-name'], required=True,
help='The name of the custom OpenID Connect provider.')
c.argument('openid_configuration', options_list=['--openid-configuration'],
help='The endpoint that contains all the configuration endpoints for the provider.')
c.argument('tenant_id', options_list=['--tenant-id'], help='The tenant id of the application.')
c.argument('app_id', options_list=['--app-id'], help='The App ID of the app used for login.')
c.argument('app_secret', options_list=['--app-secret'], help='The app secret.')
c.argument('app_secret_setting_name', options_list=['--app-secret-setting-name', '--secret-setting'], help='The app setting name that contains the app secret.')
c.argument('graph_api_version', options_list=['--graph-api-version'], help='The version of the Facebook api to be used while logging in.')
c.argument('scopes', options_list=['--scopes'], help='A list of the scopes that should be requested while authenticating.')
c.argument('consumer_key', options_list=['--consumer-key'], help='The OAuth 1.0a consumer key of the Twitter application used for sign-in.')
c.argument('consumer_secret', options_list=['--consumer-secret'], help='The consumer secret.')
c.argument('provider_name', options_list=['--provider-name'], required=True, help='The name of the custom OpenID Connect provider.')
c.argument('openid_configuration', options_list=['--openid-configuration'], help='The endpoint that contains all the configuration endpoints for the provider.')
c.argument('set_string', options_list=['--set'], help='Value of a specific field within the configuration settings for the Azure App Service Authentication / Authorization V2 feature.')
c.argument('config_file_path', options_list=['--config-file-path'], help='The path of the config file containing auth settings if they come from a file.')
c.argument('unauthenticated_client_action', options_list=['--unauthenticated-client-action', '--action'], arg_type=get_enum_type(UNAUTHENTICATED_CLIENT_ACTION), help='The action to take when an unauthenticated client attempts to access the app.')
c.argument('redirect_provider', options_list=['--redirect-provider'], help='The default authentication provider to use when multiple providers are configured.')
c.argument('enable_token_store', options_list=['--enable-token-store'], arg_type=get_three_state_flag(return_label=True), help='true to durably store platform-specific security tokens that are obtained during login flows; otherwise, false.')
c.argument('require_https', options_list=['--require-https'], arg_type=get_three_state_flag(return_label=True), help='false if the authentication/authorization responses not having the HTTPS scheme are permissible; otherwise, true.')
c.argument('proxy_convention', options_list=['--proxy-convention'], arg_type=get_enum_type(FORWARD_PROXY_CONVENTION), help='The convention used to determine the url of the request made.')
c.argument('proxy_custom_host_header', options_list=['--proxy-custom-host-header', '--custom-host-header'], help='The name of the header containing the host of the request.')
c.argument('proxy_custom_proto_header', options_list=['--proxy-custom-proto-header', '--custom-proto-header'], help='The name of the header containing the scheme of the request.')
c.argument('excluded_paths', options_list=['--excluded-paths'], help='The list of paths that should be excluded from authentication rules.')
c.argument('enabled', options_list=['--enabled'], arg_type=get_three_state_flag(return_label=True), help='true if the Authentication / Authorization feature is enabled for the current app; otherwise, false.')
2 changes: 1 addition & 1 deletion src/containerapp/azext_containerapp/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ def load_command_table(self, _):
g.custom_command('disable', 'disable_dapr', exception_handler=ex_handler_factory())

with self.command_group('containerapp auth', client_factory=auth_config_client_factory) as g:
g.custom_command('delete', 'delete_auth_config', exception_handler=ex_handler_factory())
g.custom_command('show', 'show_auth_config', exception_handler=ex_handler_factory())
g.custom_command('update', 'update_auth_config', exception_handler=ex_handler_factory())

# g.custom_command('list', 'create_azure_static_webapps_config', exception_handler=ex_handler_factory())
# g.custom_command('disable', 'disable_dapr', exception_handler=ex_handler_factory())
Expand Down
138 changes: 132 additions & 6 deletions src/containerapp/azext_containerapp/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -2960,7 +2960,7 @@ def add_openid_connect_provider_settings(cmd, client, resource_group_name, name,
auth_settings["identityProviders"]["customOpenIdConnectProviders"] = {}
if provider_name in auth_settings["identityProviders"]["customOpenIdConnectProviders"]:
raise CLIError('Usage Error: The following custom OpenID Connect provider has already been '
'configured: ' + provider_name + '. Please use az webapp auth oidc update to '
'configured: ' + provider_name + '. Please use `az containerapp auth oidc update` to '
'update the provider.')

final_client_secret_setting_name = client_secret_setting_name
Expand Down Expand Up @@ -3066,7 +3066,11 @@ def update_openid_connect_provider_settings(cmd, client, resource_group_name, na


def remove_openid_connect_provider_settings(cmd, client, resource_group_name, name, provider_name): # pylint: disable=unused-argument
auth_settings = client.get(resource_group_name=resource_group_name, container_app_name=name, auth_config_name="current").serialize()["properties"]
auth_settings = {}
try:
auth_settings = client.get(resource_group_name=resource_group_name, container_app_name=name, auth_config_name="current").serialize()["properties"]
except:
pass
if "identityProviders" not in auth_settings:
raise CLIError('Usage Error: The following custom OpenID Connect provider '
'has not been configured: ' + provider_name)
Expand All @@ -3090,8 +3094,130 @@ def get_oidc_client_setting_app_setting_name(provider_name):
return provider_name_prefix + "_PROVIDER_AUTHENTICATION_SECRET"


def delete_auth_config(client, name, resource_group_name):
return client.delete(resource_group_name=resource_group_name, container_app_name=name, auth_config_name="current")
def update_auth_config(cmd, client, resource_group_name, name, set_string=None, enabled=None, # pylint: disable=unused-argument
runtime_version=None, config_file_path=None, unauthenticated_client_action=None, # pylint: disable=unused-argument
redirect_provider=None, enable_token_store=None, require_https=None, # pylint: disable=unused-argument
proxy_convention=None, proxy_custom_host_header=None, # pylint: disable=unused-argument
proxy_custom_proto_header=None, excluded_paths=None, slot=None): # pylint: disable=unused-argument
existing_auth = {}
try:
existing_auth = client.get(resource_group_name=resource_group_name, container_app_name=name, auth_config_name="current").serialize()["properties"]
except:
existing_auth["platform"] = {}
existing_auth["platform"]["enabled"] = True
existing_auth["globalValidation"] = {}
existing_auth["login"] = {}

existing_auth = set_field_in_auth_settings(existing_auth, set_string)

if enabled is not None:
if "platform" not in existing_auth:
existing_auth["platform"] = {}
existing_auth["platform"]["enabled"] = enabled

if runtime_version is not None:
if "platform" not in existing_auth:
existing_auth["platform"] = {}
existing_auth["platform"]["runtimeVersion"] = runtime_version

if config_file_path is not None:
if "platform" not in existing_auth:
existing_auth["platform"] = {}
existing_auth["platform"]["configFilePath"] = config_file_path

def show_auth_config(client, name, resource_group_name):
return client.get(resource_group_name=resource_group_name, container_app_name=name, auth_config_name="current")
if unauthenticated_client_action is not None:
if "globalValidation" not in existing_auth:
existing_auth["globalValidation"] = {}
existing_auth["globalValidation"]["unauthenticatedClientAction"] = unauthenticated_client_action

if redirect_provider is not None:
if "globalValidation" not in existing_auth:
existing_auth["globalValidation"] = {}
existing_auth["globalValidation"]["redirectToProvider"] = redirect_provider

if enable_token_store is not None:
if "login" not in existing_auth:
existing_auth["login"] = {}
if "tokenStore" not in existing_auth["login"]:
existing_auth["login"]["tokenStore"] = {}
existing_auth["login"]["tokenStore"]["enabled"] = enable_token_store

if excluded_paths is not None:
if "globalValidation" not in existing_auth:
existing_auth["globalValidation"] = {}
excluded_paths_list_string = excluded_paths[1:-1]
existing_auth["globalValidation"]["excludedPaths"] = excluded_paths_list_string.split(",")

existing_auth = update_http_settings_in_auth_settings(existing_auth, require_https,
proxy_convention, proxy_custom_host_header,
proxy_custom_proto_header)

return client.create_or_update(resource_group_name=resource_group_name, container_app_name=name, auth_config_name="current", auth_config_envelope=existing_auth).serialize()


def show_auth_config(cmd, client, resource_group_name, name): # pylint: disable=unused-argument
auth_settings = {}
try:
auth_settings = client.get(resource_group_name=resource_group_name, container_app_name=name, auth_config_name="current").serialize()["properties"]
except:
pass
return auth_settings


def set_field_in_auth_settings(auth_settings, set_string):
if set_string is not None:
split1 = set_string.split("=")
fieldName = split1[0]
fieldValue = split1[1]
split2 = fieldName.split(".")
auth_settings = set_field_in_auth_settings_recursive(split2, fieldValue, auth_settings)
return auth_settings


def set_field_in_auth_settings_recursive(field_name_split, field_value, auth_settings):
if len(field_name_split) == 1:
if not field_value.startswith('[') or not field_value.endswith(']'):
auth_settings[field_name_split[0]] = field_value
else:
field_value_list_string = field_value[1:-1]
auth_settings[field_name_split[0]] = field_value_list_string.split(",")
return auth_settings

remaining_field_names = field_name_split[1:]
if field_name_split[0] not in auth_settings:
auth_settings[field_name_split[0]] = {}
auth_settings[field_name_split[0]] = set_field_in_auth_settings_recursive(remaining_field_names,
field_value,
auth_settings[field_name_split[0]])
return auth_settings


def update_http_settings_in_auth_settings(auth_settings, require_https, proxy_convention,
proxy_custom_host_header, proxy_custom_proto_header):
if require_https is not None:
if "httpSettings" not in auth_settings:
auth_settings["httpSettings"] = {}
auth_settings["httpSettings"]["requireHttps"] = require_https

if proxy_convention is not None:
if "httpSettings" not in auth_settings:
auth_settings["httpSettings"] = {}
if "forwardProxy" not in auth_settings["httpSettings"]:
auth_settings["httpSettings"]["forwardProxy"] = {}
auth_settings["httpSettings"]["forwardProxy"]["convention"] = proxy_convention

if proxy_custom_host_header is not None:
if "httpSettings" not in auth_settings:
auth_settings["httpSettings"] = {}
if "forwardProxy" not in auth_settings["httpSettings"]:
auth_settings["httpSettings"]["forwardProxy"] = {}
auth_settings["httpSettings"]["forwardProxy"]["customHostHeaderName"] = proxy_custom_host_header

if proxy_custom_proto_header is not None:
if "httpSettings" not in auth_settings:
auth_settings["httpSettings"] = {}
if "forwardProxy" not in auth_settings["httpSettings"]:
auth_settings["httpSettings"]["forwardProxy"] = {}
auth_settings["httpSettings"]["forwardProxy"]["customProtoHeaderName"] = proxy_custom_proto_header

return auth_settings