Refactor 2FA to not require access token storage

This commit is contained in:
Fabian Lupa 2017-01-21 18:41:50 +01:00
parent f93bb681b9
commit 0026e74d79
No known key found for this signature in database
GPG Key ID: 727817E619B6CA48
5 changed files with 122 additions and 431 deletions

View File

@ -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.

View File

@ -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=&gtAUTHENTICATE</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.

View File

@ -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.

View File

@ -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.

View File

@ -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.