Index: openacs-4/packages/xooauth/xooauth.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xooauth/xooauth.info,v
diff -u -r1.1.2.8 -r1.1.2.9
--- openacs-4/packages/xooauth/xooauth.info 3 May 2023 12:41:51 -0000 1.1.2.8
+++ openacs-4/packages/xooauth/xooauth.info 8 May 2023 17:37:52 -0000 1.1.2.9
@@ -9,7 +9,7 @@
f
f
-
+
Michael Aram
XOTcl based OAuth implementation and OAuth based REST
interfaces for OpenACS
@@ -28,7 +28,7 @@
0
-
+
Fisheye: Tag 1.1 refers to a dead (removed) revision in file `openacs-4/packages/xooauth/tcl/authorize-procs.tcl'.
Fisheye: No comparison available. Pass `N' to diff?
Index: openacs-4/packages/xooauth/tcl/ms-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xooauth/tcl/ms-procs.tcl,v
diff -u -r1.1.2.16 -r1.1.2.17
--- openacs-4/packages/xooauth/tcl/ms-procs.tcl 7 May 2023 15:22:56 -0000 1.1.2.16
+++ openacs-4/packages/xooauth/tcl/ms-procs.tcl 8 May 2023 17:37:52 -0000 1.1.2.17
@@ -1087,16 +1087,12 @@
# https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens
###########################################################
- nx::Class create Authorize -superclasses ::xo::REST {
+ nx::Class create ::ms::Authorize -superclasses ::xo::Authorize {
+ :property {pretty_name "Azure"}
:property {tenant}
+ :property {version ""}
:property {responder_url /oauth/azure-login-handler}
- :property {after_successful_login_url /}
- :property {login_failure_url /}
-
- :property {create_not_registered_users:switch false}
- :property {create_with_dotlrn_role ""}
- :property {version ""}
:property {scope {openid offline_access profile}}
:property {response_type {code id_token}}
@@ -1116,7 +1112,7 @@
# here:
# https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens
#
- if {${:version} eq ""} {
+ if {${:version} in {"" "v1.0"}} {
set base https://login.microsoftonline.com/common/oauth2/authorize
} else {
#
@@ -1161,27 +1157,28 @@
# Perform logout operation form MS in the background
# (i.e. without a redirect).
#
- ns_http run [ms::azure logout_url]
+ ns_http run [:logout_url]
}
- :method get_user_data {{required_fields {upn family_name given_name}}} {
+ :method get_user_data {
+ -token
+ } {
#
- # Get data from the query variables "id_token", "error"
- # and "token". In case of an error or incomplete data,
- # add this information the result dict. Per default, we
- # require "upn" (user principal name), "family_name" and
- # "given_name". See here for AD claim sets
+ # Get data via the provided token (which comes from the
+ # "id_token"). In case of an error or incomplete data,
+ # add this information the result dict.
+ #
+ # See here for AD claim sets
# https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims
#
- #
# The error codes returned by Azure are defined here:
# https://learn.microsoft.com/en-us/azure/active-directory/develop/reference-error-codes
# Extra errors for OpenACS are prefixed with "oacs-"
#
# @return return a dict containing the extracted fields
set result {}
- lassign [split [ns_queryget id_token] .] jwt_header jwt_claims jwt_signature
+ lassign [split $token .] jwt_header jwt_claims jwt_signature
#ns_log notice "[self]: jwt_header <[:json_to_dict [encoding convertfrom "utf-8" [ns_base64decode -binary -- $jwt_header]]]>"
@@ -1190,147 +1187,25 @@
return $result
}
- set claims [:json_to_dict [encoding convertfrom "utf-8" [ns_base64decode -binary -- $jwt_claims]]]
+ set claims [:json_to_dict \
+ [encoding convertfrom "utf-8" \
+ [ns_base64decode -binary -- $jwt_claims]]]
dict set result claims $claims
- foreach field $required_fields {
- if {![dict exists $claims $field] || [dict get $claims $field] eq ""} {
- set not_enough_data $field
- break
- }
- }
- if {[info exists not_enough_data]} {
- dict set result error oacs-not_enough_data
- }
- return $result
- }
-
- :method lookup_user_id {data} -returns integer {
- set email [dict get $data claims upn]
- set user_id [party::get_by_email -email [string tolower $email]]
- if {$user_id eq ""} {
- #
- # Here one could do some more checks or alternative lookups
- #
- }
- return [expr {$user_id eq "" ? 0 : $user_id}]
- }
-
- :method register_new_user {data} -returns integer {
- #
- # Register the user and return the user_id. In case, the
- # registration of the new user failes, raise an exception.
- #
- # not tested
- #
- db_transaction {
- set user_info(first_names) [dict get $data given_name]
- set user_info(last_name) [dict get $data family_name]
- if {![util_email_unique_p [dict get $data upn]]} {
- error "Email is not unique: [dict get $data upn]"
- }
- set user_info(email) [dict get $data upn]
- array set creation_info [auth::create_local_account \
- -authority_id [auth::authority::local] \
- -username [dict get $data upn] \
- -array user_info]
- if {$creation_info(creation_status) ne "ok"} {
- error "Error when creating user: $creation_info(creation_status) $creation_info(element_messages)"
- }
- set user_id $creation_info(user_id)
- set email [dict get $data upn]
- #db_dml _ "INSERT INTO azure_users VALUES (:user_id)"
- #db_dml _ "INSERT INTO azure_user_mails (user_id, email) VALUES (:user_id, :email)"
-
- if {[apm_package_installed_p dotlrn] && ${:create_with_dotlrn_role} ne ""} {
- #
- # We have DotLRN installed, and we want to create
- # for this register object the new users in the
- # provided role. Note that one can define
- # different instances of this class behaving
- # differently.
- #
- dotlrn::user_add \
- -type ${:create_with_dotlrn_role} \
- -can_browse=1 \
- -id $email \
- -user_id $user_id
-
- acs_privacy::set_user_read_private_data \
- -user_id $user_id \
- -object_id [dotlrn::get_package_id] \
- -value 1
- }
- } on_error {
- ns_log error "Azure Login (Error during user creation): $errmsg ($email)"
- #
- # logout the user from Azure and report an error message.
- #
- # For the time being the error is reported via
- # util_user_message. We could as well define an extra
- # error page and pass the error message and/or some
- # error code to it.
- #
- error "Azure user creation failed: $errmsg"
- }
- return $user_id
- }
-
- :public method perform_login {} {
- #
- # Get the provided claims from the Azure response and
- # perform an OpenACS login, when the user exists.
- #
- # In case the user does not exist, create it optionally (when
- # "create_not_registered_users" is activated for this
- # object).
- #
- # When the user is created, and dotlrn is installed, the
- # new user might be added optionally as a dotlrn user with
- # the role as specified in "create_with_dotlrn_role".
- #
- set data [:get_user_data]
+ set data [:get_required_fields \
+ -claims $claims \
+ -required_fields {
+ {upn email}
+ {family_name last_name}
+ {given_name first_names}
+ }]
if {[dict exists $data error]} {
- ns_log warning "Azure login failed: [dict get $data error]\n$data"
- #util_user_message -message "Azure login failed: [dict get $data error]"
- #ad_returnredirect ${:login_failure_url}
- #ad_script_abort
+ set result [dict merge $data $result]
} else {
- set user_id [:lookup_user_id $data]
- if {$user_id == 0 && ${:create_not_registered_users}} {
- try {
- :register_new_user $data
- } on ok result {
- set user_id $result
- } on error {errorMsg} {
- dict set data error oacs-register_failed
- dict set data error_description $errorMsg
- }
- }
- dict set data user_id $user_id
- if {$user_id != 0} {
- #
- # Still to do:
- # - Sync/check validity of the token vs. the validity
- # of the login cookie.
- # - maybe set an extra cookie to perform token refresh
- # from Azure when the login expires.
- #
- ad_user_login -external_registry [self] $user_id
- #ad_returnredirect ${:after_successful_login_url}
- #ad_script_abort
-
- } else {
- #
- # For the time being, just report data back to the
- # calling script.
- #
- dict set data error "oacs-no_such_user"
- }
+ set result [dict merge $result [dict get $data fields]]
}
- return $data
+ return $result
}
-
}
#
Index: openacs-4/packages/xooauth/www/azure-login-handler.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xooauth/www/azure-login-handler.adp,v
diff -u -r1.1.2.2 -r1.1.2.3
--- openacs-4/packages/xooauth/www/azure-login-handler.adp 4 May 2023 17:09:03 -0000 1.1.2.2
+++ openacs-4/packages/xooauth/www/azure-login-handler.adp 8 May 2023 17:37:52 -0000 1.1.2.3
@@ -1,11 +1,11 @@
@title;literal@
-Azure Interface
+@name@ Authorization
@@ -25,4 +25,4 @@
@cooked_data@
-
\ No newline at end of file
+
Index: openacs-4/packages/xooauth/www/azure-login-handler.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xooauth/www/azure-login-handler.tcl,v
diff -u -r1.1.2.2 -r1.1.2.3
--- openacs-4/packages/xooauth/www/azure-login-handler.tcl 4 May 2023 17:09:03 -0000 1.1.2.2
+++ openacs-4/packages/xooauth/www/azure-login-handler.tcl 8 May 2023 17:37:52 -0000 1.1.2.3
@@ -1,27 +1,47 @@
-set title "Azure Interface"
+ad_page_contract {
+ Azure landing page for OAuth authorization
+
+ @author Gustaf Neumann
+}
+
+set auth_obj ::ms::azure
+
+if {![nsf::is object $auth_obj]} {
+ set error "Authorization object '$auth_obj' was not configured"
+ set name Azure
+ set title "$name Authorization"
+ return
+}
+
set swa_p [acs_user::site_wide_admin_p]
+set name [$auth_obj name]
+set title "$name Authorization"
-set login_url [ms::azure login_url]
-set logout_url [ms::azure logout_url]
+set login_url [$auth_obj login_url]
+set logout_url [$auth_obj logout_url]
+set data ""
if {[ns_queryget id_token] ne ""} {
- set data [ms::azure perform_login]
+ set data [$auth_obj perform_login -token [ns_queryget id_token]]
+}
- if {[dict exists $data user_id] && [dict get $data user_id] > 0} {
- #
- # Login was performed, just redirect to the right place.
- #
- set redirect_url [ns_queryget state \
- [ms::azure cget -after_successful_login_url]]
- if {[string range $redirect_url 0 0] eq "/"} {
- ad_returnredirect $redirect_url
- } else {
- ns_log warning "Azure redirect URL looks suspicious: '$redirect_url'"
- }
- ad_script_abort
+if {![$auth_obj cget -debug]
+ && [dict exists $data user_id]
+ && [dict get $data user_id] > 0
+} {
+ #
+ # Login was performed, just redirect to the right place.
+ #
+ # We can use "state" on Azure as redirect URL (since it has a
+ # nonce)
+ set redirect_url [ns_queryget state \
+ [$auth_obj cget -after_successful_login_url]]
+ if {[string range $redirect_url 0 0] eq "/"} {
+ ad_returnredirect $redirect_url
+ } else {
+ ns_log warning "Azure redirect URL looks suspicious: '$redirect_url'"
}
-} else {
- set data ""
+ ad_script_abort
}
if {1 || $swa_p} {
@@ -35,10 +55,11 @@
if {[dict exists $data claims]} {
set claims [dict get $data claims]
+ dict unset data claims
}
- set form_data [ns_set array [ns_conn form]]
- set cooked_data [join [lmap {k v} $form_data { set _ "$k: $v" }] "\n"]
+ set data [dict merge $data [ns_set array [ns_conn form]]]
+ set cooked_data [join [lmap {k v} $data { set _ "$k: $v" }] "\n"]
}
if {[dict exists $data error]} {
@@ -47,7 +68,7 @@
# error cases.
#
#ad_returnredirect -allow_complete_url [:logout_url]
- ns_http run [ms::azure logout_url]
+ $auth_obj logout
set error [dict get $data error]
}
Fisheye: Tag 1.1 refers to a dead (removed) revision in file `openacs-4/packages/xooauth/www/github-login-handler.adp'.
Fisheye: No comparison available. Pass `N' to diff?
Fisheye: Tag 1.1 refers to a dead (removed) revision in file `openacs-4/packages/xooauth/www/github-login-handler.tcl'.
Fisheye: No comparison available. Pass `N' to diff?