mirror of
https://github.com/abapGit/abapGit.git
synced 2025-05-01 04:08:27 +08:00
Refactor 2FA to not require access token storage
This commit is contained in:
parent
f93bb681b9
commit
0026e74d79
|
@ -102,8 +102,5 @@ AT SELECTION-SCREEN ON EXIT-COMMAND.
|
|||
|
||||
AT SELECTION-SCREEN.
|
||||
IF sy-dynnr = lcl_password_dialog=>dynnr.
|
||||
IF sscrfields-ucomm IS INITIAL.
|
||||
sscrfields-ucomm = 'ENTER'.
|
||||
ENDIF.
|
||||
lcl_password_dialog=>on_screen_event( sscrfields-ucomm ).
|
||||
ENDIF.
|
|
@ -74,37 +74,13 @@ CLASS lcx_2fa_unsupported IMPLEMENTATION.
|
|||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcx_2fa_no_cached_token DEFINITION INHERITING FROM lcx_2fa_error FINAL.
|
||||
PROTECTED SECTION.
|
||||
METHODS:
|
||||
get_default_text REDEFINITION.
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcx_2fa_no_cached_token IMPLEMENTATION.
|
||||
METHOD get_default_text.
|
||||
rv_text = 'Cached two factor access token requested but not available.' ##NO_TEXT.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcx_2fa_cache_deletion_failed DEFINITION INHERITING FROM lcx_2fa_error FINAL.
|
||||
PROTECTED SECTION.
|
||||
METHODS:
|
||||
get_default_text REDEFINITION.
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcx_2fa_cache_deletion_failed IMPLEMENTATION.
|
||||
METHOD get_default_text.
|
||||
rv_text = 'Cache deletion failed.' ##NO_TEXT.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
|
||||
"! Defines a two factor authentication authenticator
|
||||
"! <p>
|
||||
"! Authenticators support one or multiple services and are able to generate access tokens using the
|
||||
"! service's API using the users username, password and two factor authentication token
|
||||
"! (app/sms/tokengenerator). With these access tokens the user can be authenticated to the service's
|
||||
"! implementation of the git http api, just like the "normal" password would. The authenticator can
|
||||
"! also store and retrieve the access token it generated.
|
||||
"! implementation of the git http api, just like the "normal" password would.
|
||||
"! </p>
|
||||
"! <p>
|
||||
"! <em>LCL_2FA_AUTHENTICATOR_REGISTRY</em> can be used to find a suitable implementation for a given
|
||||
|
@ -139,42 +115,18 @@ INTERFACE lif_2fa_authenticator.
|
|||
get_service_id_from_url IMPORTING iv_url TYPE string
|
||||
RETURNING VALUE(rv_id) TYPE string
|
||||
RAISING lcx_2fa_unsupported,
|
||||
"! Check if there is a cached access token (for the current user)
|
||||
"! @parameter iv_url | Repository url
|
||||
"! @parameter rv_available | Token is cached
|
||||
"! @raising lcx_2fa_unsupported | Url is not supported
|
||||
is_cached_access_token_avail IMPORTING iv_url TYPE string
|
||||
RETURNING VALUE(rv_available) TYPE abap_bool
|
||||
RAISING lcx_2fa_unsupported,
|
||||
"! Get a cached access token
|
||||
"! <p>
|
||||
"! Username and password are also parameters to decrypt the token if needed. They must no
|
||||
"! necessarily be provided if the used authenticator does not use encryption.
|
||||
"! </p>
|
||||
"! Check if two factor authentication is required
|
||||
"! @parameter iv_url | Repository url
|
||||
"! @parameter iv_username | Username
|
||||
"! @parameter iv_password | Password
|
||||
"! @parameter rv_token | Access token
|
||||
"! @raising lcx_2fa_no_cached_token | There is no cached token
|
||||
"! @raising lcx_2fa_unsupported | Url is not supported
|
||||
get_cached_access_token IMPORTING iv_url TYPE string
|
||||
iv_username TYPE string OPTIONAL
|
||||
iv_password TYPE string OPTIONAL
|
||||
RETURNING VALUE(rv_token) TYPE string
|
||||
RAISING lcx_2fa_no_cached_token
|
||||
lcx_2fa_unsupported,
|
||||
"! Delete a cached token
|
||||
"! @parameter iv_url | Repository url
|
||||
"! @raising lcx_2fa_cache_deletion_failed | Deletion failed
|
||||
delete_cached_access_token IMPORTING iv_url TYPE string
|
||||
RAISING lcx_2fa_cache_deletion_failed
|
||||
lcx_2fa_unsupported.
|
||||
"! @parameter rv_required | 2FA is required
|
||||
is_2fa_required IMPORTING iv_url TYPE string
|
||||
iv_username TYPE string
|
||||
iv_password TYPE string
|
||||
RETURNING VALUE(rv_required) TYPE abap_bool.
|
||||
ENDINTERFACE.
|
||||
|
||||
"! Default <em>LIF_2FA-AUTHENTICATOR</em> implememtation
|
||||
"! <p>
|
||||
"! This uses the user settings to store cached access tokens and encrypts / decrypts them as needed.
|
||||
"! </p>
|
||||
CLASS lcl_2fa_authenticator_base DEFINITION
|
||||
ABSTRACT
|
||||
CREATE PUBLIC.
|
||||
|
@ -186,9 +138,7 @@ CLASS lcl_2fa_authenticator_base DEFINITION
|
|||
authenticate FOR lif_2fa_authenticator~authenticate,
|
||||
supports_url FOR lif_2fa_authenticator~supports_url,
|
||||
get_service_id_from_url FOR lif_2fa_authenticator~get_service_id_from_url,
|
||||
is_cached_access_token_avail FOR lif_2fa_authenticator~is_cached_access_token_avail,
|
||||
get_cached_access_token FOR lif_2fa_authenticator~get_cached_access_token,
|
||||
delete_cached_token FOR lif_2fa_authenticator~delete_cached_access_token.
|
||||
is_2fa_required FOR lif_2fa_authenticator~is_2fa_required.
|
||||
METHODS:
|
||||
"! @parameter iv_supported_url_regex | Regular expression to check if a repository url is
|
||||
"! supported, used for default implementation of
|
||||
|
@ -196,24 +146,6 @@ CLASS lcl_2fa_authenticator_base DEFINITION
|
|||
constructor IMPORTING iv_supported_url_regex TYPE clike.
|
||||
PROTECTED SECTION.
|
||||
METHODS:
|
||||
"! Subclass implementation of <em>LIF_2FA_AUTHENTICATOR=>AUTHENTICATE</em>
|
||||
"! <p>
|
||||
"! The caller will take care of caching the token.
|
||||
"! </p>
|
||||
"! @parameter iv_url | Repository url
|
||||
"! @parameter iv_username | Username
|
||||
"! @parameter iv_password | Password
|
||||
"! @parameter iv_2fa_token | Two factor token
|
||||
"! @parameter rv_access_token | Generated access token
|
||||
"! @raising lcx_2fa_auth_failed | Authentication failed
|
||||
"! @raising lcx_2fa_token_gen_failed | Token generation failed
|
||||
authenticate_internal ABSTRACT IMPORTING iv_url TYPE string
|
||||
iv_username TYPE string
|
||||
iv_password TYPE string
|
||||
iv_2fa_token TYPE string
|
||||
RETURNING VALUE(rv_access_token) TYPE string
|
||||
RAISING lcx_2fa_auth_failed
|
||||
lcx_2fa_token_gen_failed,
|
||||
"! Helper method to raise class based exception after traditional exception was raised
|
||||
"! <p>
|
||||
"! <em>sy-msg...</em> must be set right before calling!
|
||||
|
@ -233,29 +165,7 @@ CLASS lcl_2fa_authenticator_base IMPLEMENTATION.
|
|||
ENDMETHOD.
|
||||
|
||||
METHOD authenticate.
|
||||
DATA: lv_encrypted_token TYPE string.
|
||||
|
||||
rv_access_token = authenticate_internal( iv_url = iv_url
|
||||
iv_username = iv_username
|
||||
iv_password = iv_password
|
||||
iv_2fa_token = iv_2fa_token ).
|
||||
|
||||
" Store the access token, by default in the user settings
|
||||
|
||||
" 1. Encrypt it
|
||||
* lv_encrypted_token = cl_encryption_helper=>encrypt_symmetric( iv_text = rv_access_token
|
||||
* iv_key = iv_password ).
|
||||
" TODO: Find something like the above for symmetric encryption
|
||||
lv_encrypted_token = rv_access_token.
|
||||
|
||||
" 2. Store it
|
||||
TRY.
|
||||
lcl_app=>user( )->set_2fa_access_token( iv_service_id = get_service_id_from_url( iv_url )
|
||||
iv_username = iv_username
|
||||
iv_token = lv_encrypted_token ).
|
||||
CATCH lcx_exception lcx_2fa_unsupported ##NO_HANDLER.
|
||||
" Not the biggest of deals if caching the token fails
|
||||
ENDTRY.
|
||||
RAISE EXCEPTION TYPE lcx_2fa_auth_failed. " Needs to be overwritten in subclasses
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD supports_url.
|
||||
|
@ -266,56 +176,8 @@ CLASS lcl_2fa_authenticator_base IMPLEMENTATION.
|
|||
rv_id = 'UNKNOWN SERVICE'. " Please overwrite in subclasses
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD is_cached_access_token_avail.
|
||||
DATA: lv_service_id TYPE string.
|
||||
|
||||
lv_service_id = get_service_id_from_url( iv_url ).
|
||||
|
||||
" Default storage location is user settings
|
||||
TRY.
|
||||
rv_available = boolc( lcl_app=>user( )->get_2fa_access_token( lv_service_id )
|
||||
IS NOT INITIAL ).
|
||||
CATCH lcx_exception.
|
||||
rv_available = abap_false.
|
||||
ENDTRY.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD get_cached_access_token.
|
||||
DATA: lv_access_token_encrypted TYPE string,
|
||||
lx_error TYPE REF TO cx_root.
|
||||
|
||||
TRY.
|
||||
lv_access_token_encrypted
|
||||
= lcl_app=>user( )->get_2fa_access_token( get_service_id_from_url( iv_url ) ).
|
||||
CATCH lcx_exception INTO lx_error.
|
||||
RAISE EXCEPTION TYPE lcx_2fa_no_cached_token
|
||||
EXPORTING
|
||||
ix_previous = lx_error
|
||||
iv_error_text = lx_error->get_text( ).
|
||||
ENDTRY.
|
||||
|
||||
IF lv_access_token_encrypted IS INITIAL.
|
||||
RAISE EXCEPTION TYPE lcx_2fa_no_cached_token.
|
||||
ENDIF.
|
||||
|
||||
" TODO: Decryption
|
||||
* rv_token = cl_encryption_helper=>decrypt_symmetric( iv_encrypted = rv_access_token
|
||||
* iv_key = iv_password ).
|
||||
rv_token = lv_access_token_encrypted.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD delete_cached_token.
|
||||
DATA: lx_ex TYPE REF TO cx_root.
|
||||
|
||||
TRY.
|
||||
" Default storage location is user settings
|
||||
lcl_app=>user( )->delete_2fa_config( get_service_id_from_url( iv_url ) ).
|
||||
CATCH lcx_exception INTO lx_ex.
|
||||
RAISE EXCEPTION TYPE lcx_2fa_cache_deletion_failed
|
||||
EXPORTING
|
||||
ix_previous = lx_ex
|
||||
iv_error_text = |Cache deletion failed: { lx_ex->get_text( ) }|.
|
||||
ENDTRY.
|
||||
METHOD is_2fa_required.
|
||||
rv_required = abap_false.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD raise_internal_error_from_sy.
|
||||
|
@ -338,11 +200,15 @@ CLASS lcl_2fa_github_authenticator DEFINITION
|
|||
PUBLIC SECTION.
|
||||
METHODS:
|
||||
constructor,
|
||||
get_service_id_from_url REDEFINITION.
|
||||
get_service_id_from_url REDEFINITION,
|
||||
authenticate REDEFINITION,
|
||||
is_2fa_required REDEFINITION.
|
||||
PROTECTED SECTION.
|
||||
METHODS:
|
||||
authenticate_internal REDEFINITION.
|
||||
PRIVATE SECTION.
|
||||
CONSTANTS:
|
||||
gc_github_api_url TYPE string VALUE `https://api.github.com/`,
|
||||
gc_otp_header_name TYPE string VALUE `X-Github-OTP`,
|
||||
gc_restendpoint_authorizations TYPE string VALUE `/authorizations`.
|
||||
METHODS:
|
||||
set_access_token_request IMPORTING ii_request TYPE REF TO if_http_request
|
||||
iv_repo_name TYPE string,
|
||||
|
@ -357,10 +223,8 @@ CLASS lcl_2fa_github_authenticator IMPLEMENTATION.
|
|||
super->constructor( 'https?:\/\/(www\.)?github.com.*$' ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD authenticate_internal.
|
||||
CONSTANTS: lc_github_api_url TYPE string VALUE `https://api.github.com/`,
|
||||
lc_otp_header_name TYPE string VALUE `X-Github-OTP`,
|
||||
lc_restendpoint_authorizations TYPE string VALUE `/authorizations`.
|
||||
METHOD authenticate.
|
||||
|
||||
DATA: li_http_client TYPE REF TO if_http_client,
|
||||
lv_http_code TYPE i,
|
||||
lv_http_code_description TYPE string,
|
||||
|
@ -372,7 +236,7 @@ CLASS lcl_2fa_github_authenticator IMPLEMENTATION.
|
|||
" 1. Try to login to GitHub API with username, password and 2fa token
|
||||
cl_http_client=>create_by_url(
|
||||
EXPORTING
|
||||
url = lc_github_api_url
|
||||
url = gc_github_api_url
|
||||
IMPORTING
|
||||
client = li_http_client
|
||||
EXCEPTIONS
|
||||
|
@ -386,7 +250,7 @@ CLASS lcl_2fa_github_authenticator IMPLEMENTATION.
|
|||
|
||||
" https://developer.github.com/v3/auth/#working-with-two-factor-authentication
|
||||
li_http_client->propertytype_accept_cookie = if_http_client=>co_enabled.
|
||||
li_http_client->request->set_header_field( name = lc_otp_header_name value = iv_2fa_token ).
|
||||
li_http_client->request->set_header_field( name = gc_otp_header_name value = iv_2fa_token ).
|
||||
li_http_client->authenticate( username = iv_username password = iv_password ).
|
||||
li_http_client->propertytype_logon_popup = if_http_client=>co_disabled.
|
||||
|
||||
|
@ -418,7 +282,7 @@ CLASS lcl_2fa_github_authenticator IMPLEMENTATION.
|
|||
set_access_token_request( ii_request = li_http_client->request
|
||||
iv_repo_name = parse_repo_from_url( iv_url ) ).
|
||||
li_http_client->request->set_header_field( name = if_http_header_fields_sap=>request_uri
|
||||
value = lc_restendpoint_authorizations ).
|
||||
value = gc_restendpoint_authorizations ).
|
||||
li_http_client->request->set_method( if_http_request=>co_request_method_post ).
|
||||
|
||||
li_http_client->send( EXCEPTIONS OTHERS = 1 ).
|
||||
|
@ -501,6 +365,29 @@ CLASS lcl_2fa_github_authenticator IMPLEMENTATION.
|
|||
METHOD get_service_id_from_url.
|
||||
rv_id = 'github'.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD is_2fa_required.
|
||||
DATA: li_client TYPE REF TO if_http_client,
|
||||
lv_header_value TYPE string.
|
||||
|
||||
cl_http_client=>create_by_url(
|
||||
EXPORTING
|
||||
url = gc_github_api_url
|
||||
IMPORTING
|
||||
client = li_client ).
|
||||
|
||||
li_client->propertytype_logon_popup = if_http_client=>co_disabled.
|
||||
|
||||
" Try to authenticate without password, if 2FA is required there will be a specific response
|
||||
" header
|
||||
li_client->authenticate( username = iv_username password = iv_password ).
|
||||
li_client->send( ).
|
||||
li_client->receive( ).
|
||||
|
||||
IF li_client->response->get_header_field( gc_otp_header_name ) CP 'required*'.
|
||||
rv_required = abap_true.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
|
||||
"! Static registry class to find <em>LIF_2FA_AUTHENTICATOR</em> instances
|
||||
|
@ -566,4 +453,4 @@ CLASS lcl_2fa_authenticator_registry IMPLEMENTATION.
|
|||
CATCH lcx_2fa_unsupported ##NO_HANDLER.
|
||||
ENDTRY.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
ENDCLASS.
|
||||
|
|
|
@ -469,84 +469,26 @@ CLASS lcl_http IMPLEMENTATION.
|
|||
|
||||
METHOD acquire_login_details.
|
||||
|
||||
DATA: lv_default_user TYPE string,
|
||||
lv_user TYPE string,
|
||||
lv_pass TYPE string,
|
||||
lv_2fa_token TYPE string,
|
||||
lv_access_token TYPE string,
|
||||
lo_digest TYPE REF TO lcl_http_digest,
|
||||
lv_2fa_available TYPE abap_bool,
|
||||
li_authenticator TYPE REF TO lif_2fa_authenticator,
|
||||
lx_error TYPE REF TO cx_root,
|
||||
lv_popup_mode TYPE lcl_password_dialog=>gty_mode,
|
||||
lv_popup_requested_token_del TYPE abap_bool,
|
||||
lv_service_id TYPE string.
|
||||
DATA: lv_default_user TYPE string,
|
||||
lv_user TYPE string,
|
||||
lv_pass TYPE string,
|
||||
lv_2fa_token TYPE string,
|
||||
lv_access_token TYPE string,
|
||||
lo_digest TYPE REF TO lcl_http_digest,
|
||||
li_authenticator TYPE REF TO lif_2fa_authenticator,
|
||||
lx_error TYPE REF TO cx_root,
|
||||
lv_use_2fa TYPE abap_bool.
|
||||
|
||||
|
||||
lv_default_user = lcl_app=>user( )->get_repo_username( iv_url ).
|
||||
lv_user = lv_default_user.
|
||||
|
||||
|
||||
IF lcl_2fa_authenticator_registry=>is_url_supported( iv_url ) = abap_true.
|
||||
TRY.
|
||||
li_authenticator = lcl_2fa_authenticator_registry=>get_authenticator_for_url( iv_url ).
|
||||
lv_service_id = li_authenticator->get_service_id_from_url( iv_url ).
|
||||
IF li_authenticator->is_cached_access_token_avail( iv_url ) = abap_true.
|
||||
lv_popup_mode = lcl_password_dialog=>gc_modes-unlock_2fa_token.
|
||||
ELSE.
|
||||
lv_popup_mode = lcl_password_dialog=>gc_modes-user_pass_2fa.
|
||||
ENDIF.
|
||||
|
||||
CATCH lcx_2fa_error INTO lx_error.
|
||||
RAISE EXCEPTION TYPE lcx_exception
|
||||
EXPORTING
|
||||
iv_text = lx_error->get_text( )
|
||||
ix_previous = lx_error.
|
||||
ENDTRY.
|
||||
ELSE.
|
||||
lv_popup_mode = lcl_password_dialog=>gc_modes-user_pass.
|
||||
ENDIF.
|
||||
|
||||
lcl_password_dialog=>popup(
|
||||
EXPORTING
|
||||
iv_repo_url = iv_url
|
||||
iv_mode = lv_popup_mode
|
||||
IMPORTING
|
||||
ev_delete_token = lv_popup_requested_token_del
|
||||
CHANGING
|
||||
cv_user = lv_user
|
||||
cv_pass = lv_pass
|
||||
cv_2fa_token = lv_2fa_token ).
|
||||
|
||||
IF lv_popup_requested_token_del = abap_true.
|
||||
TRY.
|
||||
li_authenticator->delete_cached_access_token( lv_service_id ).
|
||||
CATCH lcx_2fa_cache_deletion_failed lcx_2fa_unsupported INTO lx_error.
|
||||
RAISE EXCEPTION TYPE lcx_exception
|
||||
EXPORTING
|
||||
iv_text = lx_error->get_text( )
|
||||
ix_previous = lx_error.
|
||||
ENDTRY.
|
||||
|
||||
" Cancel authentication, no credentials were provided. This will cause the next http request
|
||||
" somewhere up the callstack to result in a 401 error.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
" Unlock cached access token
|
||||
IF lv_popup_mode = lcl_password_dialog=>gc_modes-unlock_2fa_token.
|
||||
TRY.
|
||||
ASSERT li_authenticator IS BOUND.
|
||||
lv_access_token = li_authenticator->get_cached_access_token( iv_url = iv_url
|
||||
iv_username = lv_user
|
||||
iv_password = lv_pass ).
|
||||
CATCH lcx_2fa_no_cached_token lcx_2fa_unsupported INTO lx_error.
|
||||
RAISE EXCEPTION TYPE lcx_exception
|
||||
EXPORTING
|
||||
iv_text = lx_error->get_text( )
|
||||
ix_previous = lx_error.
|
||||
ENDTRY.
|
||||
ENDIF.
|
||||
cv_pass = lv_pass ).
|
||||
|
||||
IF lv_user IS INITIAL.
|
||||
lcx_exception=>raise( 'HTTP 401, unauthorized' ).
|
||||
|
@ -557,25 +499,47 @@ CLASS lcl_http IMPLEMENTATION.
|
|||
iv_username = lv_user ).
|
||||
ENDIF.
|
||||
|
||||
IF lv_access_token IS INITIAL AND lv_2fa_token IS NOT INITIAL.
|
||||
" There is no cached access token but the user provided a two factor token to generate a new
|
||||
" access token
|
||||
TRY.
|
||||
ASSERT li_authenticator IS BOUND.
|
||||
lv_access_token = li_authenticator->authenticate( iv_url = iv_url
|
||||
iv_username = lv_user
|
||||
iv_password = lv_pass
|
||||
iv_2fa_token = lv_2fa_token ).
|
||||
CATCH lcx_2fa_error INTO lx_error.
|
||||
RAISE EXCEPTION TYPE lcx_exception
|
||||
EXPORTING
|
||||
iv_text = lx_error->get_text( )
|
||||
ix_previous = lx_error.
|
||||
ENDTRY.
|
||||
ENDIF.
|
||||
" Is the repository hoster supported for using two factor authentication?
|
||||
TRY.
|
||||
IF lcl_2fa_authenticator_registry=>is_url_supported( iv_url ) = abap_true.
|
||||
li_authenticator = lcl_2fa_authenticator_registry=>get_authenticator_for_url( iv_url ).
|
||||
|
||||
" If there is an access token by now use that as the password instead because two factor
|
||||
" authentication was requested.
|
||||
" Is two factor authentication required for this account?
|
||||
IF li_authenticator->is_2fa_required( iv_url = iv_url
|
||||
iv_username = lv_user
|
||||
iv_password = lv_pass ) = abap_true.
|
||||
|
||||
" Get a 2FA token (app/sms)
|
||||
CALL FUNCTION 'POPUP_GET_STRING'
|
||||
EXPORTING
|
||||
label = 'Two factor auth. token'
|
||||
IMPORTING
|
||||
value = lv_2fa_token
|
||||
okay = lv_use_2fa.
|
||||
IF lv_use_2fa = abap_false.
|
||||
lcx_exception=>raise( 'Authentication cancelled' ).
|
||||
ENDIF.
|
||||
|
||||
" Get a new access token
|
||||
lv_access_token = li_authenticator->authenticate( iv_url = iv_url
|
||||
iv_username = lv_user
|
||||
iv_password = lv_pass
|
||||
iv_2fa_token = lv_2fa_token ).
|
||||
|
||||
" Delete any old ones
|
||||
##TODO.
|
||||
ENDIF.
|
||||
ENDIF.
|
||||
|
||||
CATCH lcx_2fa_error INTO lx_error.
|
||||
RAISE EXCEPTION TYPE lcx_exception
|
||||
EXPORTING
|
||||
iv_text = lx_error->get_text( )
|
||||
ix_previous = lx_error.
|
||||
ENDTRY.
|
||||
|
||||
" If there is an access token use that as the password instead because two factor authentication
|
||||
" is required.
|
||||
IF lv_access_token IS NOT INITIAL.
|
||||
lv_pass = lv_access_token.
|
||||
ENDIF.
|
||||
|
|
|
@ -16,13 +16,6 @@ SELECTION-SCREEN BEGIN OF LINE.
|
|||
SELECTION-SCREEN COMMENT 1(10) s_pass FOR FIELD p_pass.
|
||||
PARAMETERS: p_pass TYPE string LOWER CASE VISIBLE LENGTH 40 ##SEL_WRONG.
|
||||
SELECTION-SCREEN END OF LINE.
|
||||
SELECTION-SCREEN BEGIN OF LINE.
|
||||
PARAMETERS: p_en2fa TYPE abap_bool DEFAULT abap_false USER-COMMAND u1 MODIF ID m1 AS CHECKBOX.
|
||||
SELECTION-SCREEN COMMENT 4(6) s_2fat FOR FIELD p_2fat MODIF ID m1.
|
||||
SELECTION-SCREEN POSITION 12.
|
||||
PARAMETERS: p_2fat TYPE string LOWER CASE VISIBLE LENGTH 40 MODIF ID m1.
|
||||
SELECTION-SCREEN END OF LINE.
|
||||
SELECTION-SCREEN FUNCTION KEY 1.
|
||||
SELECTION-SCREEN END OF SCREEN 1002.
|
||||
|
||||
*-----------------------------------------------------------------------
|
||||
|
@ -31,26 +24,14 @@ SELECTION-SCREEN END OF SCREEN 1002.
|
|||
CLASS lcl_password_dialog DEFINITION FINAL.
|
||||
|
||||
PUBLIC SECTION.
|
||||
TYPES:
|
||||
gty_mode TYPE i.
|
||||
CONSTANTS:
|
||||
dynnr TYPE char4 VALUE '1002',
|
||||
BEGIN OF gc_modes,
|
||||
user_pass TYPE gty_mode VALUE 1,
|
||||
user_pass_2fa TYPE gty_mode VALUE 2,
|
||||
unlock_2fa_token TYPE gty_mode VALUE 3,
|
||||
END OF gc_modes.
|
||||
CONSTANTS dynnr TYPE char4 VALUE '1002'.
|
||||
|
||||
CLASS-METHODS popup
|
||||
IMPORTING
|
||||
iv_repo_url TYPE string
|
||||
iv_mode TYPE gty_mode DEFAULT gc_modes-user_pass
|
||||
EXPORTING
|
||||
ev_delete_token TYPE abap_bool
|
||||
iv_repo_url TYPE string
|
||||
CHANGING
|
||||
cv_user TYPE string
|
||||
cv_pass TYPE string
|
||||
cv_2fa_token TYPE string.
|
||||
cv_user TYPE string
|
||||
cv_pass TYPE string.
|
||||
|
||||
CLASS-METHODS on_screen_init.
|
||||
CLASS-METHODS on_screen_output.
|
||||
|
@ -59,10 +40,7 @@ CLASS lcl_password_dialog DEFINITION FINAL.
|
|||
iv_ucomm TYPE syucomm.
|
||||
|
||||
PRIVATE SECTION.
|
||||
CLASS-DATA:
|
||||
mv_confirm TYPE abap_bool,
|
||||
gv_mode TYPE gty_mode,
|
||||
gv_delete_token TYPE abap_bool.
|
||||
CLASS-DATA mv_confirm TYPE abap_bool.
|
||||
|
||||
ENDCLASS. "lcl_password_dialog DEFINITION
|
||||
|
||||
|
@ -73,24 +51,18 @@ CLASS lcl_password_dialog IMPLEMENTATION.
|
|||
CLEAR p_pass.
|
||||
p_url = iv_repo_url.
|
||||
p_user = cv_user.
|
||||
p_2fat = abap_false.
|
||||
mv_confirm = abap_false.
|
||||
gv_mode = iv_mode.
|
||||
gv_delete_token = abap_false.
|
||||
|
||||
CALL SELECTION-SCREEN dynnr STARTING AT 5 5 ENDING AT 60 8.
|
||||
|
||||
IF mv_confirm = abap_true.
|
||||
cv_user = p_user.
|
||||
cv_pass = p_pass.
|
||||
cv_2fa_token = p_2fat.
|
||||
ELSE.
|
||||
CLEAR: cv_user, cv_pass, cv_2fa_token.
|
||||
CLEAR: cv_user, cv_pass.
|
||||
ENDIF.
|
||||
|
||||
ev_delete_token = gv_delete_token.
|
||||
|
||||
CLEAR: p_url, p_user, p_pass, p_2fat.
|
||||
CLEAR: p_url, p_user, p_pass.
|
||||
|
||||
ENDMETHOD. "popup
|
||||
|
||||
|
@ -99,7 +71,6 @@ CLASS lcl_password_dialog IMPLEMENTATION.
|
|||
s_url = 'Repo URL' ##NO_TEXT.
|
||||
s_user = 'User' ##NO_TEXT.
|
||||
s_pass = 'Password' ##NO_TEXT.
|
||||
s_2fat = '2FA' ##NO_TEXT.
|
||||
ENDMETHOD. "on_screen_init
|
||||
|
||||
METHOD on_screen_output.
|
||||
|
@ -107,51 +78,19 @@ CLASS lcl_password_dialog IMPLEMENTATION.
|
|||
|
||||
ASSERT sy-dynnr = dynnr.
|
||||
|
||||
CLEAR p_2fat.
|
||||
|
||||
LOOP AT SCREEN.
|
||||
CASE screen-name.
|
||||
WHEN 'P_URL'.
|
||||
screen-input = '0'.
|
||||
screen-intensified = '1'.
|
||||
screen-display_3d = '0'.
|
||||
MODIFY SCREEN.
|
||||
|
||||
WHEN 'P_PASS'.
|
||||
screen-invisible = '1'.
|
||||
MODIFY SCREEN.
|
||||
|
||||
WHEN 'P_USER'.
|
||||
IF gv_mode = gc_modes-unlock_2fa_token.
|
||||
screen-input = 0.
|
||||
MODIFY SCREEN.
|
||||
ENDIF.
|
||||
|
||||
WHEN 'P_2FAT'.
|
||||
IF p_en2fa = abap_true.
|
||||
screen-input = '1'.
|
||||
ELSE.
|
||||
screen-input = '0'.
|
||||
p_2fat = 'Two factor authentication token' ##NO_TEXT.
|
||||
ENDIF.
|
||||
MODIFY SCREEN.
|
||||
|
||||
ENDCASE.
|
||||
|
||||
IF screen-group1 = 'M1' AND gv_mode <> gc_modes-user_pass_2fa.
|
||||
screen-invisible = '1'.
|
||||
IF screen-name = 'P_URL'.
|
||||
screen-input = '0'.
|
||||
screen-intensified = '1'.
|
||||
screen-display_3d = '0'.
|
||||
MODIFY SCREEN.
|
||||
ENDIF.
|
||||
IF screen-name = 'P_PASS'.
|
||||
screen-invisible = '1'.
|
||||
MODIFY SCREEN.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
|
||||
IF gv_mode = gc_modes-unlock_2fa_token.
|
||||
s_title = 'Unlock two factor authentication token' ##NO_TEXT.
|
||||
sscrfields-functxt_01 = 'Remove token' ##NO_TEXT.
|
||||
ELSE.
|
||||
s_title = 'Login'.
|
||||
CLEAR sscrfields-functxt_01.
|
||||
ENDIF.
|
||||
|
||||
" Program RSSYSTDB, GUI Status %_CSP
|
||||
PERFORM set_pf_status IN PROGRAM rsdbrunt IF FOUND.
|
||||
APPEND 'NONE' TO lt_ucomm. "Button Check
|
||||
|
@ -163,32 +102,26 @@ CLASS lcl_password_dialog IMPLEMENTATION.
|
|||
TABLES
|
||||
p_exclude = lt_ucomm.
|
||||
|
||||
IF p_user IS NOT INITIAL AND p_pass IS NOT INITIAL AND p_en2fa = abap_true.
|
||||
SET CURSOR FIELD 'P_2FAT'.
|
||||
ELSEIF p_user IS NOT INITIAL.
|
||||
IF p_user IS NOT INITIAL.
|
||||
SET CURSOR FIELD 'P_PASS'.
|
||||
ENDIF.
|
||||
|
||||
ENDMETHOD. "on_screen_output
|
||||
|
||||
METHOD on_screen_event.
|
||||
DATA: lv_answer TYPE c.
|
||||
ASSERT sy-dynnr = dynnr.
|
||||
|
||||
" CRET - F8
|
||||
" OTHERS - simulate Enter press
|
||||
CASE iv_ucomm.
|
||||
WHEN 'FC01'. " Delete two factor code
|
||||
CALL FUNCTION 'POPUP_TO_CONFIRM'
|
||||
EXPORTING
|
||||
text_question = 'Do you really want to remove this two factor access token?'
|
||||
IMPORTING
|
||||
answer = lv_answer.
|
||||
IF lv_answer = '1'.
|
||||
gv_delete_token = abap_true.
|
||||
LEAVE TO SCREEN 0.
|
||||
ENDIF.
|
||||
WHEN 'CRET' OR 'ENTER'.
|
||||
WHEN 'CRET'.
|
||||
mv_confirm = abap_true.
|
||||
WHEN OTHERS. "TODO REFACTOR !!! A CLUTCH !
|
||||
" This will work unless any new specific logic appear
|
||||
" for other commands. The problem is that the password dialog
|
||||
" does not have Enter event (or I don't know how to activate it ;)
|
||||
" so Enter issues previous command from previous screen
|
||||
" But for now this works :) Fortunately Esc produces another flow
|
||||
mv_confirm = abap_true.
|
||||
LEAVE TO SCREEN 0.
|
||||
ENDCASE.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
*&----------------------------
|
||||
*&---------------------------------------------------------------------*
|
||||
*& Include ZABAPGIT_PERSISTENCE
|
||||
*&---------------------------------------------------------------------*
|
||||
|
||||
|
@ -406,21 +406,6 @@ CLASS lcl_persistence_user DEFINITION FINAL CREATE PRIVATE FRIENDS lcl_app.
|
|||
RETURNING VALUE(rv_email) TYPE string
|
||||
RAISING lcx_exception.
|
||||
|
||||
METHODS get_2fa_access_token
|
||||
IMPORTING iv_service_id TYPE string
|
||||
RETURNING VALUE(rv_token) TYPE string
|
||||
RAISING lcx_exception.
|
||||
|
||||
METHODS set_2fa_access_token
|
||||
IMPORTING iv_service_id TYPE string
|
||||
iv_username TYPE string
|
||||
iv_token TYPE string
|
||||
RAISING lcx_exception.
|
||||
|
||||
METHODS delete_2fa_config
|
||||
IMPORTING iv_service_id TYPE string
|
||||
RAISING lcx_exception.
|
||||
|
||||
METHODS toggle_hide_files
|
||||
RETURNING VALUE(rv_hide) TYPE abap_bool
|
||||
RAISING lcx_exception.
|
||||
|
@ -470,13 +455,6 @@ CLASS lcl_persistence_user DEFINITION FINAL CREATE PRIVATE FRIENDS lcl_app.
|
|||
END OF ty_repo_config.
|
||||
TYPES: ty_repo_config_tt TYPE STANDARD TABLE OF ty_repo_config WITH DEFAULT KEY.
|
||||
|
||||
TYPES: BEGIN OF ty_git_hosting_service,
|
||||
service_id TYPE string,
|
||||
username TYPE string,
|
||||
access_token TYPE string,
|
||||
END OF ty_git_hosting_service.
|
||||
TYPES: ty_git_hosting_service_tab TYPE STANDARD TABLE OF ty_git_hosting_service WITH DEFAULT KEY.
|
||||
|
||||
TYPES: BEGIN OF ty_user,
|
||||
username TYPE string,
|
||||
email TYPE string,
|
||||
|
@ -486,7 +464,6 @@ CLASS lcl_persistence_user DEFINITION FINAL CREATE PRIVATE FRIENDS lcl_app.
|
|||
changes_only TYPE abap_bool,
|
||||
diff_unified TYPE abap_bool,
|
||||
favorites TYPE tt_favorites,
|
||||
two_fact_cfg TYPE ty_git_hosting_service_tab,
|
||||
END OF ty_user.
|
||||
|
||||
METHODS constructor
|
||||
|
@ -519,16 +496,6 @@ CLASS lcl_persistence_user DEFINITION FINAL CREATE PRIVATE FRIENDS lcl_app.
|
|||
is_repo_config TYPE ty_repo_config
|
||||
RAISING lcx_exception.
|
||||
|
||||
METHODS read_2fa_config
|
||||
IMPORTING iv_service_id TYPE ty_git_hosting_service-service_id
|
||||
RETURNING VALUE(rs_2fa_config) TYPE ty_git_hosting_service
|
||||
RAISING lcx_exception.
|
||||
|
||||
METHODS update_2fa_config
|
||||
IMPORTING iv_service_id TYPE ty_git_hosting_service-service_id
|
||||
is_2fa_config TYPE ty_git_hosting_service
|
||||
RAISING lcx_exception.
|
||||
|
||||
ENDCLASS. "lcl_persistence_user DEFINITION
|
||||
|
||||
CLASS lcl_persistence_user IMPLEMENTATION.
|
||||
|
@ -672,48 +639,6 @@ CLASS lcl_persistence_user IMPLEMENTATION.
|
|||
|
||||
ENDMETHOD. "update_repo_config
|
||||
|
||||
METHOD read_2fa_config.
|
||||
DATA: lt_2fa_config TYPE ty_git_hosting_service_tab,
|
||||
lv_key TYPE string.
|
||||
|
||||
lv_key = to_lower( iv_service_id ).
|
||||
lt_2fa_config = read( )-two_fact_cfg.
|
||||
READ TABLE lt_2fa_config INTO rs_2fa_config WITH KEY service_id = lv_key.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD update_2fa_config.
|
||||
DATA: ls_user TYPE ty_user,
|
||||
lv_key TYPE string.
|
||||
FIELD-SYMBOLS <ls_2fa_config> TYPE ty_git_hosting_service.
|
||||
|
||||
ls_user = read( ).
|
||||
lv_key = to_lower( iv_service_id ).
|
||||
|
||||
READ TABLE ls_user-two_fact_cfg ASSIGNING <ls_2fa_config> WITH KEY service_id = lv_key.
|
||||
IF sy-subrc IS NOT INITIAL.
|
||||
APPEND INITIAL LINE TO ls_user-two_fact_cfg ASSIGNING <ls_2fa_config>.
|
||||
ENDIF.
|
||||
<ls_2fa_config> = is_2fa_config.
|
||||
<ls_2fa_config>-service_id = lv_key.
|
||||
|
||||
update( ls_user ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD delete_2fa_config.
|
||||
DATA: ls_user TYPE ty_user,
|
||||
lv_key TYPE string.
|
||||
|
||||
ls_user = read( ).
|
||||
lv_key = to_lower( iv_service_id ).
|
||||
|
||||
DELETE ls_user-two_fact_cfg WHERE service_id = lv_key.
|
||||
IF sy-subrc <> 0.
|
||||
lcx_exception=>raise( '2FA config could not be deleted.' ) ##NO_TEXT.
|
||||
ENDIF.
|
||||
|
||||
update( ls_user ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD set_repo_username.
|
||||
|
||||
DATA: ls_repo_config TYPE ty_repo_config.
|
||||
|
@ -746,21 +671,6 @@ CLASS lcl_persistence_user IMPLEMENTATION.
|
|||
|
||||
ENDMETHOD. "get_repo_email
|
||||
|
||||
METHOD get_2fa_access_token.
|
||||
rv_token = read_2fa_config( iv_service_id )-access_token.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD set_2fa_access_token.
|
||||
DATA: ls_config TYPE ty_git_hosting_service.
|
||||
|
||||
ls_config = read_2fa_config( iv_service_id ).
|
||||
ls_config-service_id = iv_service_id.
|
||||
ls_config-username = iv_username.
|
||||
ls_config-access_token = iv_token.
|
||||
|
||||
update_2fa_config( iv_service_id = iv_service_id is_2fa_config = ls_config ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD toggle_hide_files.
|
||||
|
||||
DATA ls_user TYPE ty_user.
|
||||
|
|
Loading…
Reference in New Issue
Block a user