diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..9aaba4ea
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,787 @@
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+max_line_length = 120
+tab_width = 4
+ij_continuation_indent_size = 8
+ij_formatter_off_tag = @formatter:off
+ij_formatter_on_tag = @formatter:on
+ij_formatter_tags_enabled = true
+ij_smart_tabs = false
+ij_visual_guides =
+ij_wrap_on_typing = false
+
+[*.css]
+ij_css_align_closing_brace_with_properties = false
+ij_css_blank_lines_around_nested_selector = 1
+ij_css_blank_lines_between_blocks = 1
+ij_css_block_comment_add_space = false
+ij_css_brace_placement = end_of_line
+ij_css_enforce_quotes_on_format = false
+ij_css_hex_color_long_format = false
+ij_css_hex_color_lower_case = false
+ij_css_hex_color_short_format = false
+ij_css_hex_color_upper_case = false
+ij_css_keep_blank_lines_in_code = 2
+ij_css_keep_indents_on_empty_lines = false
+ij_css_keep_single_line_blocks = false
+ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
+ij_css_space_after_colon = true
+ij_css_space_before_opening_brace = true
+ij_css_use_double_quotes = true
+ij_css_value_alignment = do_not_align
+
+[*.sass]
+indent_size = 2
+ij_sass_align_closing_brace_with_properties = false
+ij_sass_blank_lines_around_nested_selector = 1
+ij_sass_blank_lines_between_blocks = 1
+ij_sass_brace_placement = 0
+ij_sass_enforce_quotes_on_format = false
+ij_sass_hex_color_long_format = false
+ij_sass_hex_color_lower_case = false
+ij_sass_hex_color_short_format = false
+ij_sass_hex_color_upper_case = false
+ij_sass_keep_blank_lines_in_code = 2
+ij_sass_keep_indents_on_empty_lines = false
+ij_sass_keep_single_line_blocks = false
+ij_sass_line_comment_add_space = false
+ij_sass_line_comment_at_first_column = false
+ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
+ij_sass_space_after_colon = true
+ij_sass_space_before_opening_brace = true
+ij_sass_use_double_quotes = true
+ij_sass_value_alignment = 0
+
+[*.scss]
+indent_size = 2
+ij_scss_align_closing_brace_with_properties = false
+ij_scss_blank_lines_around_nested_selector = 1
+ij_scss_blank_lines_between_blocks = 1
+ij_scss_block_comment_add_space = false
+ij_scss_brace_placement = 0
+ij_scss_enforce_quotes_on_format = false
+ij_scss_hex_color_long_format = false
+ij_scss_hex_color_lower_case = false
+ij_scss_hex_color_short_format = false
+ij_scss_hex_color_upper_case = false
+ij_scss_keep_blank_lines_in_code = 2
+ij_scss_keep_indents_on_empty_lines = false
+ij_scss_keep_single_line_blocks = false
+ij_scss_line_comment_add_space = false
+ij_scss_line_comment_at_first_column = false
+ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
+ij_scss_space_after_colon = true
+ij_scss_space_before_opening_brace = true
+ij_scss_use_double_quotes = true
+ij_scss_value_alignment = 0
+
+[*.vue]
+indent_size = 2
+tab_width = 2
+ij_continuation_indent_size = 4
+ij_vue_indent_children_of_top_level = template
+ij_vue_interpolation_new_line_after_start_delimiter = true
+ij_vue_interpolation_new_line_before_end_delimiter = true
+ij_vue_interpolation_wrap = off
+ij_vue_keep_indents_on_empty_lines = false
+ij_vue_spaces_within_interpolation_expressions = true
+
+[.editorconfig]
+ij_editorconfig_align_group_field_declarations = false
+ij_editorconfig_space_after_colon = false
+ij_editorconfig_space_after_comma = true
+ij_editorconfig_space_before_colon = false
+ij_editorconfig_space_before_comma = false
+ij_editorconfig_spaces_around_assignment_operators = true
+
+[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xlf,*.xml,*.xsd,*.xsl,*.xslt,*.xul,phpunit.xml.dist}]
+ij_xml_align_attributes = true
+ij_xml_align_text = false
+ij_xml_attribute_wrap = normal
+ij_xml_block_comment_add_space = false
+ij_xml_block_comment_at_first_column = true
+ij_xml_keep_blank_lines = 2
+ij_xml_keep_indents_on_empty_lines = false
+ij_xml_keep_line_breaks = true
+ij_xml_keep_line_breaks_in_text = true
+ij_xml_keep_whitespaces = false
+ij_xml_keep_whitespaces_around_cdata = preserve
+ij_xml_keep_whitespaces_inside_cdata = false
+ij_xml_line_comment_at_first_column = true
+ij_xml_space_after_tag_name = false
+ij_xml_space_around_equals_in_attribute = false
+ij_xml_space_inside_empty_tag = false
+ij_xml_text_wrap = normal
+
+[{*.ats,*.cts,*.mts,*.ts}]
+ij_continuation_indent_size = 4
+ij_typescript_align_imports = false
+ij_typescript_align_multiline_array_initializer_expression = false
+ij_typescript_align_multiline_binary_operation = false
+ij_typescript_align_multiline_chained_methods = false
+ij_typescript_align_multiline_extends_list = false
+ij_typescript_align_multiline_for = true
+ij_typescript_align_multiline_parameters = true
+ij_typescript_align_multiline_parameters_in_calls = false
+ij_typescript_align_multiline_ternary_operation = false
+ij_typescript_align_object_properties = 0
+ij_typescript_align_union_types = false
+ij_typescript_align_var_statements = 0
+ij_typescript_array_initializer_new_line_after_left_brace = false
+ij_typescript_array_initializer_right_brace_on_new_line = false
+ij_typescript_array_initializer_wrap = off
+ij_typescript_assignment_wrap = off
+ij_typescript_binary_operation_sign_on_next_line = false
+ij_typescript_binary_operation_wrap = off
+ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
+ij_typescript_blank_lines_after_imports = 1
+ij_typescript_blank_lines_around_class = 1
+ij_typescript_blank_lines_around_field = 0
+ij_typescript_blank_lines_around_field_in_interface = 0
+ij_typescript_blank_lines_around_function = 1
+ij_typescript_blank_lines_around_method = 1
+ij_typescript_blank_lines_around_method_in_interface = 1
+ij_typescript_block_brace_style = end_of_line
+ij_typescript_block_comment_add_space = false
+ij_typescript_block_comment_at_first_column = true
+ij_typescript_call_parameters_new_line_after_left_paren = false
+ij_typescript_call_parameters_right_paren_on_new_line = false
+ij_typescript_call_parameters_wrap = off
+ij_typescript_catch_on_new_line = false
+ij_typescript_chained_call_dot_on_new_line = true
+ij_typescript_class_brace_style = end_of_line
+ij_typescript_comma_on_new_line = false
+ij_typescript_do_while_brace_force = never
+ij_typescript_else_on_new_line = false
+ij_typescript_enforce_trailing_comma = keep
+ij_typescript_enum_constants_wrap = on_every_item
+ij_typescript_extends_keyword_wrap = off
+ij_typescript_extends_list_wrap = off
+ij_typescript_field_prefix = _
+ij_typescript_file_name_style = relaxed
+ij_typescript_finally_on_new_line = false
+ij_typescript_for_brace_force = never
+ij_typescript_for_statement_new_line_after_left_paren = false
+ij_typescript_for_statement_right_paren_on_new_line = false
+ij_typescript_for_statement_wrap = off
+ij_typescript_force_quote_style = false
+ij_typescript_force_semicolon_style = false
+ij_typescript_function_expression_brace_style = end_of_line
+ij_typescript_if_brace_force = never
+ij_typescript_import_merge_members = global
+ij_typescript_import_prefer_absolute_path = global
+ij_typescript_import_sort_members = true
+ij_typescript_import_sort_module_name = false
+ij_typescript_import_use_node_resolution = true
+ij_typescript_imports_wrap = on_every_item
+ij_typescript_indent_case_from_switch = true
+ij_typescript_indent_chained_calls = true
+ij_typescript_indent_package_children = 0
+ij_typescript_jsdoc_include_types = false
+ij_typescript_jsx_attribute_value = braces
+ij_typescript_keep_blank_lines_in_code = 2
+ij_typescript_keep_first_column_comment = true
+ij_typescript_keep_indents_on_empty_lines = false
+ij_typescript_keep_line_breaks = true
+ij_typescript_keep_simple_blocks_in_one_line = false
+ij_typescript_keep_simple_methods_in_one_line = false
+ij_typescript_line_comment_add_space = true
+ij_typescript_line_comment_at_first_column = false
+ij_typescript_method_brace_style = end_of_line
+ij_typescript_method_call_chain_wrap = off
+ij_typescript_method_parameters_new_line_after_left_paren = false
+ij_typescript_method_parameters_right_paren_on_new_line = false
+ij_typescript_method_parameters_wrap = off
+ij_typescript_object_literal_wrap = on_every_item
+ij_typescript_object_types_wrap = on_every_item
+ij_typescript_parentheses_expression_new_line_after_left_paren = false
+ij_typescript_parentheses_expression_right_paren_on_new_line = false
+ij_typescript_place_assignment_sign_on_next_line = false
+ij_typescript_prefer_as_type_cast = false
+ij_typescript_prefer_explicit_types_function_expression_returns = false
+ij_typescript_prefer_explicit_types_function_returns = false
+ij_typescript_prefer_explicit_types_vars_fields = false
+ij_typescript_prefer_parameters_wrap = false
+ij_typescript_property_prefix =
+ij_typescript_reformat_c_style_comments = false
+ij_typescript_space_after_colon = true
+ij_typescript_space_after_comma = true
+ij_typescript_space_after_dots_in_rest_parameter = false
+ij_typescript_space_after_generator_mult = true
+ij_typescript_space_after_property_colon = true
+ij_typescript_space_after_quest = true
+ij_typescript_space_after_type_colon = true
+ij_typescript_space_after_unary_not = false
+ij_typescript_space_before_async_arrow_lparen = true
+ij_typescript_space_before_catch_keyword = true
+ij_typescript_space_before_catch_left_brace = true
+ij_typescript_space_before_catch_parentheses = true
+ij_typescript_space_before_class_lbrace = true
+ij_typescript_space_before_class_left_brace = true
+ij_typescript_space_before_colon = true
+ij_typescript_space_before_comma = false
+ij_typescript_space_before_do_left_brace = true
+ij_typescript_space_before_else_keyword = true
+ij_typescript_space_before_else_left_brace = true
+ij_typescript_space_before_finally_keyword = true
+ij_typescript_space_before_finally_left_brace = true
+ij_typescript_space_before_for_left_brace = true
+ij_typescript_space_before_for_parentheses = true
+ij_typescript_space_before_for_semicolon = false
+ij_typescript_space_before_function_left_parenth = true
+ij_typescript_space_before_generator_mult = false
+ij_typescript_space_before_if_left_brace = true
+ij_typescript_space_before_if_parentheses = true
+ij_typescript_space_before_method_call_parentheses = false
+ij_typescript_space_before_method_left_brace = true
+ij_typescript_space_before_method_parentheses = false
+ij_typescript_space_before_property_colon = false
+ij_typescript_space_before_quest = true
+ij_typescript_space_before_switch_left_brace = true
+ij_typescript_space_before_switch_parentheses = true
+ij_typescript_space_before_try_left_brace = true
+ij_typescript_space_before_type_colon = false
+ij_typescript_space_before_unary_not = false
+ij_typescript_space_before_while_keyword = true
+ij_typescript_space_before_while_left_brace = true
+ij_typescript_space_before_while_parentheses = true
+ij_typescript_spaces_around_additive_operators = true
+ij_typescript_spaces_around_arrow_function_operator = true
+ij_typescript_spaces_around_assignment_operators = true
+ij_typescript_spaces_around_bitwise_operators = true
+ij_typescript_spaces_around_equality_operators = true
+ij_typescript_spaces_around_logical_operators = true
+ij_typescript_spaces_around_multiplicative_operators = true
+ij_typescript_spaces_around_relational_operators = true
+ij_typescript_spaces_around_shift_operators = true
+ij_typescript_spaces_around_unary_operator = false
+ij_typescript_spaces_within_array_initializer_brackets = false
+ij_typescript_spaces_within_brackets = false
+ij_typescript_spaces_within_catch_parentheses = false
+ij_typescript_spaces_within_for_parentheses = false
+ij_typescript_spaces_within_if_parentheses = false
+ij_typescript_spaces_within_imports = false
+ij_typescript_spaces_within_interpolation_expressions = false
+ij_typescript_spaces_within_method_call_parentheses = false
+ij_typescript_spaces_within_method_parentheses = false
+ij_typescript_spaces_within_object_literal_braces = false
+ij_typescript_spaces_within_object_type_braces = true
+ij_typescript_spaces_within_parentheses = false
+ij_typescript_spaces_within_switch_parentheses = false
+ij_typescript_spaces_within_type_assertion = false
+ij_typescript_spaces_within_union_types = true
+ij_typescript_spaces_within_while_parentheses = false
+ij_typescript_special_else_if_treatment = true
+ij_typescript_ternary_operation_signs_on_next_line = false
+ij_typescript_ternary_operation_wrap = off
+ij_typescript_union_types_wrap = on_every_item
+ij_typescript_use_chained_calls_group_indents = false
+ij_typescript_use_double_quotes = true
+ij_typescript_use_explicit_js_extension = auto
+ij_typescript_use_path_mapping = always
+ij_typescript_use_public_modifier = false
+ij_typescript_use_semicolon_after_statement = true
+ij_typescript_var_declaration_wrap = normal
+ij_typescript_while_brace_force = never
+ij_typescript_while_on_new_line = false
+ij_typescript_wrap_comments = false
+
+[{*.bash,*.sh,*.zsh}]
+indent_size = 2
+tab_width = 2
+ij_shell_binary_ops_start_line = false
+ij_shell_keep_column_alignment_padding = false
+ij_shell_minify_program = false
+ij_shell_redirect_followed_by_space = false
+ij_shell_switch_cases_indented = false
+ij_shell_use_unix_line_separator = true
+
+[{*.cjs,*.js}]
+ij_continuation_indent_size = 4
+ij_javascript_align_imports = false
+ij_javascript_align_multiline_array_initializer_expression = false
+ij_javascript_align_multiline_binary_operation = false
+ij_javascript_align_multiline_chained_methods = false
+ij_javascript_align_multiline_extends_list = false
+ij_javascript_align_multiline_for = true
+ij_javascript_align_multiline_parameters = true
+ij_javascript_align_multiline_parameters_in_calls = false
+ij_javascript_align_multiline_ternary_operation = false
+ij_javascript_align_object_properties = 0
+ij_javascript_align_union_types = false
+ij_javascript_align_var_statements = 0
+ij_javascript_array_initializer_new_line_after_left_brace = false
+ij_javascript_array_initializer_right_brace_on_new_line = false
+ij_javascript_array_initializer_wrap = off
+ij_javascript_assignment_wrap = off
+ij_javascript_binary_operation_sign_on_next_line = false
+ij_javascript_binary_operation_wrap = off
+ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
+ij_javascript_blank_lines_after_imports = 1
+ij_javascript_blank_lines_around_class = 1
+ij_javascript_blank_lines_around_field = 0
+ij_javascript_blank_lines_around_function = 1
+ij_javascript_blank_lines_around_method = 1
+ij_javascript_block_brace_style = end_of_line
+ij_javascript_block_comment_add_space = false
+ij_javascript_block_comment_at_first_column = true
+ij_javascript_call_parameters_new_line_after_left_paren = false
+ij_javascript_call_parameters_right_paren_on_new_line = false
+ij_javascript_call_parameters_wrap = off
+ij_javascript_catch_on_new_line = false
+ij_javascript_chained_call_dot_on_new_line = true
+ij_javascript_class_brace_style = end_of_line
+ij_javascript_comma_on_new_line = false
+ij_javascript_do_while_brace_force = never
+ij_javascript_else_on_new_line = false
+ij_javascript_enforce_trailing_comma = keep
+ij_javascript_extends_keyword_wrap = off
+ij_javascript_extends_list_wrap = off
+ij_javascript_field_prefix = _
+ij_javascript_file_name_style = relaxed
+ij_javascript_finally_on_new_line = false
+ij_javascript_for_brace_force = never
+ij_javascript_for_statement_new_line_after_left_paren = false
+ij_javascript_for_statement_right_paren_on_new_line = false
+ij_javascript_for_statement_wrap = off
+ij_javascript_force_quote_style = false
+ij_javascript_force_semicolon_style = false
+ij_javascript_function_expression_brace_style = end_of_line
+ij_javascript_if_brace_force = never
+ij_javascript_import_merge_members = global
+ij_javascript_import_prefer_absolute_path = global
+ij_javascript_import_sort_members = true
+ij_javascript_import_sort_module_name = false
+ij_javascript_import_use_node_resolution = true
+ij_javascript_imports_wrap = on_every_item
+ij_javascript_indent_case_from_switch = true
+ij_javascript_indent_chained_calls = true
+ij_javascript_indent_package_children = 0
+ij_javascript_jsx_attribute_value = braces
+ij_javascript_keep_blank_lines_in_code = 2
+ij_javascript_keep_first_column_comment = true
+ij_javascript_keep_indents_on_empty_lines = false
+ij_javascript_keep_line_breaks = true
+ij_javascript_keep_simple_blocks_in_one_line = false
+ij_javascript_keep_simple_methods_in_one_line = false
+ij_javascript_line_comment_add_space = true
+ij_javascript_line_comment_at_first_column = false
+ij_javascript_method_brace_style = end_of_line
+ij_javascript_method_call_chain_wrap = off
+ij_javascript_method_parameters_new_line_after_left_paren = false
+ij_javascript_method_parameters_right_paren_on_new_line = false
+ij_javascript_method_parameters_wrap = off
+ij_javascript_object_literal_wrap = on_every_item
+ij_javascript_object_types_wrap = on_every_item
+ij_javascript_parentheses_expression_new_line_after_left_paren = false
+ij_javascript_parentheses_expression_right_paren_on_new_line = false
+ij_javascript_place_assignment_sign_on_next_line = false
+ij_javascript_prefer_as_type_cast = false
+ij_javascript_prefer_explicit_types_function_expression_returns = false
+ij_javascript_prefer_explicit_types_function_returns = false
+ij_javascript_prefer_explicit_types_vars_fields = false
+ij_javascript_prefer_parameters_wrap = false
+ij_javascript_property_prefix =
+ij_javascript_reformat_c_style_comments = false
+ij_javascript_space_after_colon = true
+ij_javascript_space_after_comma = true
+ij_javascript_space_after_dots_in_rest_parameter = false
+ij_javascript_space_after_generator_mult = true
+ij_javascript_space_after_property_colon = true
+ij_javascript_space_after_quest = true
+ij_javascript_space_after_type_colon = true
+ij_javascript_space_after_unary_not = false
+ij_javascript_space_before_async_arrow_lparen = true
+ij_javascript_space_before_catch_keyword = true
+ij_javascript_space_before_catch_left_brace = true
+ij_javascript_space_before_catch_parentheses = true
+ij_javascript_space_before_class_lbrace = true
+ij_javascript_space_before_class_left_brace = true
+ij_javascript_space_before_colon = true
+ij_javascript_space_before_comma = false
+ij_javascript_space_before_do_left_brace = true
+ij_javascript_space_before_else_keyword = true
+ij_javascript_space_before_else_left_brace = true
+ij_javascript_space_before_finally_keyword = true
+ij_javascript_space_before_finally_left_brace = true
+ij_javascript_space_before_for_left_brace = true
+ij_javascript_space_before_for_parentheses = true
+ij_javascript_space_before_for_semicolon = false
+ij_javascript_space_before_function_left_parenth = true
+ij_javascript_space_before_generator_mult = false
+ij_javascript_space_before_if_left_brace = true
+ij_javascript_space_before_if_parentheses = true
+ij_javascript_space_before_method_call_parentheses = false
+ij_javascript_space_before_method_left_brace = true
+ij_javascript_space_before_method_parentheses = false
+ij_javascript_space_before_property_colon = false
+ij_javascript_space_before_quest = true
+ij_javascript_space_before_switch_left_brace = true
+ij_javascript_space_before_switch_parentheses = true
+ij_javascript_space_before_try_left_brace = true
+ij_javascript_space_before_type_colon = false
+ij_javascript_space_before_unary_not = false
+ij_javascript_space_before_while_keyword = true
+ij_javascript_space_before_while_left_brace = true
+ij_javascript_space_before_while_parentheses = true
+ij_javascript_spaces_around_additive_operators = true
+ij_javascript_spaces_around_arrow_function_operator = true
+ij_javascript_spaces_around_assignment_operators = true
+ij_javascript_spaces_around_bitwise_operators = true
+ij_javascript_spaces_around_equality_operators = true
+ij_javascript_spaces_around_logical_operators = true
+ij_javascript_spaces_around_multiplicative_operators = true
+ij_javascript_spaces_around_relational_operators = true
+ij_javascript_spaces_around_shift_operators = true
+ij_javascript_spaces_around_unary_operator = false
+ij_javascript_spaces_within_array_initializer_brackets = false
+ij_javascript_spaces_within_brackets = false
+ij_javascript_spaces_within_catch_parentheses = false
+ij_javascript_spaces_within_for_parentheses = false
+ij_javascript_spaces_within_if_parentheses = false
+ij_javascript_spaces_within_imports = false
+ij_javascript_spaces_within_interpolation_expressions = false
+ij_javascript_spaces_within_method_call_parentheses = false
+ij_javascript_spaces_within_method_parentheses = false
+ij_javascript_spaces_within_object_literal_braces = false
+ij_javascript_spaces_within_object_type_braces = true
+ij_javascript_spaces_within_parentheses = false
+ij_javascript_spaces_within_switch_parentheses = false
+ij_javascript_spaces_within_type_assertion = false
+ij_javascript_spaces_within_union_types = true
+ij_javascript_spaces_within_while_parentheses = false
+ij_javascript_special_else_if_treatment = true
+ij_javascript_ternary_operation_signs_on_next_line = false
+ij_javascript_ternary_operation_wrap = off
+ij_javascript_union_types_wrap = on_every_item
+ij_javascript_use_chained_calls_group_indents = false
+ij_javascript_use_double_quotes = true
+ij_javascript_use_explicit_js_extension = auto
+ij_javascript_use_path_mapping = always
+ij_javascript_use_public_modifier = false
+ij_javascript_use_semicolon_after_statement = true
+ij_javascript_var_declaration_wrap = normal
+ij_javascript_while_brace_force = never
+ij_javascript_while_on_new_line = false
+ij_javascript_wrap_comments = false
+
+[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}]
+ij_continuation_indent_size = 4
+ij_php_align_assignments = false
+ij_php_align_class_constants = true
+ij_php_align_enum_cases = true
+ij_php_align_group_field_declarations = true
+ij_php_align_inline_comments = false
+ij_php_align_key_value_pairs = false
+ij_php_align_match_arm_bodies = false
+ij_php_align_multiline_array_initializer_expression = false
+ij_php_align_multiline_binary_operation = true
+ij_php_align_multiline_chained_methods = true
+ij_php_align_multiline_extends_list = true
+ij_php_align_multiline_for = true
+ij_php_align_multiline_parameters = true
+ij_php_align_multiline_parameters_in_calls = true
+ij_php_align_multiline_ternary_operation = false
+ij_php_align_named_arguments = false
+ij_php_align_phpdoc_comments = false
+ij_php_align_phpdoc_param_names = false
+ij_php_anonymous_brace_style = end_of_line
+ij_php_api_weight = 28
+ij_php_array_initializer_new_line_after_left_brace = true
+ij_php_array_initializer_right_brace_on_new_line = true
+ij_php_array_initializer_wrap = on_every_item
+ij_php_assignment_wrap = off
+ij_php_attributes_wrap = off
+ij_php_author_weight = 28
+ij_php_binary_operation_sign_on_next_line = false
+ij_php_binary_operation_wrap = off
+ij_php_blank_lines_after_class_header = 0
+ij_php_blank_lines_after_function = 1
+ij_php_blank_lines_after_imports = 1
+ij_php_blank_lines_after_opening_tag = 1
+ij_php_blank_lines_after_package = 1
+ij_php_blank_lines_around_class = 1
+ij_php_blank_lines_around_constants = 0
+ij_php_blank_lines_around_enum_cases = 0
+ij_php_blank_lines_around_field = 0
+ij_php_blank_lines_around_method = 1
+ij_php_blank_lines_before_class_end = 0
+ij_php_blank_lines_before_imports = 1
+ij_php_blank_lines_before_method_body = 0
+ij_php_blank_lines_before_package = 1
+ij_php_blank_lines_before_return_statement = 0
+ij_php_blank_lines_between_imports = 1
+ij_php_block_brace_style = end_of_line
+ij_php_call_parameters_new_line_after_left_paren = true
+ij_php_call_parameters_right_paren_on_new_line = true
+ij_php_call_parameters_wrap = on_every_item
+ij_php_catch_on_new_line = false
+ij_php_category_weight = 28
+ij_php_class_brace_style = next_line
+ij_php_comma_after_last_argument = false
+ij_php_comma_after_last_array_element = false
+ij_php_comma_after_last_closure_use_var = false
+ij_php_comma_after_last_match_arm = false
+ij_php_comma_after_last_parameter = false
+ij_php_concat_spaces = true
+ij_php_copyright_weight = 28
+ij_php_deprecated_weight = 28
+ij_php_do_while_brace_force = always
+ij_php_else_if_style = combine
+ij_php_else_on_new_line = false
+ij_php_example_weight = 28
+ij_php_extends_keyword_wrap = off
+ij_php_extends_list_wrap = on_every_item
+ij_php_fields_default_visibility = private
+ij_php_filesource_weight = 28
+ij_php_finally_on_new_line = false
+ij_php_for_brace_force = always
+ij_php_for_statement_new_line_after_left_paren = true
+ij_php_for_statement_right_paren_on_new_line = true
+ij_php_for_statement_wrap = off
+ij_php_force_empty_methods_in_one_line = false
+ij_php_force_short_declaration_array_style = false
+ij_php_getters_setters_naming_style = camel_case
+ij_php_getters_setters_order_style = getters_first
+ij_php_global_weight = 28
+ij_php_group_use_wrap = on_every_item
+ij_php_if_brace_force = always
+ij_php_if_lparen_on_next_line = false
+ij_php_if_rparen_on_next_line = false
+ij_php_ignore_weight = 28
+ij_php_import_sorting = alphabetic
+ij_php_indent_break_from_case = true
+ij_php_indent_case_from_switch = true
+ij_php_indent_code_in_php_tags = false
+ij_php_internal_weight = 28
+ij_php_keep_blank_lines_after_lbrace = 0
+ij_php_keep_blank_lines_before_right_brace = 0
+ij_php_keep_blank_lines_in_code = 2
+ij_php_keep_blank_lines_in_declarations = 2
+ij_php_keep_control_statement_in_one_line = true
+ij_php_keep_first_column_comment = true
+ij_php_keep_indents_on_empty_lines = false
+ij_php_keep_line_breaks = true
+ij_php_keep_rparen_and_lbrace_on_one_line = true
+ij_php_keep_simple_classes_in_one_line = false
+ij_php_keep_simple_methods_in_one_line = false
+ij_php_lambda_brace_style = end_of_line
+ij_php_license_weight = 28
+ij_php_line_comment_add_space = false
+ij_php_line_comment_at_first_column = true
+ij_php_link_weight = 28
+ij_php_lower_case_boolean_const = true
+ij_php_lower_case_keywords = true
+ij_php_lower_case_null_const = true
+ij_php_method_brace_style = next_line
+ij_php_method_call_chain_wrap = on_every_item
+ij_php_method_parameters_new_line_after_left_paren = true
+ij_php_method_parameters_right_paren_on_new_line = true
+ij_php_method_parameters_wrap = on_every_item
+ij_php_method_weight = 28
+ij_php_modifier_list_wrap = false
+ij_php_multiline_chained_calls_semicolon_on_new_line = false
+ij_php_namespace_brace_style = 1
+ij_php_new_line_after_php_opening_tag = true
+ij_php_null_type_position = in_the_end
+ij_php_package_weight = 28
+ij_php_param_weight = 0
+ij_php_parameters_attributes_wrap = off
+ij_php_parentheses_expression_new_line_after_left_paren = false
+ij_php_parentheses_expression_right_paren_on_new_line = false
+ij_php_phpdoc_blank_line_before_tags = false
+ij_php_phpdoc_blank_lines_around_parameters = false
+ij_php_phpdoc_keep_blank_lines = true
+ij_php_phpdoc_param_spaces_between_name_and_description = 1
+ij_php_phpdoc_param_spaces_between_tag_and_type = 1
+ij_php_phpdoc_param_spaces_between_type_and_name = 1
+ij_php_phpdoc_use_fqcn = false
+ij_php_phpdoc_wrap_long_lines = false
+ij_php_place_assignment_sign_on_next_line = false
+ij_php_place_parens_for_constructor = 0
+ij_php_property_read_weight = 28
+ij_php_property_weight = 28
+ij_php_property_write_weight = 28
+ij_php_return_type_on_new_line = false
+ij_php_return_weight = 1
+ij_php_see_weight = 28
+ij_php_since_weight = 28
+ij_php_sort_phpdoc_elements = true
+ij_php_space_after_colon = true
+ij_php_space_after_colon_in_enum_backed_type = true
+ij_php_space_after_colon_in_named_argument = true
+ij_php_space_after_colon_in_return_type = true
+ij_php_space_after_comma = true
+ij_php_space_after_for_semicolon = true
+ij_php_space_after_quest = true
+ij_php_space_after_type_cast = false
+ij_php_space_after_unary_not = false
+ij_php_space_before_array_initializer_left_brace = false
+ij_php_space_before_catch_keyword = true
+ij_php_space_before_catch_left_brace = true
+ij_php_space_before_catch_parentheses = true
+ij_php_space_before_class_left_brace = true
+ij_php_space_before_closure_left_parenthesis = true
+ij_php_space_before_colon = true
+ij_php_space_before_colon_in_enum_backed_type = false
+ij_php_space_before_colon_in_named_argument = false
+ij_php_space_before_colon_in_return_type = false
+ij_php_space_before_comma = false
+ij_php_space_before_do_left_brace = true
+ij_php_space_before_else_keyword = true
+ij_php_space_before_else_left_brace = true
+ij_php_space_before_finally_keyword = true
+ij_php_space_before_finally_left_brace = true
+ij_php_space_before_for_left_brace = true
+ij_php_space_before_for_parentheses = true
+ij_php_space_before_for_semicolon = false
+ij_php_space_before_if_left_brace = true
+ij_php_space_before_if_parentheses = true
+ij_php_space_before_method_call_parentheses = false
+ij_php_space_before_method_left_brace = true
+ij_php_space_before_method_parentheses = false
+ij_php_space_before_quest = true
+ij_php_space_before_short_closure_left_parenthesis = false
+ij_php_space_before_switch_left_brace = true
+ij_php_space_before_switch_parentheses = true
+ij_php_space_before_try_left_brace = true
+ij_php_space_before_unary_not = false
+ij_php_space_before_while_keyword = true
+ij_php_space_before_while_left_brace = true
+ij_php_space_before_while_parentheses = true
+ij_php_space_between_ternary_quest_and_colon = false
+ij_php_spaces_around_additive_operators = true
+ij_php_spaces_around_arrow = false
+ij_php_spaces_around_assignment_in_declare = false
+ij_php_spaces_around_assignment_operators = true
+ij_php_spaces_around_bitwise_operators = true
+ij_php_spaces_around_equality_operators = true
+ij_php_spaces_around_logical_operators = true
+ij_php_spaces_around_multiplicative_operators = true
+ij_php_spaces_around_null_coalesce_operator = true
+ij_php_spaces_around_pipe_in_union_type = false
+ij_php_spaces_around_relational_operators = true
+ij_php_spaces_around_shift_operators = true
+ij_php_spaces_around_unary_operator = false
+ij_php_spaces_around_var_within_brackets = false
+ij_php_spaces_within_array_initializer_braces = false
+ij_php_spaces_within_brackets = false
+ij_php_spaces_within_catch_parentheses = false
+ij_php_spaces_within_for_parentheses = false
+ij_php_spaces_within_if_parentheses = false
+ij_php_spaces_within_method_call_parentheses = false
+ij_php_spaces_within_method_parentheses = false
+ij_php_spaces_within_parentheses = false
+ij_php_spaces_within_short_echo_tags = true
+ij_php_spaces_within_switch_parentheses = false
+ij_php_spaces_within_while_parentheses = false
+ij_php_special_else_if_treatment = false
+ij_php_subpackage_weight = 28
+ij_php_ternary_operation_signs_on_next_line = false
+ij_php_ternary_operation_wrap = off
+ij_php_throws_weight = 2
+ij_php_todo_weight = 28
+ij_php_treat_multiline_arrays_and_lambdas_multiline = false
+ij_php_unknown_tag_weight = 28
+ij_php_upper_case_boolean_const = false
+ij_php_upper_case_null_const = false
+ij_php_uses_weight = 28
+ij_php_var_weight = 28
+ij_php_variable_naming_style = mixed
+ij_php_version_weight = 28
+ij_php_while_brace_force = always
+ij_php_while_on_new_line = false
+
+[{*.har,*.jsb2,*.jsb3,*.json,*.lang,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,composer.lock,jest.config}]
+indent_size = 2
+ij_json_array_wrapping = split_into_lines
+ij_json_keep_blank_lines_in_code = 0
+ij_json_keep_indents_on_empty_lines = false
+ij_json_keep_line_breaks = true
+ij_json_keep_trailing_comma = false
+ij_json_object_wrapping = split_into_lines
+ij_json_property_alignment = do_not_align
+ij_json_space_after_colon = true
+ij_json_space_after_comma = true
+ij_json_space_before_colon = false
+ij_json_space_before_comma = false
+ij_json_spaces_within_braces = false
+ij_json_spaces_within_brackets = false
+ij_json_wrap_long_lines = false
+
+[{*.htm,*.html,*.sht,*.shtm,*.shtml}]
+ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
+ij_html_align_attributes = true
+ij_html_align_text = false
+ij_html_attribute_wrap = normal
+ij_html_block_comment_add_space = false
+ij_html_block_comment_at_first_column = true
+ij_html_do_not_align_children_of_min_lines = 0
+ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p
+ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot
+ij_html_enforce_quotes = false
+ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var
+ij_html_keep_blank_lines = 2
+ij_html_keep_indents_on_empty_lines = false
+ij_html_keep_line_breaks = true
+ij_html_keep_line_breaks_in_text = true
+ij_html_keep_whitespaces = false
+ij_html_keep_whitespaces_inside = span,pre,textarea
+ij_html_line_comment_at_first_column = true
+ij_html_new_line_after_last_attribute = never
+ij_html_new_line_before_first_attribute = never
+ij_html_quote_style = double
+ij_html_remove_new_line_before_tags = br
+ij_html_space_after_tag_name = false
+ij_html_space_around_equality_in_attribute = false
+ij_html_space_inside_empty_tag = false
+ij_html_text_wrap = normal
+
+[{*.http,*.rest}]
+indent_size = 0
+ij_continuation_indent_size = 4
+ij_http request_call_parameters_wrap = normal
+ij_http request_method_parameters_wrap = split_into_lines
+ij_http request_space_before_comma = true
+ij_http request_spaces_around_assignment_operators = true
+
+[{*.markdown,*.md}]
+ij_markdown_force_one_space_after_blockquote_symbol = true
+ij_markdown_force_one_space_after_header_symbol = true
+ij_markdown_force_one_space_after_list_bullet = true
+ij_markdown_force_one_space_between_words = true
+ij_markdown_format_tables = true
+ij_markdown_insert_quote_arrows_on_wrap = true
+ij_markdown_keep_indents_on_empty_lines = false
+ij_markdown_keep_line_breaks_inside_text_blocks = true
+ij_markdown_max_lines_around_block_elements = 1
+ij_markdown_max_lines_around_header = 1
+ij_markdown_max_lines_between_paragraphs = 1
+ij_markdown_min_lines_around_block_elements = 1
+ij_markdown_min_lines_around_header = 1
+ij_markdown_min_lines_between_paragraphs = 1
+ij_markdown_wrap_text_if_long = true
+ij_markdown_wrap_text_inside_blockquotes = true
+
+[{*.twig,*.volt}]
+ij_twig_keep_indents_on_empty_lines = false
+ij_twig_spaces_inside_comments_delimiters = true
+ij_twig_spaces_inside_delimiters = true
+ij_twig_spaces_inside_variable_delimiters = true
+
+[{*.yaml,*.yml}]
+indent_size = 2
+ij_yaml_align_values_properties = do_not_align
+ij_yaml_autoinsert_sequence_marker = true
+ij_yaml_block_mapping_on_new_line = false
+ij_yaml_indent_sequence_value = true
+ij_yaml_keep_indents_on_empty_lines = false
+ij_yaml_keep_line_breaks = true
+ij_yaml_sequence_on_new_line = false
+ij_yaml_space_before_colon = false
+ij_yaml_spaces_within_braces = true
+ij_yaml_spaces_within_brackets = true
diff --git a/app/modules/web/Controllers/ConfigLdap/CheckController.php b/app/modules/web/Controllers/ConfigLdap/CheckController.php
index 60223ede..05e512bb 100644
--- a/app/modules/web/Controllers/ConfigLdap/CheckController.php
+++ b/app/modules/web/Controllers/ConfigLdap/CheckController.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -26,11 +26,14 @@ namespace SP\Modules\Web\Controllers\ConfigLdap;
use Exception;
+use JsonException;
use SP\Core\Acl\ActionsInterface;
use SP\Core\Acl\UnauthorizedPageException;
use SP\Core\Application;
use SP\Core\Events\Event;
use SP\Core\Exceptions\CheckException;
+use SP\Core\Exceptions\SessionTimeout;
+use SP\Core\Exceptions\SPException;
use SP\Domain\Auth\Ports\LdapCheckServiceInterface;
use SP\Http\JsonResponse;
use SP\Modules\Web\Controllers\SimpleControllerBase;
@@ -38,31 +41,31 @@ use SP\Modules\Web\Controllers\Traits\JsonTrait;
use SP\Mvc\Controller\SimpleControllerHelper;
use SP\Mvc\View\TemplateInterface;
+use function SP\__;
+use function SP\__u;
+use function SP\processException;
+
/**
* Class CheckController
*/
final class CheckController extends SimpleControllerBase
{
- use JsonTrait, ConfigLdapTrait;
-
- private LdapCheckServiceInterface $ldapCheckService;
- private TemplateInterface $template;
+ use ConfigLdapTrait;
+ use JsonTrait;
public function __construct(
- Application $application,
- SimpleControllerHelper $simpleControllerHelper,
- LdapCheckServiceInterface $ldapCheckService,
- TemplateInterface $template
+ Application $application,
+ SimpleControllerHelper $simpleControllerHelper,
+ private readonly LdapCheckServiceInterface $ldapCheckService,
+ private readonly TemplateInterface $template
) {
parent::__construct($application, $simpleControllerHelper);
-
- $this->ldapCheckService = $ldapCheckService;
- $this->template = $template;
}
/**
* @return bool
- * @throws \JsonException
+ * @throws JsonException
+ * @throws SPException
*/
public function checkAction(): bool
{
@@ -80,9 +83,7 @@ final class CheckController extends SimpleControllerBase
);
}
- $this->ldapCheckService->checkConnection($ldapParams);
-
- $data = $this->ldapCheckService->getObjects(false);
+ $data = $this->ldapCheckService->getObjects(false, $ldapParams);
$this->template->addTemplate('results', 'itemshow');
$this->template->assign('header', __('Results'));
@@ -104,8 +105,8 @@ final class CheckController extends SimpleControllerBase
/**
* @return void
- * @throws \JsonException
- * @throws \SP\Core\Exceptions\SessionTimeout
+ * @throws SessionTimeout
+ * @throws SPException
*/
protected function initialize(): void
{
diff --git a/app/modules/web/Controllers/ConfigLdap/CheckImportController.php b/app/modules/web/Controllers/ConfigLdap/CheckImportController.php
index 1d8dd947..114759a0 100644
--- a/app/modules/web/Controllers/ConfigLdap/CheckImportController.php
+++ b/app/modules/web/Controllers/ConfigLdap/CheckImportController.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -26,51 +26,45 @@ namespace SP\Modules\Web\Controllers\ConfigLdap;
use Exception;
-use Klein\Klein;
-use SP\Core\Acl\Acl;
use SP\Core\Acl\ActionsInterface;
use SP\Core\Acl\UnauthorizedPageException;
use SP\Core\Application;
use SP\Core\Events\Event;
use SP\Core\Exceptions\CheckException;
-use SP\Core\PhpExtensionChecker;
-use SP\Core\UI\ThemeInterface;
+use SP\Core\Exceptions\SessionTimeout;
+use SP\Core\Exceptions\SPException;
use SP\Domain\Auth\Ports\LdapCheckServiceInterface;
use SP\Http\JsonResponse;
-use SP\Http\RequestInterface;
use SP\Modules\Web\Controllers\SimpleControllerBase;
use SP\Modules\Web\Controllers\Traits\JsonTrait;
+use SP\Mvc\Controller\SimpleControllerHelper;
use SP\Mvc\View\TemplateInterface;
+use function SP\__;
+use function SP\__u;
+use function SP\processException;
+
/**
* Class CheckImportController
*/
final class CheckImportController extends SimpleControllerBase
{
- use JsonTrait, ConfigLdapTrait;
-
- private LdapCheckServiceInterface $ldapCheckService;
- private TemplateInterface $template;
+ use JsonTrait;
+ use ConfigLdapTrait;
public function __construct(
- Application $application,
- ThemeInterface $theme,
- Klein $router,
- Acl $acl,
- RequestInterface $request,
- PhpExtensionChecker $extensionChecker,
- LdapCheckServiceInterface $ldapCheckService,
- TemplateInterface $template
+ Application $application,
+ SimpleControllerHelper $simpleControllerHelper,
+ private readonly LdapCheckServiceInterface $ldapCheckService,
+ private readonly TemplateInterface $template
) {
- parent::__construct($application, $theme);
-
- $this->ldapCheckService = $ldapCheckService;
- $this->template = $template;
+ parent::__construct($application, $simpleControllerHelper);
}
/**
* @return bool
* @throws \JsonException
+ * @throws SPException
*/
public function checkImportAction(): bool
{
@@ -85,14 +79,15 @@ final class CheckImportController extends SimpleControllerBase
return $this->returnJsonResponse(JsonResponse::JSON_ERROR, __u('Missing LDAP parameters'));
}
- $this->ldapCheckService->checkConnection($ldapParams);
-
$filter = $this->request->analyzeString('ldap_import_filter');
if (empty($filter)) {
- $data = $this->ldapCheckService->getObjects($this->request->analyzeBool('ldap_import_groups', false));
+ $data = $this->ldapCheckService->getObjects(
+ $this->request->analyzeBool('ldap_import_groups', false),
+ $ldapParams
+ );
} else {
- $data = $this->ldapCheckService->getObjectsByFilter($filter);
+ $data = $this->ldapCheckService->getObjectsByFilter($filter, $ldapParams);
}
$this->template->addTemplate('results', 'itemshow');
@@ -116,8 +111,8 @@ final class CheckImportController extends SimpleControllerBase
/**
* @return void
- * @throws \JsonException
- * @throws \SP\Core\Exceptions\SessionTimeout
+ * @throws SPException
+ * @throws SessionTimeout
*/
protected function initialize(): void
{
diff --git a/app/modules/web/Controllers/ConfigLdap/ConfigLdapTrait.php b/app/modules/web/Controllers/ConfigLdap/ConfigLdapTrait.php
index aa37fccb..ce4b9e16 100644
--- a/app/modules/web/Controllers/ConfigLdap/ConfigLdapTrait.php
+++ b/app/modules/web/Controllers/ConfigLdap/ConfigLdapTrait.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -24,11 +24,12 @@
namespace SP\Modules\Web\Controllers\ConfigLdap;
-
use SP\Core\Exceptions\ValidationException;
use SP\Http\RequestInterface;
use SP\Providers\Auth\Ldap\LdapParams;
-use SP\Providers\Auth\Ldap\LdapTypeInterface;
+use SP\Providers\Auth\Ldap\LdapTypeEnum;
+
+use function SP\__u;
/**
* Trait ConfigLdapTrait
@@ -36,10 +37,10 @@ use SP\Providers\Auth\Ldap\LdapTypeInterface;
trait ConfigLdapTrait
{
/**
- * @param \SP\Http\RequestInterface $request
+ * @param RequestInterface $request
*
* @return LdapParams
- * @throws \SP\Core\Exceptions\ValidationException
+ * @throws ValidationException
*/
protected function getLdapParamsFromRequest(RequestInterface $request): LdapParams
{
@@ -49,20 +50,24 @@ trait ConfigLdapTrait
throw new ValidationException(__u('Wrong LDAP parameters'));
}
- $params = new LdapParams();
- $params->setServer($data['server']);
+ $type = LdapTypeEnum::tryFrom($request->analyzeInt('ldap_server_type')) ?: LdapTypeEnum::STD;
+
+ $params = new LdapParams(
+ $data['server'],
+ $type,
+ $request->analyzeString('ldap_binduser'),
+ $request->analyzeEncrypted('ldap_bindpass')
+ );
+
$params->setPort($data['port'] ?? 389);
$params->setSearchBase($request->analyzeString('ldap_base'));
$params->setGroup($request->analyzeString('ldap_group'));
- $params->setBindDn($request->analyzeString('ldap_binduser'));
- $params->setBindPass($request->analyzeEncrypted('ldap_bindpass'));
- $params->setType($request->analyzeInt('ldap_server_type', LdapTypeInterface::LDAP_STD));
$params->setTlsEnabled($request->analyzeBool('ldap_tls_enabled', false));
- $params->setFilterUserObject($request->analyzeString('ldap_filter_user_object', null));
- $params->setFilterGroupObject($request->analyzeString('ldap_filter_group_object', null));
+ $params->setFilterUserObject($request->analyzeString('ldap_filter_user_object'));
+ $params->setFilterGroupObject($request->analyzeString('ldap_filter_group_object'));
$params->setFilterUserAttributes($request->analyzeArray('ldap_filter_user_attributes'));
$params->setFilterGroupAttributes($request->analyzeArray('ldap_filter_group_attributes'));
return $params;
}
-}
\ No newline at end of file
+}
diff --git a/app/modules/web/Controllers/ConfigManager/IndexController.php b/app/modules/web/Controllers/ConfigManager/IndexController.php
index 128dc482..dabe3342 100644
--- a/app/modules/web/Controllers/ConfigManager/IndexController.php
+++ b/app/modules/web/Controllers/ConfigManager/IndexController.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -61,7 +61,7 @@ use SP\Mvc\View\Components\SelectItemAdapter;
use SP\Plugin\PluginManager;
use SP\Providers\Auth\Ldap\LdapMsAds;
use SP\Providers\Auth\Ldap\LdapStd;
-use SP\Providers\Auth\Ldap\LdapTypeInterface;
+use SP\Providers\Auth\Ldap\LdapTypeEnum;
use SP\Providers\Log\LogInterface;
use SP\Providers\Mail\MailHandler;
use SP\Util\Util;
@@ -82,17 +82,17 @@ final class IndexController extends ControllerBase
private PluginManager $pluginManager;
public function __construct(
- Application $application,
- WebControllerHelper $webControllerHelper,
- TabsHelper $tabsHelper,
- UserServiceInterface $userService,
- UserGroupServiceInterface $userGroupService,
+ Application $application,
+ WebControllerHelper $webControllerHelper,
+ TabsHelper $tabsHelper,
+ UserServiceInterface $userService,
+ UserGroupServiceInterface $userGroupService,
UserProfileServiceInterface $userProfileService,
- MimeTypesInterface $mimeTypes,
- DatabaseUtil $databaseUtil,
- ConfigServiceInterface $configService,
- AccountServiceInterface $accountService,
- PluginManager $pluginManager
+ MimeTypesInterface $mimeTypes,
+ DatabaseUtil $databaseUtil,
+ ConfigServiceInterface $configService,
+ AccountServiceInterface $accountService,
+ PluginManager $pluginManager
) {
parent::__construct($application, $webControllerHelper);
@@ -235,10 +235,10 @@ final class IndexController extends ControllerBase
$template->assign(
'logEvents',
SelectItemAdapter::factory($events)
- ->getItemsFromArraySelected(
- $this->configData->getLogEvents(),
- true
- )
+ ->getItemsFromArraySelected(
+ $this->configData->getLogEvents(),
+ true
+ )
);
return new DataTab(__('General'), $template);
@@ -319,14 +319,14 @@ final class IndexController extends ControllerBase
);
$serverTypes = [
- LdapTypeInterface::LDAP_STD => 'Standard',
- LdapTypeInterface::LDAP_ADS => 'Active Directory',
+ LdapTypeEnum::STD->value => 'Standard',
+ LdapTypeEnum::ADS->value => 'Active Directory',
];
$template->assign(
'serverTypes',
SelectItemAdapter::factory($serverTypes)
- ->getItemsFromArraySelected([$this->configData->getLdapType()])
+ ->getItemsFromArraySelected([$this->configData->getLdapType()])
);
$userAttributes = array_merge(
@@ -338,7 +338,7 @@ final class IndexController extends ControllerBase
$template->assign(
'userAttributes',
SelectItemAdapter::factory($userAttributes)
- ->getItemsFromArraySelected($this->configData->getLdapFilterUserAttributes())
+ ->getItemsFromArraySelected($this->configData->getLdapFilterUserAttributes())
);
$groupAttributes = array_merge(
@@ -350,7 +350,7 @@ final class IndexController extends ControllerBase
$template->assign(
'groupAttributes',
SelectItemAdapter::factory($groupAttributes)
- ->getItemsFromArraySelected($this->configData->getLdapFilterGroupAttributes())
+ ->getItemsFromArraySelected($this->configData->getLdapFilterGroupAttributes())
);
return new DataTab(__('LDAP'), $template);
@@ -386,10 +386,10 @@ final class IndexController extends ControllerBase
$template->assign(
'mailEvents',
SelectItemAdapter::factory($events)
- ->getItemsFromArraySelected(
- $mailEvents,
- true
- )
+ ->getItemsFromArraySelected(
+ $mailEvents,
+ true
+ )
);
return new DataTab(__('Mail'), $template);
@@ -534,12 +534,12 @@ final class IndexController extends ControllerBase
$template->assign(
'userGroups',
SelectItemAdapter::factory($this->userGroupService->getAllBasic())
- ->getItemsFromModelSelected([$this->userData->getUserGroupId()])
+ ->getItemsFromModelSelected([$this->userData->getUserGroupId()])
);
$template->assign(
'users',
SelectItemAdapter::factory($this->userService->getAllBasic())
- ->getItemsFromModelSelected([$this->userData->getId()])
+ ->getItemsFromModelSelected([$this->userData->getId()])
);
return new DataTab(__('Import Accounts'), $template);
@@ -557,7 +557,7 @@ final class IndexController extends ControllerBase
$template->addTemplate('info');
$template->assign('dbInfo', $this->databaseUtil->getDBinfo());
- $template->assign('dbName', $this->configData->getDbName().'@'.$this->configData->getDbHost());
+ $template->assign('dbName', $this->configData->getDbName() . '@' . $this->configData->getDbHost());
$template->assign(
'configBackupDate',
date('r', $this->configService->getByParam('config_backup_date', 0))
diff --git a/composer.json b/composer.json
index da3b02a9..c33c3b8d 100644
--- a/composer.json
+++ b/composer.json
@@ -54,7 +54,8 @@
"league/fractal": "^0.20",
"symfony/console": "^v5.1",
"symfony/lock": "^v5.0",
- "aura/sqlquery": "~3.0"
+ "aura/sqlquery": "~3.0",
+ "laminas/laminas-ldap": "^2.17"
},
"require-dev": {
"roave/security-advisories": "dev-latest",
diff --git a/composer.lock b/composer.lock
index 48002dfc..558ca2ed 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "bba9096278509c2d1c21cb52101586bc",
+ "content-hash": "321f22ee1b6ccb2d6740fe5a18907cc6",
"packages": [
{
"name": "ademarre/binary-to-text-php",
@@ -1139,16 +1139,16 @@
},
{
"name": "guzzlehttp/promises",
- "version": "1.5.2",
+ "version": "1.5.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
- "reference": "b94b2807d85443f9719887892882d0329d1e2598"
+ "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598",
- "reference": "b94b2807d85443f9719887892882d0329d1e2598",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e",
+ "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e",
"shasum": ""
},
"require": {
@@ -1158,11 +1158,6 @@
"symfony/phpunit-bridge": "^4.4 || ^5.1"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.5-dev"
- }
- },
"autoload": {
"files": [
"src/functions_include.php"
@@ -1203,7 +1198,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
- "source": "https://github.com/guzzle/promises/tree/1.5.2"
+ "source": "https://github.com/guzzle/promises/tree/1.5.3"
},
"funding": [
{
@@ -1219,7 +1214,7 @@
"type": "tidelift"
}
],
- "time": "2022-08-28T14:55:35+00:00"
+ "time": "2023-05-21T12:31:43+00:00"
},
{
"name": "guzzlehttp/psr7",
@@ -1386,6 +1381,72 @@
},
"time": "2017-02-01T23:08:58+00:00"
},
+ {
+ "name": "laminas/laminas-ldap",
+ "version": "2.17.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laminas/laminas-ldap.git",
+ "reference": "cb66c477ec2fd2a7f38527c59d0635a9166b6597"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laminas/laminas-ldap/zipball/cb66c477ec2fd2a7f38527c59d0635a9166b6597",
+ "reference": "cb66c477ec2fd2a7f38527c59d0635a9166b6597",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ldap": "*",
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
+ },
+ "conflict": {
+ "zendframework/zend-ldap": "*"
+ },
+ "require-dev": {
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "laminas/laminas-config": "^3.8.0",
+ "laminas/laminas-eventmanager": "^3.6.0",
+ "laminas/laminas-stdlib": "^3.15.0",
+ "php-mock/php-mock-phpunit": "^2.6.1",
+ "phpunit/phpunit": "^9.5.26",
+ "psalm/plugin-phpunit": "^0.18.0",
+ "vimeo/psalm": "^5.0.0"
+ },
+ "suggest": {
+ "laminas/laminas-eventmanager": "Laminas\\EventManager component"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Laminas\\Ldap\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Provides support for LDAP operations including but not limited to binding, searching and modifying entries in an LDAP directory",
+ "homepage": "https://laminas.dev",
+ "keywords": [
+ "laminas",
+ "ldap"
+ ],
+ "support": {
+ "chat": "https://laminas.dev/chat",
+ "docs": "https://docs.laminas.dev/laminas-ldap/",
+ "forum": "https://discourse.laminas.dev",
+ "issues": "https://github.com/laminas/laminas-ldap/issues",
+ "rss": "https://github.com/laminas/laminas-ldap/releases.atom",
+ "source": "https://github.com/laminas/laminas-ldap"
+ },
+ "funding": [
+ {
+ "url": "https://funding.communitybridge.org/projects/laminas-project",
+ "type": "community_bridge"
+ }
+ ],
+ "time": "2022-12-19T19:50:51+00:00"
+ },
{
"name": "laravel/serializable-closure",
"version": "v1.3.0",
@@ -3855,16 +3916,16 @@
},
{
"name": "phpunit/php-code-coverage",
- "version": "10.1.1",
+ "version": "10.1.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "884a0da7f9f46f28b2cb69134217fd810b793974"
+ "reference": "db1497ec8dd382e82c962f7abbe0320e4882ee4e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/884a0da7f9f46f28b2cb69134217fd810b793974",
- "reference": "884a0da7f9f46f28b2cb69134217fd810b793974",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/db1497ec8dd382e82c962f7abbe0320e4882ee4e",
+ "reference": "db1497ec8dd382e82c962f7abbe0320e4882ee4e",
"shasum": ""
},
"require": {
@@ -3921,7 +3982,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.1"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.2"
},
"funding": [
{
@@ -3929,7 +3990,7 @@
"type": "github"
}
],
- "time": "2023-04-17T12:15:40+00:00"
+ "time": "2023-05-22T09:04:27+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -4280,12 +4341,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
- "reference": "67504d48750a345d427a6e653b46704599c15d3d"
+ "reference": "2d9146bd69addfbd99652930a825c8ba7b8ea13c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/67504d48750a345d427a6e653b46704599c15d3d",
- "reference": "67504d48750a345d427a6e653b46704599c15d3d",
+ "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/2d9146bd69addfbd99652930a825c8ba7b8ea13c",
+ "reference": "2d9146bd69addfbd99652930a825c8ba7b8ea13c",
"shasum": ""
},
"conflict": {
@@ -4349,7 +4410,7 @@
"cockpit-hq/cockpit": "<2.4.1",
"codeception/codeception": "<3.1.3|>=4,<4.1.22",
"codeigniter/framework": "<=3.0.6",
- "codeigniter4/framework": "<4.2.11",
+ "codeigniter4/framework": "<4.3.5",
"codeigniter4/shield": "<1-beta.4|= 1.0.0-beta",
"codiad/codiad": "<=2.8.4",
"composer/composer": "<1.10.26|>=2-alpha.1,<2.2.12|>=2.3,<2.3.5",
@@ -4361,7 +4422,7 @@
"contao/core-bundle": "<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4|= 4.10.0",
"contao/listing-bundle": ">=4,<4.4.8",
"contao/managed-edition": "<=1.5",
- "craftcms/cms": "<=3.8.3|>=4,<=4.4.3|>= 4.0.0-RC1, < 4.3.7|>= 4.0.0-RC1, < 4.2.1",
+ "craftcms/cms": "<=3.8.3|>=4,<4.4.6|>= 4.0.0-RC1, < 4.3.7|>= 4.0.0-RC1, < 4.2.1",
"croogo/croogo": "<3.0.7",
"cuyz/valinor": "<0.12",
"czproject/git-php": "<4.0.3",
@@ -4683,7 +4744,7 @@
"simplesamlphp/simplesamlphp-module-openidprovider": "<0.9",
"simplito/elliptic-php": "<1.0.6",
"sitegeist/fluid-components": "<3.5",
- "slim/psr7": "<1.6.1",
+ "slim/psr7": "<1.4.1|>=1.5,<1.5.1|>=1.6,<1.6.1",
"slim/slim": "<2.6",
"smarty/smarty": "<3.1.48|>=4,<4.3.1",
"snipe/snipe-it": "<=6.0.14|>= 6.0.0-RC-1, <= 6.0.0-RC-5",
@@ -4880,7 +4941,7 @@
"type": "tidelift"
}
],
- "time": "2023-05-20T00:13:18+00:00"
+ "time": "2023-05-22T21:04:18+00:00"
},
{
"name": "sebastian/cli-parser",
diff --git a/lib/SP/Core/Definitions/CoreDefinitions.php b/lib/SP/Core/Definitions/CoreDefinitions.php
index d07f0671..80b12d6d 100644
--- a/lib/SP/Core/Definitions/CoreDefinitions.php
+++ b/lib/SP/Core/Definitions/CoreDefinitions.php
@@ -49,6 +49,9 @@ use SP\Core\MimeTypesInterface;
use SP\Core\ProvidersHelper;
use SP\Core\UI\Theme;
use SP\Core\UI\ThemeInterface;
+use SP\Domain\Auth\Ports\LdapActionsInterface;
+use SP\Domain\Auth\Ports\LdapAuthInterface;
+use SP\Domain\Auth\Ports\LdapConnectionInterface;
use SP\Domain\Config\Ports\ConfigDataInterface;
use SP\Domain\Config\Ports\ConfigInterface;
use SP\Domain\Config\Services\ConfigBackupService;
@@ -79,9 +82,10 @@ use SP\Providers\Auth\Browser\BrowserAuth;
use SP\Providers\Auth\Browser\BrowserAuthInterface;
use SP\Providers\Auth\Database\DatabaseAuth;
use SP\Providers\Auth\Database\DatabaseAuthInterface;
-use SP\Providers\Auth\Ldap\Ldap;
+use SP\Providers\Auth\Ldap\LdapActions;
use SP\Providers\Auth\Ldap\LdapAuth;
-use SP\Providers\Auth\Ldap\LdapAuthInterface;
+use SP\Providers\Auth\Ldap\LdapBase;
+use SP\Providers\Auth\Ldap\LdapConnection;
use SP\Providers\Auth\Ldap\LdapParams;
use SP\Providers\Log\DatabaseLogHandler;
use SP\Providers\Log\FileLogHandler;
@@ -91,6 +95,7 @@ use SP\Providers\Mail\MailHandler;
use SP\Providers\Mail\MailProvider;
use SP\Providers\Mail\PhpMailerWrapper;
use SP\Providers\Notification\NotificationHandler;
+
use function DI\autowire;
use function DI\create;
use function DI\factory;
@@ -105,11 +110,11 @@ final class CoreDefinitions
public static function getDefinitions(): array
{
return [
- RequestInterface::class => create(Request::class)
+ RequestInterface::class => create(Request::class)
->constructor(\Klein\Request::createFromGlobals(), autowire(CryptPKI::class)),
- ContextInterface::class =>
+ ContextInterface::class =>
static fn() => ContextFactory::getForModule(APP_MODULE),
- ConfigInterface::class => create(ConfigFileService::class)
+ ConfigInterface::class => create(ConfigFileService::class)
->constructor(
create(XmlHandler::class)
->constructor(create(FileHandler::class)->constructor(CONFIG_FILE)),
@@ -117,37 +122,40 @@ final class CoreDefinitions
get(ContextInterface::class),
autowire(ConfigBackupService::class)
),
- ConfigDataInterface::class =>
+ ConfigDataInterface::class =>
static fn(ConfigInterface $config) => $config->getConfigData(),
- DatabaseConnectionData::class => factory([DatabaseConnectionData::class, 'getFromConfig']),
- DbStorageInterface::class => autowire(MysqlHandler::class),
- Actions::class =>
+ DatabaseConnectionData::class => factory([DatabaseConnectionData::class, 'getFromConfig']),
+ DbStorageInterface::class => autowire(MysqlHandler::class),
+ Actions::class =>
static fn() => new Actions(
new FileCache(Actions::ACTIONS_CACHE_FILE),
new XmlHandler(new FileHandler(ACTIONS_FILE))
),
- MimeTypesInterface::class =>
+ MimeTypesInterface::class =>
static fn() => new MimeTypes(
new FileCache(MimeTypes::MIME_CACHE_FILE),
new XmlHandler(new FileHandler(MIMETYPES_FILE))
),
- Acl::class => autowire(Acl::class)
+ Acl::class => autowire(Acl::class)
->constructorParameter('actions', get(Actions::class)),
- ThemeInterface::class => autowire(Theme::class)
+ ThemeInterface::class => autowire(Theme::class)
->constructorParameter('module', APP_MODULE)
->constructorParameter(
'fileCache',
create(FileCache::class)->constructor(Theme::ICONS_CACHE_FILE)
),
- TemplateInterface::class => autowire(Template::class),
- DatabaseAuthInterface::class => autowire(DatabaseAuth::class),
- BrowserAuthInterface::class => autowire(BrowserAuth::class),
- LdapAuthInterface::class => autowire(LdapAuth::class)
+ TemplateInterface::class => autowire(Template::class),
+ DatabaseAuthInterface::class => autowire(DatabaseAuth::class),
+ BrowserAuthInterface::class => autowire(BrowserAuth::class),
+ LdapParams::class => factory([LdapParams::class, 'getFrom']),
+ LdapConnectionInterface::class => autowire(LdapConnection::class),
+ LdapActionsInterface::class => autowire(LdapActions::class),
+ LdapAuthInterface::class => autowire(LdapAuth::class)
->constructorParameter(
'ldap',
- factory([Ldap::class, 'factory'])->parameter('ldapParams', factory([LdapParams::class, 'getFrom']))
+ factory([LdapBase::class, 'factory'])
),
- AuthProviderInterface::class =>
+ AuthProviderInterface::class =>
static function (ContainerInterface $c, ConfigDataInterface $configData) {
$provider = $c->get(AuthProvider::class);
@@ -161,18 +169,18 @@ final class CoreDefinitions
return $provider;
},
- Logger::class => create(Logger::class)
+ Logger::class => create(Logger::class)
->constructor('syspass'),
- \GuzzleHttp\Client::class => create(\GuzzleHttp\Client::class)
+ \GuzzleHttp\Client::class => create(\GuzzleHttp\Client::class)
->constructor(factory([Client::class, 'getOptions'])),
- CSRF::class => autowire(CSRF::class),
- LanguageInterface::class => autowire(Language::class),
- DatabaseInterface::class => autowire(Database::class),
- MailProviderInterface::class => autowire(MailProvider::class),
- MailerInterface::class => autowire(PhpMailerWrapper::class)->constructor(
+ CSRF::class => autowire(CSRF::class),
+ LanguageInterface::class => autowire(Language::class),
+ DatabaseInterface::class => autowire(Database::class),
+ MailProviderInterface::class => autowire(MailProvider::class),
+ MailerInterface::class => autowire(PhpMailerWrapper::class)->constructor(
create(PHPMailer::class)->constructor(true)
),
- DatabaseSetupInterface::class => static function (RequestInterface $request) {
+ DatabaseSetupInterface::class => static function (RequestInterface $request) {
$installData = InstallDataFactory::buildFromRequest($request);
if ($installData->getBackendType() === 'mysql') {
@@ -181,7 +189,7 @@ final class CoreDefinitions
throw new SPException(__u('Unimplemented'), SPException::ERROR, __u('Wrong backend type'));
},
- ProvidersHelper::class => factory(static function (ContainerInterface $c) {
+ ProvidersHelper::class => factory(static function (ContainerInterface $c) {
$configData = $c->get(ConfigDataInterface::class);
if (!$configData->isInstalled()) {
@@ -198,15 +206,15 @@ final class CoreDefinitions
$c->get(NotificationHandler::class)
);
}),
- QueryFactory::class => create(QueryFactory::class)
+ QueryFactory::class => create(QueryFactory::class)
->constructor('mysql', QueryFactory::COMMON),
- CryptInterface::class => create(Crypt::class),
- CryptPKIInterface::class => autowire(CryptPKI::class)
+ CryptInterface::class => create(Crypt::class),
+ CryptPKIInterface::class => autowire(CryptPKI::class)
->constructorParameter('publicKeyFile', new FileHandler(CryptPKI::PUBLIC_KEY_FILE))
->constructorParameter('privateKeyFile', new FileHandler(CryptPKI::PRIVATE_KEY_FILE)),
- FileCacheInterface::class => create(FileCache::class),
- Application::class => autowire(Application::class),
- UUIDCookie::class => factory([UUIDCookie::class, 'factory'])
+ FileCacheInterface::class => create(FileCache::class),
+ Application::class => autowire(Application::class),
+ UUIDCookie::class => factory([UUIDCookie::class, 'factory'])
->parameter(
'request',
get(RequestInterface::class)
diff --git a/lib/SP/Core/Events/Event.php b/lib/SP/Core/Events/Event.php
index 68d7107e..5cc3c0af 100644
--- a/lib/SP/Core/Events/Event.php
+++ b/lib/SP/Core/Events/Event.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -34,21 +34,20 @@ use SP\Core\Exceptions\SPException;
*/
class Event
{
- private object $source;
+ private object $source;
private ?EventMessage $eventMessage;
/**
* Event constructor.
*
- * @param object $source
+ * @param object $source
* @param EventMessage|null $eventMessage
*
*/
public function __construct(
- object $source,
- EventMessage $eventMessage = null
- )
- {
+ object $source,
+ ?EventMessage $eventMessage = null
+ ) {
$this->source = $source;
$this->eventMessage = $eventMessage;
}
@@ -76,5 +75,4 @@ class Event
{
return $this->eventMessage;
}
-
-}
\ No newline at end of file
+}
diff --git a/lib/SP/Core/Exceptions/SPException.php b/lib/SP/Core/Exceptions/SPException.php
index 38209c68..d8dafd75 100644
--- a/lib/SP/Core/Exceptions/SPException.php
+++ b/lib/SP/Core/Exceptions/SPException.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -33,10 +33,6 @@ defined('APP_ROOT') || die();
*/
class SPException extends Exception
{
- /**
- * Constantes para tipos de excepción
- */
- public const OK = 0;
public const CRITICAL = 1;
public const WARNING = 2;
public const ERROR = 3;
@@ -48,17 +44,17 @@ class SPException extends Exception
/**
* SPException constructor.
*
- * @param string $message
- * @param int $type
- * @param string|null $hint
- * @param int $code
- * @param Exception|null $previous
+ * @param string $message
+ * @param int $type
+ * @param string|null $hint
+ * @param int $code
+ * @param Exception|null $previous
*/
public function __construct(
- string $message,
- int $type = self::ERROR,
- ?string $hint = null,
- int $code = 0,
+ string $message,
+ int $type = self::ERROR,
+ ?string $hint = null,
+ int $code = 0,
Exception $previous = null
) {
$this->type = $type;
@@ -67,12 +63,48 @@ class SPException extends Exception
parent::__construct($message, $code, $previous);
}
+ public static function error(
+ string $message,
+ ?string $hint = null,
+ int $code = 0,
+ Exception $previous = null
+ ): static {
+ return new static($message, SPException::ERROR, $hint, $code, $previous);
+ }
+
+ public static function critical(
+ string $message,
+ ?string $hint = null,
+ int $code = 0,
+ Exception $previous = null
+ ): static {
+ return new static($message, SPException::CRITICAL, $hint, $code, $previous);
+ }
+
+ public static function warning(
+ string $message,
+ ?string $hint = null,
+ int $code = 0,
+ Exception $previous = null
+ ): static {
+ return new static($message, SPException::WARNING, $hint, $code, $previous);
+ }
+
+ public static function info(
+ string $message,
+ ?string $hint = null,
+ int $code = 0,
+ Exception $previous = null
+ ): static {
+ return new static($message, SPException::INFO, $hint, $code, $previous);
+ }
+
/**
* @return string
*/
- public function __toString()
+ public function __toString(): string
{
- return __CLASS__.": [{$this->code}]: {$this->message} ({$this->hint})\n";
+ return sprintf('%s: [%s]: %s (%s)', __CLASS__, $this->code, $this->message, $this->hint);
}
public function getHint(): ?string
diff --git a/lib/SP/Domain/Auth/Ports/LdapActionsInterface.php b/lib/SP/Domain/Auth/Ports/LdapActionsInterface.php
new file mode 100644
index 00000000..0dbb5af9
--- /dev/null
+++ b/lib/SP/Domain/Auth/Ports/LdapActionsInterface.php
@@ -0,0 +1,74 @@
+.
+ */
+
+namespace SP\Domain\Auth\Ports;
+
+
+use SP\Providers\Auth\Ldap\AttributeCollection;
+use SP\Providers\Auth\Ldap\LdapException;
+use SP\Providers\Auth\Ldap\LdapParams;
+
+/**
+ * Class LdapActions
+ *
+ * @package SP\Providers\Auth\Ldap
+ */
+interface LdapActionsInterface
+{
+ /**
+ * Obtener el RDN del grupo.
+ *
+ * @param string $groupFilter
+ *
+ * @return array Groups' DN
+ * @throws LdapException
+ */
+ public function searchGroupsDn(string $groupFilter): array;
+
+ /**
+ * @param string $filter
+ *
+ * @return AttributeCollection
+ * @throws LdapException
+ */
+ public function getAttributes(string $filter): AttributeCollection;
+
+ /**
+ * Obtener los objetos según el filtro indicado
+ *
+ * @param string $filter
+ * @param array $attributes
+ * @param string|null $searchBase
+ *
+ * @return array
+ * @throws LdapException
+ */
+ public function getObjects(
+ string $filter,
+ array $attributes,
+ ?string $searchBase = null
+ ): array;
+
+ public function mutate(LdapParams $ldapParams): LdapActionsInterface;
+}
diff --git a/lib/SP/Providers/Auth/Ldap/LdapAuthInterface.php b/lib/SP/Domain/Auth/Ports/LdapAuthInterface.php
similarity index 65%
rename from lib/SP/Providers/Auth/Ldap/LdapAuthInterface.php
rename to lib/SP/Domain/Auth/Ports/LdapAuthInterface.php
index 8de21ac6..079feb10 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapAuthInterface.php
+++ b/lib/SP/Domain/Auth/Ports/LdapAuthInterface.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -22,10 +22,10 @@
* along with sysPass. If not, see .
*/
-namespace SP\Providers\Auth\Ldap;
-
+namespace SP\Domain\Auth\Ports;
use SP\Providers\Auth\AuthInterface;
+use SP\Providers\Auth\Ldap\LdapAuthData;
/**
* Class LdapBase
@@ -41,24 +41,4 @@ interface LdapAuthInterface extends AuthInterface
* @return LdapAuthData
*/
public function getLdapAuthData(): LdapAuthData;
-
- /**
- * @return string
- */
- public function getUserLogin(): ?string;
-
- /**
- * @param string $userLogin
- */
- public function setUserLogin(string $userLogin): void;
-
- /**
- * Obtener los atributos del usuario.
- *
- * @param string $userLogin
- *
- * @return LdapAuthData con los atributos disponibles y sus valores
- * @throws LdapException
- */
- public function getAttributes(string $userLogin): LdapAuthData;
-}
\ No newline at end of file
+}
diff --git a/lib/SP/Domain/Auth/Ports/LdapCheckServiceInterface.php b/lib/SP/Domain/Auth/Ports/LdapCheckServiceInterface.php
index 9a2aec5c..09a4b5c2 100644
--- a/lib/SP/Domain/Auth/Ports/LdapCheckServiceInterface.php
+++ b/lib/SP/Domain/Auth/Ports/LdapCheckServiceInterface.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -26,7 +26,6 @@ namespace SP\Domain\Auth\Ports;
use SP\Providers\Auth\Ldap\LdapException;
-use SP\Providers\Auth\Ldap\LdapParams;
/**
* Class LdapCheckService
@@ -36,29 +35,12 @@ use SP\Providers\Auth\Ldap\LdapParams;
interface LdapCheckServiceInterface
{
/**
- * @param LdapParams $ldapParams
- *
* @throws LdapException
*/
- public function checkConnection(LdapParams $ldapParams): void;
-
- /**
- * @throws \SP\Providers\Auth\Ldap\LdapException
- */
public function getObjects(bool $includeGroups = true): array;
/**
- * Obtener los datos de una búsqueda de LDAP de un atributo
- *
- * @param array $data
- * @param string[] $attributes
- *
- * @return array
- */
- public function ldapResultsMapper(array $data, array $attributes = ['dn']): array;
-
- /**
- * @throws \SP\Providers\Auth\Ldap\LdapException
+ * @throws LdapException
*/
public function getObjectsByFilter(string $filter): array;
}
diff --git a/lib/SP/Domain/Auth/Ports/LdapConnectionInterface.php b/lib/SP/Domain/Auth/Ports/LdapConnectionInterface.php
new file mode 100644
index 00000000..5ed4acc9
--- /dev/null
+++ b/lib/SP/Domain/Auth/Ports/LdapConnectionInterface.php
@@ -0,0 +1,51 @@
+.
+ */
+
+namespace SP\Domain\Auth\Ports;
+
+use SP\Providers\Auth\Ldap\LdapException;
+use SP\Providers\Auth\Ldap\LdapParams;
+
+/**
+ * Interface LdapInterface
+ *
+ * @package Auth\Ldap
+ */
+interface LdapConnectionInterface
+{
+ /**
+ * @throws LdapException
+ */
+ public function checkConnection(): void;
+
+ /**
+ * @throws LdapException
+ */
+ public function connect(?string $bindDn = null, ?string $bindPass = null): void;
+
+ /**
+ * @throws LdapException
+ */
+ public function mutate(LdapParams $ldapParams): LdapConnectionInterface;
+}
diff --git a/lib/SP/Providers/Auth/Ldap/LdapInterface.php b/lib/SP/Domain/Auth/Ports/LdapInterface.php
similarity index 82%
rename from lib/SP/Providers/Auth/Ldap/LdapInterface.php
rename to lib/SP/Domain/Auth/Ports/LdapInterface.php
index 5259cb6e..d09f131f 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapInterface.php
+++ b/lib/SP/Domain/Auth/Ports/LdapInterface.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -22,9 +22,11 @@
* along with sysPass. If not, see .
*/
-namespace SP\Providers\Auth\Ldap;
+namespace SP\Domain\Auth\Ports;
+use SP\Providers\Auth\Ldap\LdapException;
+
/**
* Interface LdapInterface
*
@@ -32,8 +34,6 @@ namespace SP\Providers\Auth\Ldap;
*/
interface LdapInterface
{
- public const PAGE_SIZE = 500;
-
/**
* Obtener el filtro para buscar el usuario
*
@@ -64,7 +64,7 @@ interface LdapInterface
*
* @param string $userDn
* @param string $userLogin
- * @param array $groupsDn
+ * @param array $groupsDn
*
* @return bool
*/
@@ -77,28 +77,21 @@ interface LdapInterface
*/
public function getGroupObjectFilter(): string;
- /**
- * Connects and binds to an LDAP server
- *
- * @throws LdapException
- */
- public function connect();
-
/**
* @param string|null $bindDn
* @param string|null $bindPass
*
- * @return bool
- */
- public function bind(?string $bindDn = null, ?string $bindPass = null): bool;
+ * @throws LdapException
+ **/
+ public function connect(?string $bindDn = null, ?string $bindPass = null): void;
/**
- * @return LdapActions
+ * @return LdapActionsInterface
*/
- public function getLdapActions(): LdapActions;
+ public function getLdapActions(): LdapActionsInterface;
/**
* @return string
*/
public function getServer(): string;
-}
\ No newline at end of file
+}
diff --git a/lib/SP/Domain/Auth/Services/LdapCheckService.php b/lib/SP/Domain/Auth/Services/LdapCheckService.php
index 71e2089c..670387bc 100644
--- a/lib/SP/Domain/Auth/Services/LdapCheckService.php
+++ b/lib/SP/Domain/Auth/Services/LdapCheckService.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -24,65 +24,76 @@
namespace SP\Domain\Auth\Services;
+use SP\Core\Application;
+use SP\Domain\Auth\Ports\LdapActionsInterface;
use SP\Domain\Auth\Ports\LdapCheckServiceInterface;
+use SP\Domain\Auth\Ports\LdapConnectionInterface;
+use SP\Domain\Auth\Ports\LdapInterface;
use SP\Domain\Common\Services\Service;
-use SP\Providers\Auth\Ldap\Ldap;
+use SP\Providers\Auth\Ldap\LdapBase;
use SP\Providers\Auth\Ldap\LdapException;
-use SP\Providers\Auth\Ldap\LdapInterface;
use SP\Providers\Auth\Ldap\LdapParams;
/**
* Class LdapCheckService
- *
- * @package SP\Domain\Import\Services
*/
final class LdapCheckService extends Service implements LdapCheckServiceInterface
{
- protected ?LdapInterface $ldap = null;
-
- /**
- * @param LdapParams $ldapParams
- *
- * @throws LdapException
- */
- public function checkConnection(LdapParams $ldapParams): void
- {
- $this->ldap = Ldap::factory(
- $ldapParams,
- $this->eventDispatcher,
- true
- );
+ public function __construct(
+ Application $application,
+ private readonly LdapConnectionInterface $ldapConnection,
+ private readonly LdapActionsInterface $ldapActions
+ ) {
+ parent::__construct($application);
}
/**
- * @throws \SP\Providers\Auth\Ldap\LdapException
+ * @throws LdapException
*/
- public function getObjectsByFilter(string $filter): array
+ public function getObjectsByFilter(string $filter, ?LdapParams $ldapParams = null): array
{
+ $ldap = $this->getLdap($ldapParams);
+
$objects = $this->ldapResultsMapper(
- $this->ldap->getLdapActions()->getObjects($filter, ['dn'])
+ $ldap->getLdapActions()->getObjects($filter, ['dn'])
);
return [
- 'count' => count($objects),
+ 'count' => count($objects),
'results' => [
[
- 'icon' => '',
+ 'icon' => '',
'items' => $objects,
],
],
];
}
+ /**
+ * @param LdapParams $ldapParams
+ *
+ * @return LdapInterface
+ * @throws LdapException
+ */
+ private function getLdap(LdapParams $ldapParams): LdapInterface
+ {
+ return LdapBase::factory(
+ $this->eventDispatcher,
+ $this->ldapConnection,
+ $this->ldapActions,
+ $ldapParams
+ );
+ }
+
/**
* Obtener los datos de una búsqueda de LDAP de un atributo
*
- * @param array $data
- * @param string[] $attributes
+ * @param array $data
+ * @param string[] $attributes
*
* @return array
*/
- public function ldapResultsMapper(
+ private function ldapResultsMapper(
array $data,
array $attributes = ['dn']
): array {
@@ -108,21 +119,23 @@ final class LdapCheckService extends Service implements LdapCheckServiceInterfac
}
/**
- * @throws \SP\Providers\Auth\Ldap\LdapException
+ * @throws LdapException
*/
- public function getObjects(bool $includeGroups = true): array
+ public function getObjects(bool $includeGroups = true, ?LdapParams $ldapParams = null): array
{
- $ldapActions = $this->ldap->getLdapActions();
+ $ldap = $this->getLdap($ldapParams);
+
+ $ldapActions = $ldap->getLdapActions();
$data = ['count' => 0, 'results' => []];
$indirectFilterItems = $this->ldapResultsMapper(
- $ldapActions->getObjects($this->ldap->getGroupMembershipIndirectFilter(), ['dn'])
+ $ldapActions->getObjects($ldap->getGroupMembershipIndirectFilter(), ['dn'])
);
$directFilterItems = $this->ldapResultsMapper(
$ldapActions->getObjects(
- $this->ldap->getGroupMembershipDirectFilter(),
+ $ldap->getGroupMembershipDirectFilter(),
['member', 'memberUid', 'uniqueMember']
),
['member', 'memberUid', 'uniqueMember']
@@ -131,17 +144,17 @@ final class LdapCheckService extends Service implements LdapCheckServiceInterfac
$userItems = array_unique(array_merge($indirectFilterItems, $directFilterItems));
$data['results'][] = [
- 'icon' => 'person',
+ 'icon' => 'person',
'items' => array_values($userItems),
];
if ($includeGroups) {
$groupItems = $this->ldapResultsMapper(
- $ldapActions->getObjects($this->ldap->getGroupObjectFilter(), ['dn'])
+ $ldapActions->getObjects($ldap->getGroupObjectFilter(), ['dn'])
);
$data['results'][] = [
- 'icon' => 'group',
+ 'icon' => 'group',
'items' => $groupItems,
];
}
diff --git a/lib/SP/Domain/Auth/Services/LoginService.php b/lib/SP/Domain/Auth/Services/LoginService.php
index 07478c07..399b3629 100644
--- a/lib/SP/Domain/Auth/Services/LoginService.php
+++ b/lib/SP/Domain/Auth/Services/LoginService.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -39,6 +39,7 @@ use SP\Core\LanguageInterface;
use SP\Core\UI\ThemeInterface;
use SP\DataModel\UserLoginData;
use SP\DataModel\UserPreferencesData;
+use SP\Domain\Auth\Ports\LdapAuthInterface;
use SP\Domain\Auth\Ports\LoginServiceInterface;
use SP\Domain\Common\Services\Service;
use SP\Domain\Config\Ports\ConfigDataInterface;
@@ -58,10 +59,11 @@ use SP\Providers\Auth\AuthProviderInterface;
use SP\Providers\Auth\Browser\BrowserAuthData;
use SP\Providers\Auth\Database\DatabaseAuthData;
use SP\Providers\Auth\Ldap\LdapAuthData;
-use SP\Providers\Auth\Ldap\LdapAuthInterface;
-use SP\Providers\Auth\Ldap\LdapCode;
+use SP\Providers\Auth\Ldap\LdapCodeEnum;
use SP\Util\PasswordUtil;
+use function SP\__u;
+
/**
* Class LoginService
*
@@ -98,17 +100,17 @@ final class LoginService extends Service implements LoginServiceInterface
* @throws \SP\Domain\Auth\Services\AuthException
*/
public function __construct(
- Application $application,
- AuthProviderInterface $authProvider,
- ThemeInterface $theme,
- LanguageInterface $language,
- TrackServiceInterface $trackService,
- RequestInterface $request,
- UserServiceInterface $userService,
- UserPassRecoverServiceInterface $userPassRecoverService,
+ Application $application,
+ AuthProviderInterface $authProvider,
+ ThemeInterface $theme,
+ LanguageInterface $language,
+ TrackServiceInterface $trackService,
+ RequestInterface $request,
+ UserServiceInterface $userService,
+ UserPassRecoverServiceInterface $userPassRecoverService,
TemporaryMasterPassServiceInterface $temporaryMasterPassService,
- UserPassServiceInterface $userPassService,
- UserProfileServiceInterface $userProfileService
+ UserPassServiceInterface $userPassService,
+ UserProfileServiceInterface $userProfileService
) {
parent::__construct($application);
@@ -257,8 +259,8 @@ final class LoginService extends Service implements LoginServiceInterface
new Event(
$this,
EventMessage::factory()
- ->addDescription(__u('User disabled'))
- ->addDetail(__u('User'), $userLoginResponse->getLogin())
+ ->addDescription(__u('User disabled'))
+ ->addDetail(__u('User'), $userLoginResponse->getLogin())
)
);
@@ -284,7 +286,7 @@ final class LoginService extends Service implements LoginServiceInterface
$this->userPassRecoverService->add($userLoginResponse->getId(), $hash);
$uri = new Uri('index.php');
- $uri->addParam('r', 'userPassReset/reset/'.$hash);
+ $uri->addParam('r', 'userPassReset/reset/' . $hash);
return new LoginResponse(self::STATUS_PASS_RESET, $uri->getUri());
}
@@ -457,7 +459,7 @@ final class LoginService extends Service implements LoginServiceInterface
}
/**
- * @param string|null $from
+ * @param string|null $from
*/
public function setFrom(?string $from): void
{
@@ -467,7 +469,7 @@ final class LoginService extends Service implements LoginServiceInterface
/**
* Autentificación LDAP
*
- * @param LdapAuthData $authData
+ * @param LdapAuthData $authData
*
* @return bool
* @throws SPException
@@ -475,13 +477,13 @@ final class LoginService extends Service implements LoginServiceInterface
*/
private function authLdap(LdapAuthData $authData): bool
{
- if ($authData->getStatusCode() > LdapCode::SUCCESS) {
+ if ($authData->getStatusCode() > LdapCodeEnum::SUCCESS->value) {
$eventMessage = EventMessage::factory()
- ->addDetail(__u('Type'), __FUNCTION__)
- ->addDetail(__u('LDAP Server'), $authData->getServer())
- ->addDetail(__u('User'), $this->userLoginData->getLoginUser());
+ ->addDetail(__u('Type'), __FUNCTION__)
+ ->addDetail(__u('LDAP Server'), $authData->getServer())
+ ->addDetail(__u('User'), $this->userLoginData->getLoginUser());
- if ($authData->getStatusCode() === LdapCode::INVALID_CREDENTIALS) {
+ if ($authData->getStatusCode() === LdapCodeEnum::INVALID_CREDENTIALS->value) {
$eventMessage->addDescription(__u('Wrong login'));
$this->addTracking();
@@ -522,7 +524,7 @@ final class LoginService extends Service implements LoginServiceInterface
);
}
- if ($authData->getStatusCode() === LdapCode::NO_SUCH_OBJECT
+ if ($authData->getStatusCode() === LdapCodeEnum::NO_SUCH_OBJECT->value
|| $authData->isAuthoritative() === false
) {
$eventMessage->addDescription(__u('Non authoritative auth'));
@@ -552,8 +554,8 @@ final class LoginService extends Service implements LoginServiceInterface
new Event(
$this,
EventMessage::factory()
- ->addDetail(__u('Type'), __FUNCTION__)
- ->addDetail(__u('LDAP Server'), $authData->getServer())
+ ->addDetail(__u('Type'), __FUNCTION__)
+ ->addDetail(__u('LDAP Server'), $authData->getServer())
)
);
@@ -596,7 +598,7 @@ final class LoginService extends Service implements LoginServiceInterface
/**
* Autentificación en BD
*
- * @param DatabaseAuthData $authData
+ * @param DatabaseAuthData $authData
*
* @return bool
* @throws SPException
@@ -605,8 +607,8 @@ final class LoginService extends Service implements LoginServiceInterface
private function authDatabase(DatabaseAuthData $authData): bool
{
$eventMessage = EventMessage::factory()
- ->addDetail(__u('Type'), __FUNCTION__)
- ->addDetail(__u('User'), $this->userLoginData->getLoginUser());
+ ->addDetail(__u('Type'), __FUNCTION__)
+ ->addDetail(__u('User'), $this->userLoginData->getLoginUser());
// Autentificamos con la BBDD
if ($authData->getAuthenticated() === false) {
@@ -643,7 +645,7 @@ final class LoginService extends Service implements LoginServiceInterface
/**
* Comprobar si el cliente ha enviado las variables de autentificación
*
- * @param BrowserAuthData $authData
+ * @param BrowserAuthData $authData
*
* @return bool
* @throws AuthException
@@ -653,9 +655,12 @@ final class LoginService extends Service implements LoginServiceInterface
$authType = $this->request->getServer('AUTH_TYPE') ?: __('N/A');
$eventMessage = EventMessage::factory()
- ->addDetail(__u('Type'), __FUNCTION__)
- ->addDetail(__u('User'), $this->userLoginData->getLoginUser())
- ->addDetail(__u('Authentication'), sprintf('%s (%s)', $authType, $authData->getName()));
+ ->addDetail(__u('Type'), __FUNCTION__)
+ ->addDetail(__u('User'), $this->userLoginData->getLoginUser())
+ ->addDetail(
+ __u('Authentication'),
+ sprintf('%s (%s)', $authType, $authData->getName())
+ );
// Comprobar si concide el login con la autentificación del servidor web
if ($authData->getAuthenticated() === false) {
diff --git a/lib/SP/Domain/Config/Services/UpgradeConfigService.php b/lib/SP/Domain/Config/Services/UpgradeConfigService.php
index e779fb47..0f36b705 100644
--- a/lib/SP/Domain/Config/Services/UpgradeConfigService.php
+++ b/lib/SP/Domain/Config/Services/UpgradeConfigService.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -34,10 +34,12 @@ use SP\Domain\Config\Ports\ConfigDataInterface;
use SP\Domain\Config\Ports\UpgradeConfigServiceInterface;
use SP\Domain\Upgrade\Services\UpgradeException;
use SP\Infrastructure\File\FileException;
-use SP\Providers\Auth\Ldap\LdapTypeInterface;
+use SP\Providers\Auth\Ldap\LdapTypeEnum;
use SP\Providers\Log\FileLogHandler;
use SP\Util\VersionUtil;
+use function SP\__u;
+
/**
* Class UpgradeService
*
@@ -75,7 +77,7 @@ final class UpgradeConfigService extends Service implements UpgradeConfigService
/**
* Actualizar el archivo de configuración a formato XML
*
- * @throws \SP\Domain\Upgrade\Services\UpgradeException
+ * @throws UpgradeException
*/
public function upgradeOldConfigFile(string $version): void
{
@@ -111,7 +113,7 @@ final class UpgradeConfigService extends Service implements UpgradeConfigService
}
}
- $oldFile = OLD_CONFIG_FILE.'.old.'.time();
+ $oldFile = OLD_CONFIG_FILE . '.old.' . time();
try {
$configData->setSiteTheme('material-blue');
@@ -132,8 +134,8 @@ final class UpgradeConfigService extends Service implements UpgradeConfigService
new Event(
$this,
EventMessage::factory()
- ->addDescription(__u('Error while updating the configuration'))
- ->addDetail(__u('File'), $oldFile)
+ ->addDescription(__u('Error while updating the configuration'))
+ ->addDetail(__u('File'), $oldFile)
)
);
@@ -147,58 +149,58 @@ final class UpgradeConfigService extends Service implements UpgradeConfigService
private static function getConfigParams(): array
{
return [
- 'setAccountCount' => 'account_count',
- 'setAccountLink' => 'account_link',
- 'setCheckUpdates' => 'checkupdates',
- 'setCheckNotices' => 'checknotices',
- 'setDbHost' => 'dbhost',
- 'setDbName' => 'dbname',
- 'setDbPass' => 'dbpass',
- 'setDbUser' => 'dbuser',
- 'setDebug' => 'debug',
- 'setDemoEnabled' => 'demo_enabled',
- 'setGlobalSearch' => 'globalsearch',
- 'setInstalled' => 'installed',
- 'setMaintenance' => 'maintenance',
- 'setPasswordSalt' => 'passwordsalt',
- 'setSessionTimeout' => 'session_timeout',
- 'setSiteLang' => 'sitelang',
- 'setConfigVersion' => 'version',
- 'setConfigHash' => 'config_hash',
- 'setProxyEnabled' => 'proxy_enabled',
- 'setProxyPass' => 'proxy_pass',
- 'setProxyPort' => 'proxy_port',
- 'setProxyServer' => 'proxy_server',
- 'setProxyUser' => 'proxy_user',
- 'setResultsAsCards' => 'resultsascards',
- 'setSiteTheme' => 'sitetheme',
- 'setAccountPassToImage' => 'account_passtoimage',
- 'setFilesAllowedExts' => ['allowed_exts', 'files_allowed_exts'],
- 'setFilesAllowedSize' => ['allowed_size', 'files_allowed_size'],
- 'setFilesEnabled' => ['filesenabled', 'files_enabled'],
- 'setLdapBase' => ['ldapbase', 'ldap_base'],
- 'setLdapBindPass' => ['ldapbindpass', 'ldap_bindpass'],
- 'setLdapBindUser' => ['ldapbinduser', 'ldap_binduser'],
- 'setLdapEnabled' => ['ldapenabled', 'ldap_enabled'],
- 'setLdapGroup' => ['ldapgroup', 'ldap_group'],
- 'setLdapServer' => ['ldapserver', 'ldap_server'],
- 'setLdapAds' => 'ldap_ads',
- 'setLdapDefaultGroup' => 'ldap_defaultgroup',
- 'setLdapDefaultProfile' => 'ldap_defaultprofile',
- 'setLogEnabled' => ['logenabled', 'log_enabled'],
- 'setMailEnabled' => ['mailenabled', 'mail_enabled'],
- 'setMailFrom' => ['mailfrom', 'mail_from'],
- 'setMailPass' => ['mailpass', 'mail_pass'],
- 'setMailPort' => ['mailport', 'mail_port'],
+ 'setAccountCount' => 'account_count',
+ 'setAccountLink' => 'account_link',
+ 'setCheckUpdates' => 'checkupdates',
+ 'setCheckNotices' => 'checknotices',
+ 'setDbHost' => 'dbhost',
+ 'setDbName' => 'dbname',
+ 'setDbPass' => 'dbpass',
+ 'setDbUser' => 'dbuser',
+ 'setDebug' => 'debug',
+ 'setDemoEnabled' => 'demo_enabled',
+ 'setGlobalSearch' => 'globalsearch',
+ 'setInstalled' => 'installed',
+ 'setMaintenance' => 'maintenance',
+ 'setPasswordSalt' => 'passwordsalt',
+ 'setSessionTimeout' => 'session_timeout',
+ 'setSiteLang' => 'sitelang',
+ 'setConfigVersion' => 'version',
+ 'setConfigHash' => 'config_hash',
+ 'setProxyEnabled' => 'proxy_enabled',
+ 'setProxyPass' => 'proxy_pass',
+ 'setProxyPort' => 'proxy_port',
+ 'setProxyServer' => 'proxy_server',
+ 'setProxyUser' => 'proxy_user',
+ 'setResultsAsCards' => 'resultsascards',
+ 'setSiteTheme' => 'sitetheme',
+ 'setAccountPassToImage' => 'account_passtoimage',
+ 'setFilesAllowedExts' => ['allowed_exts', 'files_allowed_exts'],
+ 'setFilesAllowedSize' => ['allowed_size', 'files_allowed_size'],
+ 'setFilesEnabled' => ['filesenabled', 'files_enabled'],
+ 'setLdapBase' => ['ldapbase', 'ldap_base'],
+ 'setLdapBindPass' => ['ldapbindpass', 'ldap_bindpass'],
+ 'setLdapBindUser' => ['ldapbinduser', 'ldap_binduser'],
+ 'setLdapEnabled' => ['ldapenabled', 'ldap_enabled'],
+ 'setLdapGroup' => ['ldapgroup', 'ldap_group'],
+ 'setLdapServer' => ['ldapserver', 'ldap_server'],
+ 'setLdapAds' => 'ldap_ads',
+ 'setLdapDefaultGroup' => 'ldap_defaultgroup',
+ 'setLdapDefaultProfile' => 'ldap_defaultprofile',
+ 'setLogEnabled' => ['logenabled', 'log_enabled'],
+ 'setMailEnabled' => ['mailenabled', 'mail_enabled'],
+ 'setMailFrom' => ['mailfrom', 'mail_from'],
+ 'setMailPass' => ['mailpass', 'mail_pass'],
+ 'setMailPort' => ['mailport', 'mail_port'],
'setMailRequestsEnabled' => ['mailrequestsenabled', 'mail_requestsenabled'],
- 'setMailAuthenabled' => 'mail_authenabled',
- 'setMailSecurity' => ['mailsecurity', 'mail_security'],
- 'setMailServer' => ['mailserver', 'mail_server'],
- 'setMailUser' => ['mailuser', 'mail_user'],
- 'setWikiEnabled' => ['wikienabled', 'wiki_enabled'],
- 'setWikiFilter' => ['wikifilter', 'wiki_filter'],
- 'setWikiPageUrl' => ['wikipageurl'.'wiki_pageurl'],
- 'setWikiSearchUrl' => ['wikisearchurl', 'wiki_searchurl'],
+ 'setMailAuthenabled' => 'mail_authenabled',
+ 'setMailSecurity' => ['mailsecurity', 'mail_security'],
+ 'setMailServer' => ['mailserver', 'mail_server'],
+ 'setMailUser' => ['mailuser', 'mail_user'],
+ 'setWikiEnabled' => ['wikienabled', 'wiki_enabled'],
+ 'setWikiFilter' => ['wikifilter', 'wiki_filter'],
+ 'setWikiPageUrl' => ['wikipageurl' . 'wiki_pageurl'],
+ 'setWikiSearchUrl' => ['wikisearchurl', 'wiki_searchurl'],
];
}
@@ -240,7 +242,7 @@ final class UpgradeConfigService extends Service implements UpgradeConfigService
}
/**
- * @throws \SP\Infrastructure\File\FileException
+ * @throws FileException
*/
private function upgrade_200_17011202(string $version): void
{
@@ -254,8 +256,8 @@ final class UpgradeConfigService extends Service implements UpgradeConfigService
new Event(
$this,
EventMessage::factory()
- ->addDescription(__u('Update Configuration'))
- ->addDetail(__u('Version'), $version)
+ ->addDescription(__u('Update Configuration'))
+ ->addDetail(__u('Version'), $version)
)
);
}
@@ -281,9 +283,9 @@ final class UpgradeConfigService extends Service implements UpgradeConfigService
new Event(
$this,
EventMessage::factory()
- ->addDescription(__u('MIME type set for this extension'))
- ->addDetail(__u('MIME type'), $mimeType['type'])
- ->addDetail(__u('Extension'), $extension)
+ ->addDescription(__u('MIME type set for this extension'))
+ ->addDetail(__u('MIME type'), $mimeType['type'])
+ ->addDetail(__u('Extension'), $extension)
)
);
}
@@ -295,8 +297,8 @@ final class UpgradeConfigService extends Service implements UpgradeConfigService
new Event(
$this,
EventMessage::factory()
- ->addDescription(__u('MIME type not found for this extension'))
- ->addDetail(__u('Extension'), $extension)
+ ->addDescription(__u('MIME type not found for this extension'))
+ ->addDetail(__u('Extension'), $extension)
)
);
}
@@ -312,22 +314,22 @@ final class UpgradeConfigService extends Service implements UpgradeConfigService
new Event(
$this,
EventMessage::factory()
- ->addDescription(__u('Update Configuration'))
- ->addDetail(__u('Version'), $version)
+ ->addDescription(__u('Update Configuration'))
+ ->addDetail(__u('Version'), $version)
)
);
}
/**
- * @throws \SP\Infrastructure\File\FileException
+ * @throws FileException
*/
private function upgrade_300_18112501(string $version): void
{
if ($this->configData->isLdapEnabled()) {
if ($this->configData->get('ldapAds')) {
- $this->configData->setLdapType(LdapTypeInterface::LDAP_ADS);
+ $this->configData->setLdapType(LdapTypeEnum::ADS->value);
} else {
- $this->configData->setLdapType(LdapTypeInterface::LDAP_STD);
+ $this->configData->setLdapType(LdapTypeEnum::STD->value);
}
$this->configData->setConfigVersion($version);
@@ -339,21 +341,21 @@ final class UpgradeConfigService extends Service implements UpgradeConfigService
new Event(
$this,
EventMessage::factory()
- ->addDescription(__u('Update Configuration'))
- ->addDetail(__u('Version'), $version)
+ ->addDescription(__u('Update Configuration'))
+ ->addDetail(__u('Version'), $version)
)
);
}
}
/**
- * @throws \SP\Infrastructure\File\FileException
+ * @throws FileException
*/
private function upgrade_320_20062801(string $version): void
{
if ($this->configData->isLdapEnabled()) {
- if ($this->configData->get('ldapType') === LdapTypeInterface::LDAP_AZURE) {
- $this->configData->setLdapType(LdapTypeInterface::LDAP_ADS);
+ if ($this->configData->get('ldapType') === LdapTypeEnum::AZURE->value) {
+ $this->configData->setLdapType(LdapTypeEnum::ADS->value);
}
$this->configData->setConfigVersion($version);
@@ -365,8 +367,8 @@ final class UpgradeConfigService extends Service implements UpgradeConfigService
new Event(
$this,
EventMessage::factory()
- ->addDescription(__u('Update Configuration'))
- ->addDetail(__u('Version'), $version)
+ ->addDescription(__u('Update Configuration'))
+ ->addDetail(__u('Version'), $version)
)
);
}
diff --git a/lib/SP/Domain/Import/Services/LdapImportService.php b/lib/SP/Domain/Import/Services/LdapImportService.php
index e5dabe90..0d631c64 100644
--- a/lib/SP/Domain/Import/Services/LdapImportService.php
+++ b/lib/SP/Domain/Import/Services/LdapImportService.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -30,13 +30,13 @@ use SP\Core\Events\Event;
use SP\Core\Events\EventMessage;
use SP\DataModel\UserData;
use SP\DataModel\UserGroupData;
+use SP\Domain\Auth\Ports\LdapInterface;
use SP\Domain\Common\Services\Service;
use SP\Domain\Import\Ports\LdapImportServiceInterface;
use SP\Domain\User\Ports\UserServiceInterface;
use SP\Domain\User\Services\UserGroupService;
-use SP\Providers\Auth\Ldap\Ldap;
+use SP\Providers\Auth\Ldap\LdapBase;
use SP\Providers\Auth\Ldap\LdapException;
-use SP\Providers\Auth\Ldap\LdapInterface;
use SP\Providers\Auth\Ldap\LdapParams;
/**
@@ -155,7 +155,7 @@ final class LdapImportService extends Service implements LdapImportServiceInterf
*/
protected function getLdap(LdapParams $ldapParams): LdapInterface
{
- return Ldap::factory(
+ return LdapBase::factory(
$ldapParams,
$this->eventDispatcher,
$this->config->getConfigData()->isDebug()
diff --git a/lib/SP/Providers/Auth/AuthDataBase.php b/lib/SP/Providers/Auth/AuthDataBase.php
index c68eecad..3d9a25bb 100644
--- a/lib/SP/Providers/Auth/AuthDataBase.php
+++ b/lib/SP/Providers/Auth/AuthDataBase.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -25,127 +25,78 @@
namespace SP\Providers\Auth;
/**
- * Class AuthData
- *
- * @package Auth
+ * Class AuthDataBase
*/
abstract class AuthDataBase
{
- /**
- * @var string
- */
- protected string $name;
- /**
- * @var string
- */
- protected string $email;
- /**
- * @var bool
- */
- protected ?bool $authenticated;
- /**
- * @var int
- */
- protected int $statusCode = 0;
- /**
- * @var string
- */
- protected string $server;
- /**
- * @var bool
- */
- protected bool $authoritative = false;
- /**
- * @var bool
- */
- protected bool $failed = false;
+ protected ?string $name = null;
+ protected ?string $email = null;
+ protected ?bool $authenticated = null;
+ protected int $statusCode = 0;
+ protected ?string $server = null;
+ protected bool $failed = false;
/**
- * @return string|null
+ * @param bool $authoritative Whether this authentication is required to access to the application
*/
+ public function __construct(private readonly bool $authoritative = false)
+ {
+ }
+
public function getName(): ?string
{
return $this->name;
}
- /**
- * @param string $name
- */
- public function setName(string $name)
+ public function setName(string $name): void
{
$this->name = $name;
}
- /**
- * @return string|null
- */
public function getEmail(): ?string
{
return $this->email;
}
- /**
- * @param string $email
- */
public function setEmail(string $email): void
{
$this->email = $email;
}
- /**
- * @return int|null
- */
public function getAuthenticated(): ?int
{
return $this->authenticated;
}
- /**
- * @param bool $authenticated
- *
- * @return $this
- */
- public function setAuthenticated(?bool $authenticated = null): AuthDataBase
+ public function setAuthenticated(?bool $authenticated = null): static
{
$this->authenticated = $authenticated;
return $this;
}
- /**
- * @return string|null
- */
public function getServer(): ?string
{
return $this->server;
}
- /**
- * @param string $server
- */
- public function setServer(string $server)
+ public function setServer(string $server): void
{
$this->server = $server;
}
- /**
- * @return int
- */
public function getStatusCode(): int
{
- return (int)$this->statusCode;
+ return $this->statusCode;
}
- /**
- * @param int $statusCode
- */
public function setStatusCode(int $statusCode): void
{
$this->statusCode = $statusCode;
}
/**
- * Indica si es requerida para acceder a la aplicación
+ * Whether this authentication is required to access to the application
*
* @return bool
*/
@@ -154,29 +105,13 @@ abstract class AuthDataBase
return $this->authoritative;
}
- /**
- * Indica si es requerida para acceder a la aplicación
- *
- * @param bool $authoritative
- */
- public function setAuthoritative(bool $authoritative): void
- {
- $this->authoritative = $authoritative;
- }
-
- /**
- * @return bool|null
- */
- public function isFailed(): ?bool
+ public function isFailed(): bool
{
return $this->failed;
}
- /**
- * @param bool $failed
- */
- public function setFailed(bool $failed)
+ public function setFailed(bool $failed): void
{
$this->failed = $failed;
}
-}
\ No newline at end of file
+}
diff --git a/lib/SP/Providers/Auth/AuthProvider.php b/lib/SP/Providers/Auth/AuthProvider.php
index 26c4fb5e..ac25ffc6 100644
--- a/lib/SP/Providers/Auth/AuthProvider.php
+++ b/lib/SP/Providers/Auth/AuthProvider.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -27,10 +27,10 @@ namespace SP\Providers\Auth;
use SP\Core\Application;
use SP\Core\Exceptions\SPException;
use SP\DataModel\UserLoginData;
+use SP\Domain\Auth\Ports\LdapAuthInterface;
use SP\Domain\Auth\Services\AuthException;
use SP\Providers\Auth\Browser\BrowserAuthInterface;
use SP\Providers\Auth\Database\DatabaseAuthInterface;
-use SP\Providers\Auth\Ldap\LdapAuthInterface;
use SP\Providers\Provider;
defined('APP_ROOT') || die();
diff --git a/lib/SP/Providers/Auth/AuthProviderInterface.php b/lib/SP/Providers/Auth/AuthProviderInterface.php
index fb4390c7..91133786 100644
--- a/lib/SP/Providers/Auth/AuthProviderInterface.php
+++ b/lib/SP/Providers/Auth/AuthProviderInterface.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -26,9 +26,9 @@ namespace SP\Providers\Auth;
use SP\DataModel\UserLoginData;
+use SP\Domain\Auth\Ports\LdapAuthInterface;
use SP\Domain\Auth\Services\AuthException;
use SP\Providers\Auth\Browser\BrowserAuthInterface;
-use SP\Providers\Auth\Ldap\LdapAuthInterface;
/**
* Class Auth
@@ -58,4 +58,4 @@ interface AuthProviderInterface
public function withLdapAuth(LdapAuthInterface $ldapAuth): void;
public function withBrowserAuth(BrowserAuthInterface $browserAuth): void;
-}
\ No newline at end of file
+}
diff --git a/lib/SP/Providers/Auth/Ldap/Ldap.php b/lib/SP/Providers/Auth/Ldap/Ldap.php
deleted file mode 100644
index a768d526..00000000
--- a/lib/SP/Providers/Auth/Ldap/Ldap.php
+++ /dev/null
@@ -1,174 +0,0 @@
-.
- */
-
-namespace SP\Providers\Auth\Ldap;
-
-use SP\Core\Events\EventDispatcher;
-
-/**
- * Class Ldap
- *
- * @package SP\Providers\Auth\Ldap
- */
-abstract class Ldap implements LdapInterface
-{
- /**
- * @var LdapParams
- */
- protected LdapParams $ldapParams;
- /**
- * @var EventDispatcher
- */
- protected EventDispatcher $eventDispatcher;
- /**
- * @var LdapActions
- */
- protected LdapActions $ldapActions;
- /**
- * @var LdapConnectionInterface
- */
- protected LdapConnectionInterface $ldapConnection;
- /**
- * @var string
- */
- protected string $server;
-
- /**
- * LdapBase constructor.
- *
- * @param LdapConnectionInterface $ldapConnection
- * @param \SP\Providers\Auth\Ldap\LdapActions $ldapActions
- * @param EventDispatcher $eventDispatcher
- */
- public function __construct(
- LdapConnectionInterface $ldapConnection,
- LdapActions $ldapActions,
- EventDispatcher $eventDispatcher
- ) {
- $this->eventDispatcher = $eventDispatcher;
- $this->ldapActions = $ldapActions;
- $this->ldapConnection = $ldapConnection;
- $this->ldapParams = $ldapConnection->getLdapParams();
- $this->server = $this->pickServer();
- $this->ldapConnection->setServer($this->server);
- }
-
- /**
- * Obtener el servidor de LDAP a utilizar
- *
- * @return mixed
- */
- abstract protected function pickServer(): string;
-
- /**
- * @param LdapParams $ldapParams
- * @param EventDispatcher $eventDispatcher
- * @param bool $debug
- *
- * @return LdapInterface
- * @throws LdapException
- */
- public static function factory(
- LdapParams $ldapParams,
- EventDispatcher $eventDispatcher,
- bool $debug
- ): LdapInterface {
- $ldapConnection = new LdapConnection($ldapParams, $eventDispatcher, $debug);
- $ldapConnection->checkConnection();
-
- $ldapActions = new LdapActions($ldapConnection, $eventDispatcher);
-
- switch ($ldapParams->getType()) {
- case LdapTypeInterface::LDAP_STD:
- return new LdapStd($ldapConnection, $ldapActions, $eventDispatcher);
- case LdapTypeInterface::LDAP_ADS:
- return new LdapMsAds($ldapConnection, $ldapActions, $eventDispatcher);
- }
-
- throw new LdapException(__u('LDAP type not set'));
- }
-
- /**
- * @return LdapActions
- */
- public function getLdapActions(): LdapActions
- {
- return $this->ldapActions;
- }
-
- /**
- * Realizar la conexión al servidor de LDAP.
- *
- * @return resource
- * @throws LdapException
- */
- public function connect()
- {
- return $this->ldapConnection->connectAndBind();
- }
-
- /**
- * @param string|null $bindDn
- * @param string|null $bindPass
- *
- * @return bool
- */
- public function bind(?string $bindDn = null, ?string $bindPass = null): bool
- {
- return $this->ldapConnection->bind($bindDn, $bindPass);
- }
-
- /**
- * @return string
- */
- public function getServer(): string
- {
- return $this->server;
- }
-
- /**
- * @return string
- */
- protected function getGroupFromParams(): string
- {
- if (stripos($this->ldapParams->getGroup(), 'cn') === 0) {
- return LdapUtil::getGroupName($this->ldapParams->getGroup()) ?: '';
- }
-
- return $this->ldapParams->getGroup();
- }
-
- /**
- * @return string
- * @throws LdapException
- */
- protected function getGroupDn(): string
- {
- if (stripos($this->ldapParams->getGroup(), 'cn') === 0) {
- return $this->ldapParams->getGroup();
- }
-
- return $this->ldapActions->searchGroupsDn($this->getGroupObjectFilter())[0];
- }
-}
diff --git a/lib/SP/Providers/Auth/Ldap/LdapActions.php b/lib/SP/Providers/Auth/Ldap/LdapActions.php
index 45927ec3..501a9a80 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapActions.php
+++ b/lib/SP/Providers/Auth/Ldap/LdapActions.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -22,26 +22,24 @@
* along with sysPass. If not, see .
*/
-/** @noinspection PhpComposerExtensionStubsInspection */
-
namespace SP\Providers\Auth\Ldap;
+use Laminas\Ldap\Collection;
+use Laminas\Ldap\Exception\LdapException as LaminasLdapException;
+use Laminas\Ldap\Ldap as LaminasLdap;
use SP\Core\Events\Event;
-use SP\Core\Events\EventDispatcher;
+use SP\Core\Events\EventDispatcherInterface;
use SP\Core\Events\EventMessage;
-use SP\Core\Exceptions\SPException;
-
+use SP\Domain\Auth\Ports\LdapActionsInterface;
+use function SP\__u;
/**
* Class LdapActions
*
* @package SP\Providers\Auth\Ldap
*/
-final class LdapActions
+final class LdapActions implements LdapActionsInterface
{
- /**
- * Atributos de búsqueda
- */
public const USER_ATTRIBUTES = [
'dn',
'displayname',
@@ -55,217 +53,176 @@ final class LdapActions
'givenname',
'sn',
'userprincipalname',
- 'cn'
+ 'cn',
];
public const ATTRIBUTES_MAPPING = [
- 'dn' => 'dn',
+ 'dn' => 'dn',
'groupmembership' => 'group',
- 'memberof' => 'group',
- 'displayname' => 'fullname',
- 'fullname' => 'fullname',
- 'givenname' => 'name',
- 'sn' => 'sn',
- 'mail' => 'mail',
- 'lockouttime' => 'expire'
+ 'memberof' => 'group',
+ 'displayname' => 'fullname',
+ 'fullname' => 'fullname',
+ 'givenname' => 'name',
+ 'sn' => 'sn',
+ 'mail' => 'mail',
+ 'lockouttime' => 'expire',
];
/**
- * @var LdapParams
- */
- private LdapParams $ldapParams;
- /**
- * @var resource
- */
- private $ldapHandler;
- /**
- * @var EventDispatcher
- */
- private EventDispatcher $eventDispatcher;
-
- /**
- * LdapActions constructor.
- *
- * @param LdapConnectionInterface $ldapConnection
- * @param EventDispatcher $eventDispatcher
- *
- * @throws LdapException
+ * @param LaminasLdap $ldap
+ * @param LdapParams $ldapParams
+ * @param EventDispatcherInterface $eventDispatcher
*/
public function __construct(
- LdapConnectionInterface $ldapConnection,
- EventDispatcher $eventDispatcher
- )
- {
- $this->ldapHandler = $ldapConnection->connectAndBind();
- $this->ldapParams = $ldapConnection->getLdapParams();
- $this->eventDispatcher = $eventDispatcher;
- }
+ private readonly LaminasLdap $ldap,
+ private readonly LdapParams $ldapParams,
+ private readonly EventDispatcherInterface $eventDispatcher
+ ) {}
/**
* Obtener el RDN del grupo.
*
- * @param string $groupFilter
+ * @param string $groupFilter
*
* @return array Groups' DN
* @throws LdapException
*/
public function searchGroupsDn(string $groupFilter): array
{
- $filter = '(&(cn='
- . ldap_escape($this->getGroupFromParams(), null, LDAP_ESCAPE_FILTER)
- . ')'
- . $groupFilter
- . ')';
+ $group = $this->getGroupFromParams();
+
+ /** @noinspection PhpComposerExtensionStubsInspection */
+ $filter = sprintf(
+ '(&(cn=%s)%s)',
+ ldap_escape(
+ $group,
+ null,
+ LDAP_ESCAPE_FILTER
+ ),
+ $groupFilter
+ );
$searchResults = $this->getResults($filter, ['dn']);
- if ((int)$searchResults['count'] === 0) {
- $this->eventDispatcher->notifyEvent('ldap.search.group',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('Error while searching the group RDN'))
- ->addDetail(__u('Group'), $this->getGroupFromParams())
- ->addDetail('LDAP ERROR', LdapConnection::getLdapErrorMessage($this->ldapHandler))
- ->addDetail('LDAP FILTER', $filter))
+ if ($searchResults->count() === 0) {
+ $this->eventDispatcher->notifyEvent(
+ 'ldap.search.group',
+ new Event(
+ $this,
+ EventMessage::factory()
+ ->addDescription(__u('Error while searching the group RDN'))
+ ->addDetail(__u('Group'), $group)
+ ->addDetail('LDAP ERROR', $this->ldap->getLastError())
+ ->addDetail('LDAP FILTER', $filter)
+ )
);
- throw new LdapException(
+ throw LdapException::error(
__u('Error while searching the group RDN'),
- SPException::ERROR,
null,
- LdapCode::NO_SUCH_OBJECT
+ LdapCodeEnum::NO_SUCH_OBJECT->value
);
}
- return array_filter(array_map(
- static function ($value) {
- if (is_array($value)) {
- return $value['dn'];
- }
+ return array_values(
+ array_filter(
+ array_map(
+ static function ($value) {
+ if (is_array($value)) {
+ return $value['dn'];
+ }
- return null;
- },
- $searchResults)
+ return null;
+ },
+ $searchResults->toArray()
+ )
+ )
);
}
- /**
- * @return string
- */
protected function getGroupFromParams(): string
{
if (stripos($this->ldapParams->getGroup(), 'cn') === 0) {
return LdapUtil::getGroupName($this->ldapParams->getGroup()) ?: '';
}
- return $this->ldapParams->getGroup();
+ return $this->ldapParams->getGroup() ?: '*';
}
/**
- * Devolver los resultados de una paginación
+ * Get LDAP search results as a Collection
*
- * @param string $filter Filtro a utilizar
- * @param array|null $attributes Atributos a devolver
- * @param string|null $searchBase
+ * @param string $filter Filtro a utilizar
+ * @param array|null $attributes Atributos a devolver
+ * @param string|null $searchBase
*
- * @return bool|array
+ * @return Collection
+ * @throws LdapException
*/
protected function getResults(
- string $filter,
- ?array $attributes = null,
+ string $filter,
+ ?array $attributes = [],
?string $searchBase = null
- )
- {
- $cookie = '';
- $results = [];
-
+ ): Collection {
if (empty($searchBase)) {
$searchBase = $this->ldapParams->getSearchBase();
}
- do {
- ldap_control_paged_result(
- $this->ldapHandler,
- LdapInterface::PAGE_SIZE,
- false,
- $cookie
- );
+ try {
+ return $this->ldap->search($filter, $searchBase, LaminasLdap::SEARCH_SCOPE_SUB, $attributes);
+ } catch (LaminasLdapException $e) {
+ $this->eventDispatcher->notifyEvent('exception', new Event($e));
- $searchRes = @ldap_search(
- $this->ldapHandler,
- $searchBase,
- $filter,
- $attributes
- );
-
- if (!$searchRes) {
- return false;
- }
-
- $entries = @ldap_get_entries($this->ldapHandler, $searchRes);
-
- if (!$entries) {
- return false;
- }
-
- $results = array_merge($results, $entries);
-
- ldap_control_paged_result_response(
- $this->ldapHandler,
- $searchRes,
- $cookie
- );
- } while (!empty($cookie));
-
- return $results;
+ throw LdapException::error($e->getMessage(), null, $e->getCode(), $e);
+ }
}
/**
- * Obtener los atributos del usuario.
- *
- * @param string $filter
+ * @param string $filter
*
* @return AttributeCollection
* @throws LdapException
*/
public function getAttributes(string $filter): AttributeCollection
{
- $searchResults = $this->getObjects($filter);
+ $searchResults = $this->getResults($filter)
+ ->getFirst();
- if ((int)$searchResults['count'] === 0) {
- $this->eventDispatcher->notifyEvent('ldap.getAttributes',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('Error while searching the user on LDAP'))
- ->addDetail('LDAP FILTER', $filter))
- );
-
- throw new LdapException(
- __u('Error while searching the user on LDAP'),
- SPException::ERROR,
- null,
- LdapCode::NO_SUCH_OBJECT
- );
+ if ($searchResults === null) {
+ return new AttributeCollection();
}
// Normalize keys for comparing
- $results = array_change_key_case($searchResults[0], CASE_LOWER);
+ $results = array_change_key_case($searchResults);
$attributeCollection = new AttributeCollection();
- foreach (self::ATTRIBUTES_MAPPING as $attribute => $map) {
- if (isset($results[$attribute])) {
- if (is_array($results[$attribute])) {
- if ((int)$results[$attribute]['count'] > 1) {
- unset($results[$attribute]['count']);
+ $attributes = array_filter(
+ self::ATTRIBUTES_MAPPING,
+ fn($attribute) => isset($results[$attribute]),
+ ARRAY_FILTER_USE_KEY
+ );
- // Store the whole array
- $attributeCollection->set($map, $results[$attribute]);
- } else {
- // Store first value
- $attributeCollection->set($map, trim($results[$attribute][0]));
- }
+ foreach ($attributes as $attribute => $map) {
+ if (is_array($results[$attribute])) {
+ if ((int)$results[$attribute]['count'] > 1) {
+ // Store the whole array
+ $attributeCollection->set(
+ $map,
+ array_filter($results[$attribute], fn($key) => $key !== 'count', ARRAY_FILTER_USE_KEY)
+ );
} else {
- $attributeCollection->set($map, trim($results[$attribute]));
+ // Store first value
+ $attributeCollection->set(
+ $map,
+ trim($results[$attribute][0])
+ );
}
+ } else {
+ $attributeCollection->set(
+ $map,
+ trim($results[$attribute])
+ );
}
}
@@ -273,39 +230,26 @@ final class LdapActions
}
/**
- * Obtener los objetos según el filtro indicado
+ * Get LDAP search results as an array
*
- * @param string $filter
- * @param array $attributes
- * @param string|null $searchBase
+ * @param string $filter
+ * @param array $attributes
+ * @param string|null $searchBase
*
* @return array
* @throws LdapException
*/
public function getObjects(
- string $filter,
- array $attributes = self::USER_ATTRIBUTES,
+ string $filter,
+ array $attributes = self::USER_ATTRIBUTES,
?string $searchBase = null
- ): array
+ ): array {
+ return $this->getResults($filter, $attributes, $searchBase)
+ ->toArray();
+ }
+
+ public function mutate(LdapParams $ldapParams): LdapActionsInterface
{
- $searchResults = $this->getResults($filter, $attributes, $searchBase);
-
- if ($searchResults === false) {
- $this->eventDispatcher->notifyEvent('ldap.search',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('Error while searching objects in base DN'))
- ->addDetail('LDAP ERROR', LdapConnection::getLdapErrorMessage($this->ldapHandler))
- ->addDetail('LDAP FILTER', $filter))
- );
-
- throw new LdapException(
- __u('Error while searching objects in base DN'),
- SPException::ERROR,
- null,
- LdapCode::OPERATIONS_ERROR
- );
- }
-
- return $searchResults;
+ return new self($this->ldap, $ldapParams, $this->eventDispatcher);
}
}
diff --git a/lib/SP/Providers/Auth/Ldap/LdapAuth.php b/lib/SP/Providers/Auth/Ldap/LdapAuth.php
index 59ecd867..5447fa74 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapAuth.php
+++ b/lib/SP/Providers/Auth/Ldap/LdapAuth.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -24,10 +24,18 @@
namespace SP\Providers\Auth\Ldap;
+use SP\Core\Events\Event;
use SP\Core\Events\EventDispatcher;
+use SP\Core\Events\EventDispatcherInterface;
+use SP\Core\Events\EventMessage;
use SP\DataModel\UserLoginData;
+use SP\Domain\Auth\Ports\LdapAuthInterface;
+use SP\Domain\Auth\Ports\LdapInterface;
use SP\Domain\Config\Ports\ConfigDataInterface;
+use function SP\__u;
+use function SP\processException;
+
/**
* Class LdapBase
*
@@ -35,30 +43,31 @@ use SP\Domain\Config\Ports\ConfigDataInterface;
*/
final class LdapAuth implements LdapAuthInterface
{
- protected string $userLogin;
- protected LdapAuthData $ldapAuthData;
- protected EventDispatcher $eventDispatcher;
- protected string $server;
- private LdapInterface $ldap;
- private ConfigDataInterface $configData;
+ private readonly LdapAuthData $ldapAuthData;
/**
* LdapBase constructor.
*
- * @param LdapInterface $ldap
- * @param EventDispatcher $eventDispatcher
- * @param \SP\Domain\Config\Ports\ConfigDataInterface $configData
+ * @param LdapInterface $ldap
+ * @param EventDispatcher $eventDispatcher
+ * @param ConfigDataInterface $configData
*/
public function __construct(
- LdapInterface $ldap,
- EventDispatcher $eventDispatcher,
- ConfigDataInterface $configData
+ private readonly LdapInterface $ldap,
+ private readonly EventDispatcherInterface $eventDispatcher,
+ private readonly ConfigDataInterface $configData
) {
- $this->ldap = $ldap;
- $this->eventDispatcher = $eventDispatcher;
- $this->configData = $configData;
+ $this->ldapAuthData = new LdapAuthData($this->isAuthGranted());
+ }
- $this->ldapAuthData = new LdapAuthData();
+ /**
+ * Indica si es requerida para acceder a la aplicación
+ *
+ * @return bool
+ */
+ public function isAuthGranted(): bool
+ {
+ return !$this->configData->isLdapDatabaseEnabled();
}
/**
@@ -69,46 +78,33 @@ final class LdapAuth implements LdapAuthInterface
return $this->ldapAuthData;
}
- /**
- * @return string
- */
- public function getUserLogin(): ?string
- {
- return $this->userLogin;
- }
-
- /**
- * @param string $userLogin
- */
- public function setUserLogin(string $userLogin): void
- {
- $this->userLogin = strtolower($userLogin);
- }
/**
* Autentificar al usuario
*
- * @param UserLoginData $userLoginData Datos del usuario
+ * @param UserLoginData $userLoginData Datos del usuario
*
* @return bool
*/
public function authenticate(UserLoginData $userLoginData): bool
{
try {
- $this->ldapAuthData->setAuthoritative($this->isAuthGranted());
$this->ldapAuthData->setServer($this->ldap->getServer());
- $this->setUserLogin($userLoginData->getLoginUser());
-
$this->ldap->connect();
$this->getAttributes($userLoginData->getLoginUser());
- $this->ldap->bind($this->ldapAuthData->getDn(), $userLoginData->getLoginPass());
+ $this->ldap->connect($this->ldapAuthData->getDn(), $userLoginData->getLoginPass());
+
+ $this->ldapAuthData->setFailed(false);
+ $this->ldapAuthData->setAuthenticated(true);
} catch (LdapException $e) {
processException($e);
$this->ldapAuthData->setStatusCode($e->getCode());
+ $this->ldapAuthData->setAuthenticated(false);
+ $this->ldapAuthData->setFailed(true);
return false;
}
@@ -116,36 +112,43 @@ final class LdapAuth implements LdapAuthInterface
return true;
}
- /**
- * Indica si es requerida para acceder a la aplicación
- *
- * @return boolean
- */
- public function isAuthGranted(): bool
- {
- return !$this->configData->isLdapDatabaseEnabled();
- }
-
/**
* Obtener los atributos del usuario.
*
- * @param string $userLogin
+ * @param string $userLogin
*
- * @return LdapAuthData con los atributos disponibles y sus valores
+ * @return void con los atributos disponibles y sus valores
* @throws LdapException
*/
- public function getAttributes(string $userLogin): LdapAuthData
+ private function getAttributes(string $userLogin): void
{
- $attributes = $this->ldap->getLdapActions()
- ->getAttributes($this->ldap->getUserDnFilter($userLogin));
+ $filter = $this->ldap->getUserDnFilter($userLogin);
+ $attributes = $this->ldap->getLdapActions()->getAttributes($filter);
+
+ if ($attributes->count() === 0) {
+ $this->eventDispatcher->notifyEvent(
+ 'ldap.getAttributes',
+ new Event(
+ $this,
+ EventMessage::factory()->addDescription(__u('Error while searching the user on LDAP'))->addDetail(
+ 'LDAP FILTER',
+ $filter
+ )
+ )
+ );
+
+ throw LdapException::error(
+ __u('Error while searching the user on LDAP'),
+ null,
+ LdapCodeEnum::NO_SUCH_OBJECT->value
+ );
+ }
if (!empty($attributes->get('fullname'))) {
$this->ldapAuthData->setName($attributes->get('fullname'));
} else {
$name = trim(
- $attributes->get('name', '')
- .' '
- .$attributes->get('sn', '')
+ $attributes->get('name', '') . ' ' . $attributes->get('sn', '')
);
$this->ldapAuthData->setName($name);
@@ -167,7 +170,5 @@ final class LdapAuth implements LdapAuthInterface
(array)$attributes->get('group')
)
);
-
- return $this->ldapAuthData;
}
}
diff --git a/lib/SP/Providers/Auth/Ldap/LdapAuthData.php b/lib/SP/Providers/Auth/Ldap/LdapAuthData.php
index 0802d746..0d29ba4b 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapAuthData.php
+++ b/lib/SP/Providers/Auth/Ldap/LdapAuthData.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -33,84 +33,37 @@ use SP\Providers\Auth\AuthDataBase;
*/
final class LdapAuthData extends AuthDataBase
{
- /**
- * @var string
- */
- protected string $dn;
- /**
- * @var string
- */
- protected string $groupDn;
- /**
- * @var int
- */
- protected int $expire = 0;
- /**
- * @var bool
- */
- protected bool $inGroup = false;
+ protected ?string $dn = null;
+ protected int $expire = 0;
+ protected bool $inGroup = false;
- /**
- * @return string
- */
public function getDn(): ?string
{
return $this->dn;
}
- /**
- * @param string $dn
- */
public function setDn(string $dn): void
{
$this->dn = $dn;
}
- /**
- * @return int
- */
public function getExpire(): int
{
return $this->expire;
}
- /**
- * @param int $expire
- */
public function setExpire(int $expire): void
{
$this->expire = $expire;
}
- /**
- * @return boolean
- */
public function isInGroup(): bool
{
return $this->inGroup;
}
- /**
- * @param boolean $inGroup
- */
public function setInGroup(bool $inGroup): void
{
$this->inGroup = $inGroup;
}
-
- /**
- * @return string
- */
- public function getGroupDn(): ?string
- {
- return $this->groupDn;
- }
-
- /**
- * @param string $groupDn
- */
- public function setGroupDn(string $groupDn): void
- {
- $this->groupDn = $groupDn;
- }
-}
\ No newline at end of file
+}
diff --git a/lib/SP/Providers/Auth/Ldap/LdapBase.php b/lib/SP/Providers/Auth/Ldap/LdapBase.php
new file mode 100644
index 00000000..79339572
--- /dev/null
+++ b/lib/SP/Providers/Auth/Ldap/LdapBase.php
@@ -0,0 +1,140 @@
+.
+ */
+
+namespace SP\Providers\Auth\Ldap;
+
+use Exception;
+use SP\Core\Events\EventDispatcher;
+use SP\Core\Events\EventDispatcherInterface;
+use SP\Domain\Auth\Ports\LdapActionsInterface;
+use SP\Domain\Auth\Ports\LdapConnectionInterface;
+use SP\Domain\Auth\Ports\LdapInterface;
+
+use function SP\__u;
+
+/**
+ * Class LdapBase
+ *
+ * @package SP\Providers\Auth\Ldap
+ */
+abstract class LdapBase implements LdapInterface
+{
+ protected string $server;
+
+ /**
+ * LdapBase constructor.
+ *
+ * @param LdapConnectionInterface $ldapConnection
+ * @param LdapActionsInterface $ldapActions
+ * @param LdapParams $ldapParams
+ * @param EventDispatcher $eventDispatcher
+ */
+ public function __construct(
+ protected readonly LdapConnectionInterface $ldapConnection,
+ protected readonly LdapActionsInterface $ldapActions,
+ protected readonly LdapParams $ldapParams,
+ protected readonly EventDispatcherInterface $eventDispatcher
+ ) {
+ $this->server = $this->pickServer();
+ }
+
+ abstract protected function pickServer(): string;
+
+ /**
+ * @param EventDispatcher $eventDispatcher
+ * @param LdapConnectionInterface $ldapConnection
+ * @param LdapActionsInterface $ldapActions
+ * @param LdapParams|null $ldapParams
+ * @return LdapInterface
+ * @throws LdapException
+ * @throws Exception
+ */
+ public static function factory(
+ EventDispatcherInterface $eventDispatcher,
+ LdapConnectionInterface $ldapConnection,
+ LdapActionsInterface $ldapActions,
+ ?LdapParams $ldapParams = null
+ ): LdapInterface {
+ if (null !== $ldapParams) {
+ $ldapConnection = $ldapConnection->mutate($ldapParams);
+ $ldapActions = $ldapActions->mutate($ldapParams);
+ }
+
+ $ldapConnection->checkConnection();
+
+ switch ($ldapParams->getType()) {
+ case LdapTypeEnum::STD:
+ return new LdapStd($ldapConnection, $ldapActions, $ldapParams, $eventDispatcher);
+ case LdapTypeEnum::ADS:
+ return new LdapMsAds($ldapConnection, $ldapActions, $ldapParams, $eventDispatcher);
+ case LdapTypeEnum::AZURE:
+ throw new LdapException(__u('To be implemented'));
+ }
+
+ throw LdapException::error(__u('LDAP type not set'));
+ }
+
+ public function getLdapActions(): LdapActionsInterface
+ {
+ return $this->ldapActions;
+ }
+
+ /**
+ * @throws LdapException
+ */
+ public function connect(?string $bindDn = null, ?string $bindPass = null): void
+ {
+ $this->ldapConnection->connect($bindDn, $bindPass);
+ }
+
+ public function getServer(): string
+ {
+ return $this->server;
+ }
+
+ /**
+ * @return string
+ */
+ protected function getGroupFromParams(): string
+ {
+ if (stripos($this->ldapParams->getGroup(), 'cn') === 0) {
+ return LdapUtil::getGroupName($this->ldapParams->getGroup()) ?: '';
+ }
+
+ return $this->ldapParams->getGroup();
+ }
+
+ /**
+ * @return string
+ * @throws LdapException
+ */
+ protected function getGroupDn(): string
+ {
+ if (stripos($this->ldapParams->getGroup(), 'cn') === 0) {
+ return $this->ldapParams->getGroup();
+ }
+
+ return $this->ldapActions->searchGroupsDn($this->getGroupObjectFilter())[0];
+ }
+}
diff --git a/lib/SP/Providers/Auth/Ldap/LdapCode.php b/lib/SP/Providers/Auth/Ldap/LdapCodeEnum.php
similarity index 62%
rename from lib/SP/Providers/Auth/Ldap/LdapCode.php
rename to lib/SP/Providers/Auth/Ldap/LdapCodeEnum.php
index 61de34ce..830856ed 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapCode.php
+++ b/lib/SP/Providers/Auth/Ldap/LdapCodeEnum.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -24,20 +24,17 @@
namespace SP\Providers\Auth\Ldap;
-
/**
- * Interface LdapCode
- *
- * @package SP\Providers\Auth\Ldap
+ * Class LdapCodeEnum
*/
-interface LdapCode
+enum LdapCodeEnum: int
{
- public const SUCCESS = 0;
- public const OPERATIONS_ERROR = 1;
- public const AUTH_METHOD_NOT_SUPPORTED = 7;
- public const STRONGER_AUTH_REQUIRED = 8;
- public const CONFIDENTIALITY_REQUIRED = 13;
- public const NO_SUCH_OBJECT = 32;
- public const INVALID_CREDENTIALS = 49;
- public const FILTER_ERROR = 87;
-}
\ No newline at end of file
+ case SUCCESS = 0;
+ case OPERATIONS_ERROR = 1;
+ case AUTH_METHOD_NOT_SUPPORTED = 7;
+ case STRONGER_AUTH_REQUIRED = 8;
+ case CONFIDENTIALITY_REQUIRED = 13;
+ case NO_SUCH_OBJECT = 32;
+ case INVALID_CREDENTIALS = 49;
+ case FILTER_ERROR = 87;
+}
diff --git a/lib/SP/Providers/Auth/Ldap/LdapConnection.php b/lib/SP/Providers/Auth/Ldap/LdapConnection.php
index 2aa59a7f..201052e2 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapConnection.php
+++ b/lib/SP/Providers/Auth/Ldap/LdapConnection.php
@@ -1,9 +1,10 @@
-setUp();
+ }
+
+ /**
+ * @throws LdapException
+ */
+ private function setUp(): void
{
- $this->ldapParams = $ldapParams;
- $this->eventDispatcher = $eventDispatcher;
- $this->debug = $debug;
+ if ($this->debug) {
+ @ldap_set_option(
+ null,
+ LDAP_OPT_DEBUG_LEVEL,
+ 7
+ );
+ }
+
+ try {
+ $this->ldap->setOptions([
+ 'host' => $this->ldapParams->getPort(),
+ 'port' => $this->ldapParams->getPort(),
+ 'useStartTls' => $this->ldapParams->isTlsEnabled(),
+ 'username' => $this->ldapParams->getBindDn(),
+ 'password' => $this->ldapParams->getBindPass(),
+ 'networkTimeout' => self::TIMEOUT_SECONDS,
+ 'reconnectAttempts' => self::RECONNECT_ATTEMPTS,
+ ]);
+ } catch (LaminasLdapException $e) {
+ throw LdapException::error($e->getMessage(), null, $e->getCode(), $e);
+ }
+ }
+
+ /**
+ * @throws LdapException
+ */
+ public function mutate(LdapParams $ldapParams): LdapConnectionInterface
+ {
+ return new self($this->ldap, $ldapParams, $this->eventDispatcher, $this->debug);
}
/**
@@ -76,264 +100,57 @@ final class LdapConnection implements LdapConnectionInterface
*/
public function checkConnection(): void
{
+ $this->connect();
- $this->connectAndBind();
-
- $this->eventDispatcher->notifyEvent('ldap.check.connection',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('LDAP connection OK')))
+ $this->eventDispatcher->notifyEvent(
+ 'ldap.check.connection',
+ new Event(
+ $this,
+ EventMessage::factory()
+ ->addDescription(__u('LDAP connection OK'))
+ )
);
}
/**
- * @return resource
- * @throws LdapException
- */
- public function connectAndBind()
- {
- if (!$this->isConnected && !$this->isBound) {
- $this->isConnected = $this->connect();
- $this->isBound = $this->bind();
- }
-
- return $this->ldapHandler;
- }
-
- /**
- * Realizar la conexión al servidor de LDAP.
+ * Connects to LDAP server using authentication
*
- * @return bool
- * @throws LdapException
- */
- public function connect(): bool
- {
- if ($this->isConnected) {
- return true;
- }
-
- $this->checkParams();
-
- // Habilitar la traza si el modo debug está habilitado
- if ($this->debug) {
- @ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
- }
-
- $this->ldapHandler = @ldap_connect($this->getServerUri());
-
- // Conexión al servidor LDAP
- if (!is_resource($this->ldapHandler)) {
- $this->eventDispatcher->notifyEvent('ldap.connect',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('Unable to connect to LDAP server'))
- ->addDetail(__u('Server'), $this->getServer()))
- );
-
- throw new LdapException(__u('Unable to connect to LDAP server'));
- }
-
- @ldap_set_option($this->ldapHandler, LDAP_OPT_NETWORK_TIMEOUT, self::TIMEOUT);
- @ldap_set_option($this->ldapHandler, LDAP_OPT_PROTOCOL_VERSION, 3);
- @ldap_set_option($this->ldapHandler, LDAP_OPT_REFERRALS, 0);
-
- $this->isTls = $this->connectTls();
-
- return true;
- }
-
- /**
- * Comprobar si los parámetros necesario de LDAP están establecidos.
- *
- * @throws LdapException
- */
- public function checkParams(): bool
- {
- if (empty($this->ldapParams->getSearchBase())
- || empty($this->getServer())
- || empty($this->ldapParams->getBindDn())
- ) {
- $this->eventDispatcher->notifyEvent('ldap.check.params',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('LDAP parameters are not set'))));
-
- throw new LdapException(__u('LDAP parameters are not set'));
- }
-
- return true;
- }
-
- /**
- * @return string
- */
- public function getServer(): string
- {
- return $this->server ?: $this->ldapParams->getServer();
- }
-
- /**
- * @param string $server
- *
- * @return LdapConnection
- */
- public function setServer(string $server): LdapConnectionInterface
- {
- $this->server = $server;
-
- return $this;
- }
-
- public function getServerUri(): string
- {
- $server = $this->getServer();
- $port = $this->ldapParams->getPort();
-
- if (strpos($server, '://') !== false) {
- return $server . ':' . $port;
- }
-
- if ($port === 389) {
- return 'ldap://' . $server;
- }
-
- if ($port === 636) {
- return 'ldaps://' . $server;
- }
-
- return 'ldap://' . $server . ':' . $port;
- }
-
- /**
- * Connect through TLS
- *
- * @throws LdapException
- */
- private function connectTls(): bool
- {
- if ($this->ldapParams->isTlsEnabled()) {
- $result = @ldap_start_tls($this->ldapHandler);
-
- if ($result === false) {
- $this->eventDispatcher->notifyEvent('ldap.connect.tls',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('Unable to connect to LDAP server'))
- ->addDetail(__u('Server'), $this->getServer())
- ->addDetail('TLS', __u('ON'))
- ->addDetail('LDAP ERROR', self::getLdapErrorMessage($this->ldapHandler))));
-
- throw new LdapException(__u('Unable to connect to LDAP server'));
- }
-
- return true;
- }
-
- return false;
- }
-
- /**
- * Registrar error de LDAP y devolver el mensaje de error
- *
- * @param resource $ldapHandler
- *
- * @return string
- */
- public static function getLdapErrorMessage($ldapHandler): string
- {
- return sprintf('%s (%d)', ldap_error($ldapHandler), ldap_errno($ldapHandler));
- }
-
- /**
- * Realizar la autentificación con el servidor de LDAP.
- *
- * @param string|null $bindDn con el DN del usuario
+ * @param string|null $bindDn con el DN del usuario
* @param string|null $bindPass con la clave del usuario
*
- * @return bool
* @throws LdapException
*/
- public function bind(string $bindDn = null, string $bindPass = null): bool
- {
- $dn = $bindDn ?: $this->ldapParams->getBindDn();
- $pass = $bindPass ?: $this->ldapParams->getBindPass();
+ public function connect(
+ ?string $bindDn = null,
+ ?string $bindPass = null
+ ): void {
+ $username = $bindDn ?: $this->ldapParams->getBindDn();
+ $password = $bindPass ?: $this->ldapParams->getBindPass();
- if (@ldap_bind($this->ldapHandler, $dn, $pass) === false) {
- $this->eventDispatcher->notifyEvent('ldap.bind',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('Connection error (BIND)'))
- ->addDetail('LDAP ERROR', self::getLdapErrorMessage($this->ldapHandler))
- ->addDetail('LDAP DN', $dn))
+ try {
+ $this->ldap->bind(
+ $username,
+ $password
+ );
+ } catch (LaminasLdapException $e) {
+ $this->eventDispatcher->notifyEvent('exception', new Event($e));
+
+ $this->eventDispatcher->notifyEvent(
+ 'ldap.bind',
+ new Event(
+ $this,
+ EventMessage::factory()
+ ->addDescription(__u('LDAP connection error'))
+ ->addDetail('LDAP ERROR', $this->ldap->getLastError())
+ ->addDetail('LDAP DN', $username)
+ )
);
- throw new LdapException(
- __u('Connection error (BIND)'),
- SPException::ERROR,
- self::getLdapErrorMessage($this->ldapHandler),
- $this->getErrorCode()
+ throw LdapException::error(
+ __u('LDAP connection error'),
+ $this->ldap->getLastError(),
+ $this->ldap->getLastErrorCode()
);
}
-
- return true;
}
-
- /**
- * @return int
- */
- public function getErrorCode(): int
- {
- if (is_resource($this->ldapHandler)) {
- return ldap_errno($this->ldapHandler);
- }
-
- return -1;
- }
-
- /**
- * @return bool
- */
- public function isConnected(): bool
- {
- return $this->isConnected;
- }
-
- /**
- * @return bool
- */
- public function isBound(): bool
- {
- return $this->isBound;
- }
-
- /**
- * @return LdapParams
- */
- public function getLdapParams(): LdapParams
- {
- return $this->ldapParams;
- }
-
- /**
- * @return bool
- */
- public function isDebug(): bool
- {
- return $this->debug;
- }
-
- /**
- * Realizar la desconexión del servidor de LDAP.
- */
- public function unbind(): bool
- {
- if (($this->isConnected || $this->isBound)
- && @ldap_unbind($this->ldapHandler) === false
- ) {
- $this->eventDispatcher->notifyEvent('ldap.unbind',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('Error while disconnecting from LDAP server'))
- ->addDetail('LDAP ERROR', self::getLdapErrorMessage($this->ldapHandler)))
- );
-
- return false;
- }
-
- return true;
- }
-}
\ No newline at end of file
+}
diff --git a/lib/SP/Providers/Auth/Ldap/LdapConnectionInterface.php b/lib/SP/Providers/Auth/Ldap/LdapConnectionInterface.php
deleted file mode 100644
index c8d698e8..00000000
--- a/lib/SP/Providers/Auth/Ldap/LdapConnectionInterface.php
+++ /dev/null
@@ -1,89 +0,0 @@
-.
- */
-
-namespace SP\Providers\Auth\Ldap;
-
-/**
- * Interface LdapInterface
- *
- * @package Auth\Ldap
- */
-interface LdapConnectionInterface
-{
- /**
- * Comprobar la conexión al servidor de LDAP.
- */
- public function checkConnection(): void;
-
- /**
- * Comprobar si los parámetros necesarios de LDAP están establecidos.
- *
- * @return bool
- */
- public function checkParams(): bool;
-
- /**
- * @return resource
- * @throws LdapException
- */
- public function connectAndBind();
-
- /**
- * Realizar la conexión al servidor de LDAP.
- *
- * @return bool
- * @throws LdapException
- */
- public function connect(): bool;
-
- /**
- * @param string|null $bindDn
- * @param string|null $bindPass
- *
- * @return bool
- */
- public function bind(?string $bindDn = null, ?string $bindPass = null): bool;
-
- /**
- * @return bool
- */
- public function unbind(): bool;
-
- /**
- * @return LdapParams
- */
- public function getLdapParams(): LdapParams;
-
- /**
- * @return string
- */
- public function getServer(): string;
-
- /**
- * @param string $server
- *
- * @return LdapConnectionInterface
- */
- public function setServer(string $server): LdapConnectionInterface;
-}
\ No newline at end of file
diff --git a/lib/SP/Providers/Auth/Ldap/LdapMsAds.php b/lib/SP/Providers/Auth/Ldap/LdapMsAds.php
index a87d250a..bf0aa0ea 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapMsAds.php
+++ b/lib/SP/Providers/Auth/Ldap/LdapMsAds.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -29,6 +29,9 @@ use SP\Core\Events\EventMessage;
use SP\Core\Exceptions\SPException;
use SP\Http\Address;
+use function SP\__u;
+use function SP\logger;
+
/**
* Class LdapAds
*
@@ -36,11 +39,11 @@ use SP\Http\Address;
*
* @package SP\Auth\Ldap
*/
-final class LdapMsAds extends Ldap
+final class LdapMsAds extends LdapBase
{
- public const DEFAULT_FILTER_USER_OBJECT = '(&(!(UserAccountControl:1.2.840.113556.1.4.804:=32))(|(objectCategory=person)(objectClass=user)))';
- public const DEFAULT_FILTER_GROUP_OBJECT = '(objectCategory=group)';
- public const DEFAULT_FILTER_USER_ATTRIBUTES = ['samaccountname', 'cn', 'uid', 'userPrincipalName'];
+ public const DEFAULT_FILTER_USER_OBJECT = '(&(!(UserAccountControl:1.2.840.113556.1.4.804:=32))(|(objectCategory=person)(objectClass=user)))';
+ public const DEFAULT_FILTER_GROUP_OBJECT = '(objectCategory=group)';
+ public const DEFAULT_FILTER_USER_ATTRIBUTES = ['samaccountname', 'cn', 'uid', 'userPrincipalName'];
public const DEFAULT_FILTER_GROUP_ATTRIBUTES = ['memberOf', 'groupMembership', 'memberof:1.2.840.113556.1.4.1941:'];
/**
@@ -61,13 +64,7 @@ final class LdapMsAds extends Ldap
$attributes = $this->ldapParams->getFilterGroupAttributes();
}
- return '(&(|'
- . LdapUtil::getAttributesForFilter(
- $attributes,
- $this->getGroupDn())
- . ')'
- . $filter
- . ')';
+ return '(&(|' . LdapUtil::getAttributesForFilter($attributes, $this->getGroupDn()) . ')' . $filter . ')';
}
/**
@@ -94,10 +91,10 @@ final class LdapMsAds extends Ldap
}
return '(&(|'
- . LdapUtil::getAttributesForFilter($attributes, $userLogin)
- . ')'
- . $this->getUserObjectFilter()
- . ')';
+ . LdapUtil::getAttributesForFilter($attributes, $userLogin)
+ . ')'
+ . $this->getUserObjectFilter()
+ . ')';
}
/**
@@ -124,11 +121,16 @@ final class LdapMsAds extends Ldap
|| $this->ldapParams->getGroup() === '*'
|| in_array($this->getGroupDn(), $groupsDn, true)
) {
- $this->eventDispatcher->notifyEvent('ldap.check.group',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('User in group verified'))
- ->addDetail(__u('User'), $userLogin)
- ->addDetail(__u('Group'), $this->ldapParams->getGroup())));
+ $this->eventDispatcher->notifyEvent(
+ 'ldap.check.group',
+ new Event(
+ $this,
+ EventMessage::factory()
+ ->addDescription(__u('User in group verified'))
+ ->addDetail(__u('User'), $userLogin)
+ ->addDetail(__u('Group'), $this->ldapParams->getGroup())
+ )
+ );
return true;
}
@@ -153,21 +155,31 @@ final class LdapMsAds extends Ldap
if (isset($searchResults['count'])
&& (int)$searchResults['count'] === 0
) {
- $this->eventDispatcher->notifyEvent('ldap.check.group',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('User does not belong to the group'))
- ->addDetail(__u('User'), $userLogin)
- ->addDetail(__u('Group'), $groupDn)
- ->addDetail('LDAP FILTER', $filter)));
+ $this->eventDispatcher->notifyEvent(
+ 'ldap.check.group',
+ new Event(
+ $this,
+ EventMessage::factory()
+ ->addDescription(__u('User does not belong to the group'))
+ ->addDetail(__u('User'), $userLogin)
+ ->addDetail(__u('Group'), $groupDn)
+ ->addDetail('LDAP FILTER', $filter)
+ )
+ );
return false;
}
- $this->eventDispatcher->notifyEvent('ldap.check.group',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('User in group verified'))
- ->addDetail(__u('User'), $userLogin)
- ->addDetail(__u('Group'), $groupDn)));
+ $this->eventDispatcher->notifyEvent(
+ 'ldap.check.group',
+ new Event(
+ $this,
+ EventMessage::factory()
+ ->addDescription(__u('User in group verified'))
+ ->addDetail(__u('User'), $userLogin)
+ ->addDetail(__u('Group'), $groupDn)
+ )
+ );
return true;
}
@@ -185,13 +197,10 @@ final class LdapMsAds extends Ldap
}
return '(|'
- . LdapUtil::getAttributesForFilter($attributes, $this->getGroupDn())
- . ')';
+ . LdapUtil::getAttributesForFilter($attributes, $this->getGroupDn())
+ . ')';
}
- /**
- * @inheritDoc
- */
protected function pickServer(): string
{
$server = $this->ldapParams->getServer();
diff --git a/lib/SP/Providers/Auth/Ldap/LdapParams.php b/lib/SP/Providers/Auth/Ldap/LdapParams.php
index b826a032..a57fdc65 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapParams.php
+++ b/lib/SP/Providers/Auth/Ldap/LdapParams.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -27,6 +27,8 @@ namespace SP\Providers\Auth\Ldap;
use SP\Core\Exceptions\ValidationException;
use SP\Domain\Config\Ports\ConfigDataInterface;
+use function SP\__u;
+
/**
* Class LdapParams
*
@@ -36,74 +38,44 @@ final class LdapParams
{
private const REGEX_SERVER = '(?(?:(?ldap|ldaps):\/\/)?[\w\.\-]+)(?::(?\d+))?';
- /**
- * @var string
- */
- protected string $server;
- /**
- * @var int
- */
- protected int $port = 389;
- /**
- * @var string
- */
- protected string $searchBase;
- /**
- * @var string
- */
- protected string $bindDn;
- /**
- * @var string
- */
- protected string $bindPass;
- /**
- * @var string
- */
- protected string $group;
- /**
- * @var int
- */
- protected int $type;
- /**
- * @var bool
- */
- protected bool $tlsEnabled = false;
- /**
- * @var string
- */
- protected string $filterUserObject;
- /**
- * @var string
- */
- protected string $filterGroupObject;
- /**
- * @var array
- */
- protected array $filterUserAttributes;
- /**
- * @var array
- */
- protected array $filterGroupAttributes;
+ private int $port = 389;
+ private ?string $searchBase = null;
+ private ?string $group = null;
+ private bool $tlsEnabled = false;
+ private ?string $filterUserObject = null;
+ private ?string $filterGroupObject = null;
+ private ?array $filterUserAttributes = null;
+ private ?array $filterGroupAttributes = null;
+
+ public function __construct(
+ private readonly string $server,
+ private readonly LdapTypeEnum $type,
+ private readonly string $bindDn,
+ private readonly string $bindPass
+ ) {
+ }
/**
- * @throws \SP\Core\Exceptions\ValidationException
+ * @throws ValidationException
*/
public static function getFrom(ConfigDataInterface $configData): LdapParams
{
$data = self::getServerAndPort($configData->getLdapServer());
if (count($data) === 0) {
- throw new ValidationException(__u('Wrong LDAP parameters'));
+ throw ValidationException::error(__u('Wrong LDAP parameters'));
}
- $ldapParams = new self();
- $ldapParams->setServer($data['server']);
+ $ldapParams = new self(
+ $data['server'],
+ LdapTypeEnum::from($configData->getLdapType()),
+ $configData->getLdapBindUser(),
+ $configData->getLdapBindPass()
+ );
+
$ldapParams->setPort($data['port'] ?? 389);
$ldapParams->setSearchBase($configData->getLdapBase());
$ldapParams->setGroup($configData->getLdapGroup());
- $ldapParams->setBindDn($configData->getLdapBindUser());
- $ldapParams->setBindPass($configData->getLdapBindPass());
- $ldapParams->setType($configData->getLdapType());
$ldapParams->setFilterUserObject($configData->getLdapFilterUserObject());
$ldapParams->setFilterGroupObject($configData->getLdapFilterGroupObject());
$ldapParams->setFilterUserAttributes($configData->getLdapFilterUserAttributes());
@@ -122,23 +94,17 @@ final class LdapParams
public static function getServerAndPort($server): array
{
return preg_match(
- '#'.self::REGEX_SERVER.'#i',
+ '#' . self::REGEX_SERVER . '#i',
$server,
$matches
) ? $matches : [];
}
- /**
- * @return string
- */
public function getFilterUserObject(): ?string
{
return $this->filterUserObject;
}
- /**
- * @param string|null $filterUserObject
- */
public function setFilterUserObject(?string $filterUserObject = null): void
{
if (!empty($filterUserObject)) {
@@ -146,17 +112,11 @@ final class LdapParams
}
}
- /**
- * @return string
- */
public function getFilterGroupObject(): ?string
{
return $this->filterGroupObject;
}
- /**
- * @param string|null $filterGroupObject
- */
public function setFilterGroupObject(?string $filterGroupObject = null): void
{
if (!empty($filterGroupObject)) {
@@ -164,51 +124,31 @@ final class LdapParams
}
}
- /**
- * @return array
- */
public function getFilterUserAttributes(): ?array
{
return $this->filterUserAttributes;
}
- /**
- * @param array|null $filterUserAttributes
- */
public function setFilterUserAttributes(?array $filterUserAttributes = null): void
{
$this->filterUserAttributes = $filterUserAttributes;
}
- /**
- * @return array
- */
public function getFilterGroupAttributes(): ?array
{
return $this->filterGroupAttributes;
}
- /**
- * @param array|null $filterGroupAttributes
- */
public function setFilterGroupAttributes(?array $filterGroupAttributes = null): void
{
$this->filterGroupAttributes = $filterGroupAttributes;
}
- /**
- * @return int
- */
public function getPort(): int
{
return $this->port;
}
- /**
- * @param int $port
- *
- * @return LdapParams
- */
public function setPort(int $port): LdapParams
{
$this->port = $port;
@@ -216,19 +156,11 @@ final class LdapParams
return $this;
}
- /**
- * @return string
- */
public function getSearchBase(): ?string
{
return $this->searchBase;
}
- /**
- * @param string $searchBase
- *
- * @return LdapParams
- */
public function setSearchBase(string $searchBase): LdapParams
{
$this->searchBase = $searchBase;
@@ -236,59 +168,21 @@ final class LdapParams
return $this;
}
- /**
- * @return string
- */
public function getBindDn(): ?string
{
return $this->bindDn;
}
- /**
- * @param string $bindDn
- *
- * @return LdapParams
- */
- public function setBindDn(string $bindDn): LdapParams
- {
- $this->bindDn = $bindDn;
-
- return $this;
- }
-
- /**
- * @return string
- */
public function getBindPass(): ?string
{
return $this->bindPass;
}
- /**
- * @param string $bindPass
- *
- * @return LdapParams
- */
- public function setBindPass(string $bindPass): LdapParams
- {
- $this->bindPass = $bindPass;
-
- return $this;
- }
-
- /**
- * @return string
- */
public function getGroup(): ?string
{
return $this->group;
}
- /**
- * @param string $group
- *
- * @return LdapParams
- */
public function setGroup(string $group): LdapParams
{
$this->group = $group;
@@ -296,59 +190,21 @@ final class LdapParams
return $this;
}
- /**
- * @return string|null
- */
public function getServer(): ?string
{
return $this->server;
}
- /**
- * @param string $server
- *
- * @return LdapParams
- */
- public function setServer(string $server): LdapParams
- {
- $this->server = $server;
-
- return $this;
- }
-
- /**
- * @return int
- */
- public function getType(): ?int
+ public function getType(): LdapTypeEnum
{
return $this->type;
}
- /**
- * @param int $type
- *
- * @return LdapParams
- */
- public function setType(int $type): LdapParams
- {
- $this->type = $type;
-
- return $this;
- }
-
- /**
- * @return bool
- */
public function isTlsEnabled(): bool
{
return $this->tlsEnabled;
}
- /**
- * @param bool $tlsEnabled
- *
- * @return LdapParams
- */
public function setTlsEnabled(bool $tlsEnabled): LdapParams
{
$this->tlsEnabled = $tlsEnabled;
diff --git a/lib/SP/Providers/Auth/Ldap/LdapStd.php b/lib/SP/Providers/Auth/Ldap/LdapStd.php
index cf14806c..680a7baf 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapStd.php
+++ b/lib/SP/Providers/Auth/Ldap/LdapStd.php
@@ -1,9 +1,10 @@
-ldapParams->getFilterGroupAttributes();
}
- return '(&(|'
- . LdapUtil::getAttributesForFilter(
- $attributes,
- $this->getGroupDn())
- . ')' . $filter
- . ')';
+ return '(&(|' . LdapUtil::getAttributesForFilter($attributes, $this->getGroupDn()) . ')' . $filter . ')';
}
/**
@@ -93,11 +91,7 @@ final class LdapStd extends Ldap
$filter = $this->getUserObjectFilter();
- return '(&(|'
- . LdapUtil::getAttributesForFilter($attributes, $userLogin)
- . ')'
- . $filter
- . ')';
+ return '(&(|' . LdapUtil::getAttributesForFilter($attributes, $userLogin) . ')' . $filter . ')';
}
/**
@@ -110,13 +104,20 @@ final class LdapStd extends Ldap
// los grupos del usuario
if (empty($this->ldapParams->getGroup())
|| $this->ldapParams->getGroup() === '*'
- || in_array($this->getGroupDn(), $groupsDn, true)
- ) {
- $this->eventDispatcher->notifyEvent('ldap.check.group',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('User in group verified'))
- ->addDetail(__u('User'), $userDn)
- ->addDetail(__u('Group'), $this->ldapParams->getGroup())));
+ || in_array($this->getGroupDn(), $groupsDn, true)) {
+ $this->eventDispatcher->notifyEvent(
+ 'ldap.check.group',
+ new Event(
+ $this,
+ EventMessage::factory()
+ ->addDescription(__u('User in group verified'))
+ ->addDetail(
+ __u('User'),
+ $userDn
+ )
+ ->addDetail(__u('Group'), $this->ldapParams->getGroup())
+ )
+ );
return true;
}
@@ -136,15 +137,24 @@ final class LdapStd extends Ldap
$searchResults = $this->ldapActions->getObjects($filter, ['dn']);
- if (isset($searchResults['count'])
- && (int)$searchResults['count'] === 0
- ) {
- $this->eventDispatcher->notifyEvent('ldap.check.group',
- new Event($this, EventMessage::factory()
- ->addDescription(__u('User does not belong to the group'))
- ->addDetail(__u('User'), $userDn)
- ->addDetail(__u('Group'), $this->getGroupFromParams())
- ->addDetail('LDAP FILTER', $filter)));
+ if (isset($searchResults['count']) && (int)$searchResults['count'] === 0) {
+ $this->eventDispatcher->notifyEvent(
+ 'ldap.check.group',
+ new Event(
+ $this,
+ EventMessage::factory()
+ ->addDescription(__u('User does not belong to the group'))
+ ->addDetail(
+ __u('User'),
+ $userDn
+ )
+ ->addDetail(__u('Group'), $this->getGroupFromParams())
+ ->addDetail(
+ 'LDAP FILTER',
+ $filter
+ )
+ )
+ );
return false;
}
@@ -164,10 +174,8 @@ final class LdapStd extends Ldap
return $this->getUserObjectFilter();
}
- return '(&(cn=' . $groupName . ')'
- . '(|(memberUid=' . $member . ')(member=' . $member . ')(uniqueMember=' . $member . '))'
- . $this->getGroupObjectFilter()
- . ')';
+ return '(&(cn=' . $groupName . ')' . '(|(memberUid=' . $member . ')(member=' . $member . ')(uniqueMember=' . $member . '))' .
+ $this->getGroupObjectFilter() . ')';
}
/**
@@ -191,4 +199,4 @@ final class LdapStd extends Ldap
{
return $this->ldapParams->getServer();
}
-}
\ No newline at end of file
+}
diff --git a/lib/SP/Providers/Auth/Ldap/LdapTypeInterface.php b/lib/SP/Providers/Auth/Ldap/LdapTypeEnum.php
similarity index 75%
rename from lib/SP/Providers/Auth/Ldap/LdapTypeInterface.php
rename to lib/SP/Providers/Auth/Ldap/LdapTypeEnum.php
index 1f4566f6..0802372e 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapTypeInterface.php
+++ b/lib/SP/Providers/Auth/Ldap/LdapTypeEnum.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link https://syspass.org
- * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org
+ * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
@@ -24,15 +24,12 @@
namespace SP\Providers\Auth\Ldap;
-
/**
- * Interface LdapTypeInterface
- *
- * @package SP\Providers\Auth\Ldap
+ * Class LdapTypeEnum
*/
-interface LdapTypeInterface
+enum LdapTypeEnum: int
{
- public const LDAP_STD = 1;
- public const LDAP_ADS = 2;
- public const LDAP_AZURE = 3;
-}
\ No newline at end of file
+ case STD = 1;
+ case ADS = 2;
+ case AZURE = 3;
+}
diff --git a/lib/SP/Providers/Auth/Ldap/LdapUtil.php b/lib/SP/Providers/Auth/Ldap/LdapUtil.php
index fa5a4bb8..086288f9 100644
--- a/lib/SP/Providers/Auth/Ldap/LdapUtil.php
+++ b/lib/SP/Providers/Auth/Ldap/LdapUtil.php
@@ -1,9 +1,10 @@
-\+#\/]+)/',
+ '/([";<>+#\/]+)/',
'/\G(\s)/',
- '/(\s)(?=\s*$)/'
+ '/(\s)(?=\s*$)/',
];
return preg_replace($chars, '\\\1', $dn);
@@ -57,23 +58,19 @@ final class LdapUtil
*
* @param string $group
*
- * @return bool|string
+ * @return string|null
*/
- public static function getGroupName(string $group)
+ public static function getGroupName(string $group): ?string
{
- if (preg_match(
- '/^cn=(?[^,]+),.*/i',
- $group,
- $matches)
- ) {
+ if (preg_match('/^cn=(?[^,]+),.*/i', $group, $matches)) {
return $matches['groupname'];
}
- return false;
+ return null;
}
/**
- * @param array $attributes
+ * @param array $attributes
* @param string $value
*
* @return string
@@ -92,4 +89,4 @@ final class LdapUtil
)
);
}
-}
\ No newline at end of file
+}
diff --git a/tests/SP/Html/HtmlTest.php b/tests/SP/Html/HtmlTest.php
index bab9d18d..6e651680 100644
--- a/tests/SP/Html/HtmlTest.php
+++ b/tests/SP/Html/HtmlTest.php
@@ -24,23 +24,16 @@
namespace SP\Tests\Html;
-use Faker\Factory;
-use PHPUnit\Framework\TestCase;
use SP\Html\Html;
+use SP\Tests\UnitaryTestCase;
/**
* Class HtmlTest
+ *
+ * @group unitary
*/
-class HtmlTest extends TestCase
+class HtmlTest extends UnitaryTestCase
{
- private static $faker;
-
- public static function setUpBeforeClass(): void
- {
- parent::setUpBeforeClass();
-
- self::$faker = Factory::create();
- }
public static function urlProvider(): array
{
diff --git a/tests/SP/Http/AddressTest.php b/tests/SP/Http/AddressTest.php
index 82452a49..a902b572 100644
--- a/tests/SP/Http/AddressTest.php
+++ b/tests/SP/Http/AddressTest.php
@@ -24,31 +24,21 @@
namespace SP\Tests\Http;
-use Faker\Factory;
-use PHPUnit\Framework\TestCase;
use SP\Core\Exceptions\InvalidArgumentException;
use SP\Http\Address;
+use SP\Tests\UnitaryTestCase;
/**
* Class AddressTest
*
- * @package SP\Tests\Http
+ * @group unitary
*/
-class AddressTest extends TestCase
+class AddressTest extends UnitaryTestCase
{
public static function binaryCheckProvider(): array
{
- $faker = Factory::create();
-
- $out = [];
-
- for ($i = 0; $i <= 100; $i++) {
- $out[] = [$faker->ipv4];
- $out[] = [$faker->ipv6];
- }
-
- return $out;
+ return array_map(fn() => [[self::$faker->ipv4], [self::$faker->ipv6]], range(0, 99));
}
public static function checkAddressProvider(): array
@@ -121,7 +111,7 @@ class AddressTest extends TestCase
*
* @throws InvalidArgumentException
*/
- public function testBinary($address)
+ public function testBinary(string $address)
{
$binary = Address::toBinary($address);
@@ -159,7 +149,7 @@ class AddressTest extends TestCase
*
* @throws InvalidArgumentException
*/
- public function testCheck($address, $inAddress, $inMask, $expected)
+ public function testCheck(string $address, string $inAddress, string $inMask, bool $expected)
{
$this->assertEquals($expected, Address::check($address, $inAddress, $inMask));
}
@@ -174,7 +164,7 @@ class AddressTest extends TestCase
*
* @throws InvalidArgumentException
*/
- public function testCheckWithCidr($address, $inAddress, $inMask, $expected)
+ public function testCheckWithCidr(string $address, string $inAddress, string $inMask, bool $expected)
{
$this->assertEquals($expected, Address::check($address, $inAddress, Address::cidrToDec($inMask)));
}
@@ -182,7 +172,7 @@ class AddressTest extends TestCase
/**
* @throws InvalidArgumentException
*/
- public function testParse()
+ public function testParseWithFullMask()
{
$address = '192.168.0.1/255.255.255.0';
$parse = Address::parse4($address);
@@ -192,7 +182,13 @@ class AddressTest extends TestCase
$this->assertEquals('192.168.0.1', $parse['address']);
$this->assertArrayHasKey('mask', $parse);
$this->assertEquals('255.255.255.0', $parse['mask']);
+ }
+ /**
+ * @throws InvalidArgumentException
+ */
+ public function testParseWithoutMask()
+ {
$address = '192.168.0.2';
$parse = Address::parse4($address);
@@ -210,6 +206,21 @@ class AddressTest extends TestCase
$this->assertEquals('24', $parse['cidr']);
}
+ /**
+ * @throws InvalidArgumentException
+ */
+ public function testParseWithCIDR()
+ {
+ $address = '192.168.0.1/24';
+ $parse = Address::parse4($address);
+
+ $this->assertCount(7, $parse);
+ $this->assertArrayHasKey('address', $parse);
+ $this->assertEquals('192.168.0.1', $parse['address']);
+ $this->assertArrayHasKey('cidr', $parse);
+ $this->assertEquals('24', $parse['cidr']);
+ }
+
/**
* @throws InvalidArgumentException
*/
diff --git a/tests/SP/Providers/Auth/Ldap/LdapActionsTest.php b/tests/SP/Providers/Auth/Ldap/LdapActionsTest.php
new file mode 100644
index 00000000..1946b375
--- /dev/null
+++ b/tests/SP/Providers/Auth/Ldap/LdapActionsTest.php
@@ -0,0 +1,285 @@
+.
+ */
+
+namespace SP\Tests\Providers\Auth\Ldap;
+
+use Laminas\Ldap\Collection;
+use Laminas\Ldap\Ldap;
+use PHPUnit\Framework\MockObject\Exception;
+use PHPUnit\Framework\MockObject\MockObject;
+use SP\Core\Events\Event;
+use SP\Core\Events\EventDispatcherInterface;
+use SP\Providers\Auth\Ldap\AttributeCollection;
+use SP\Providers\Auth\Ldap\LdapActions;
+use SP\Providers\Auth\Ldap\LdapCodeEnum;
+use SP\Providers\Auth\Ldap\LdapException;
+use SP\Providers\Auth\Ldap\LdapParams;
+use SP\Providers\Auth\Ldap\LdapTypeEnum;
+use SP\Tests\UnitaryTestCase;
+
+/**
+ * Class LdapActionsTest
+ *
+ * @group unitary
+ */
+class LdapActionsTest extends UnitaryTestCase
+{
+
+ private Ldap|MockObject $ldap;
+ private EventDispatcherInterface|MockObject $eventDispatcher;
+ private LdapActions $ldapActions;
+
+ /**
+ * @throws LdapException
+ * @throws Exception
+ */
+ public function testGetObjects(): void
+ {
+ $filter = 'test';
+ $collection = $this->createMock(Collection::class);
+ $result = array_map(fn() => self::$faker->randomNumber(), range(0, 9));
+ $attributes = array_map(fn() => self::$faker->colorName, range(0, 9));
+ $searchBase = self::$faker->colorName;
+
+ $this->ldap->expects(self::once())
+ ->method('search')
+ ->with(
+ $filter,
+ $searchBase,
+ Ldap::SEARCH_SCOPE_SUB,
+ $attributes,
+ )
+ ->willReturn($collection);
+
+ $collection->expects(self::once())->method('toArray')->willReturn($result);
+
+ $out = $this->ldapActions->getObjects($filter, $attributes, $searchBase);
+
+ self::assertEquals($result, $out);
+ }
+
+ /**
+ * @throws LdapException
+ */
+ public function testGetObjectsError(): void
+ {
+ $this->expectGetResultsError();
+
+ $this->ldapActions->getObjects('test');
+ }
+
+ /**
+ * @return void
+ */
+ private function expectGetResultsError(): void
+ {
+ $message = 'test';
+ $code = self::$faker->randomNumber();
+ $exception = new \Laminas\Ldap\Exception\LdapException(null, $message, $code);
+
+ $this->ldap->expects(self::once())
+ ->method('search')
+ ->willThrowException($exception);
+
+ $this->eventDispatcher->expects(self::once())
+ ->method('notifyEvent')
+ ->with('exception', new Event($exception));
+
+ $this->expectException(LdapException::class);
+ $this->expectExceptionMessage($message);
+ $this->expectExceptionCode($code);
+ }
+
+ /**
+ * @throws LdapException
+ * @throws Exception
+ */
+ public function testGetAttributes(): void
+ {
+ $filter = 'test';
+ $collection = $this->createMock(Collection::class);
+ $attributes = $this->buildAttributes();
+
+ $this->ldap->expects(self::once())
+ ->method('search')
+ ->with(
+ $filter,
+ null,
+ Ldap::SEARCH_SCOPE_SUB,
+ [],
+ )
+ ->willReturn($collection);
+
+ $collection->expects(self::once())->method('getFirst')->willReturn($attributes);
+
+ $out = $this->ldapActions->getAttributes($filter);
+
+ $expected = new AttributeCollection([
+ 'dn' => $attributes['dn'],
+ 'group' => array_filter(
+ $attributes['memberof'],
+ fn($key) => $key !== 'count',
+ ARRAY_FILTER_USE_KEY
+ ),
+ 'fullname' => $attributes['displayname'],
+ 'name' => $attributes['givenname'],
+ 'sn' => $attributes['sn'],
+ 'mail' => $attributes['mail'],
+ 'expire' => $attributes['lockouttime'],
+ ]);
+
+ self::assertEquals($expected, $out);
+ }
+
+ /**
+ * @return array
+ */
+ private function buildAttributes(): array
+ {
+ return [
+ 'dn' => self::$faker->userName,
+ 'memberof' => [
+ 'count' => 3,
+ self::$faker->company,
+ self::$faker->company,
+ self::$faker->company,
+ ],
+ 'displayname' => self::$faker->name,
+ 'givenname' => self::$faker->firstName,
+ 'sn' => self::$faker->lastName,
+ 'mail' => self::$faker->email,
+ 'lockouttime' => self::$faker->unixTime,
+ ];
+ }
+
+ /**
+ * @throws \SP\Providers\Auth\Ldap\LdapException
+ */
+ public function testGetAttributesError(): void
+ {
+ $this->expectGetResultsError();
+
+ $this->ldapActions->getAttributes('test');
+ }
+
+ public function testMutate(): void
+ {
+ $ldapParams =
+ new LdapParams(self::$faker->domainName, LdapTypeEnum::ADS, self::$faker->company, self::$faker->password);
+
+ $this->ldapActions->mutate($ldapParams);
+
+ $this->assertTrue(true);
+ }
+
+ /**
+ * @throws \SP\Providers\Auth\Ldap\LdapException
+ * @throws \PHPUnit\Framework\MockObject\Exception
+ */
+ public function testSearchGroupsDn(): void
+ {
+ $filter = 'test';
+ $collection = $this->createMock(Collection::class);
+
+ $this->ldap->expects(self::once())
+ ->method('search')
+ ->with(
+ '(&(cn=\2a)test)',
+ null,
+ Ldap::SEARCH_SCOPE_SUB,
+ ['dn'],
+ )
+ ->willReturn($collection);
+
+ $collection->expects(self::once())->method('count')->willReturn(1);
+
+ $expected = [
+ [],
+ [
+ 'dn' => self::$faker->name,
+ ],
+ ];
+ $collection->expects(self::once())->method('toArray')->willReturn($expected);
+
+ $out = $this->ldapActions->searchGroupsDn($filter);
+
+ self::assertEquals($expected[1]['dn'], $out[0]);
+ }
+
+ /**
+ * @throws \SP\Providers\Auth\Ldap\LdapException
+ * @throws \PHPUnit\Framework\MockObject\Exception
+ */
+ public function testSearchGroupsDnNoGroups(): void
+ {
+ $filter = 'test';
+ $collection = $this->createMock(Collection::class);
+
+ $this->ldap->expects(self::once())
+ ->method('search')
+ ->with(
+ '(&(cn=\2a)test)',
+ null,
+ Ldap::SEARCH_SCOPE_SUB,
+ ['dn'],
+ )
+ ->willReturn($collection);
+
+ $this->eventDispatcher->expects(self::once())
+ ->method('notifyEvent')
+ ->with('ldap.search.group');
+
+ $collection->expects(self::once())->method('count')->willReturn(0);
+
+ $this->expectException(LdapException::class);
+ $this->expectExceptionMessage('Error while searching the group RDN');
+ $this->expectExceptionCode(LdapCodeEnum::NO_SUCH_OBJECT->value);
+
+ $this->ldapActions->searchGroupsDn($filter);
+ }
+
+ /**
+ * @throws \SP\Providers\Auth\Ldap\LdapException
+ */
+ public function testSearchGroupsDnError(): void
+ {
+ $this->expectGetResultsError();
+
+ $this->ldapActions->searchGroupsDn('test');
+ }
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $this->ldap = $this->createMock(Ldap::class);
+ $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
+
+ $ldapParams =
+ new LdapParams(self::$faker->domainName, LdapTypeEnum::STD, self::$faker->userName, self::$faker->password);
+
+ $this->ldapActions = new LdapActions($this->ldap, $ldapParams, $this->eventDispatcher);
+ }
+
+}
diff --git a/tests/SP/Providers/Auth/Ldap/LdapConnectionTest.php b/tests/SP/Providers/Auth/Ldap/LdapConnectionTest.php
index eea7b848..92b8d5df 100644
--- a/tests/SP/Providers/Auth/Ldap/LdapConnectionTest.php
+++ b/tests/SP/Providers/Auth/Ldap/LdapConnectionTest.php
@@ -1,10 +1,10 @@
.
+ * along with sysPass. If not, see .
*/
namespace SP\Tests\Providers\Auth\Ldap;
-use PHPUnit\Framework\TestCase;
-use SP\Core\Events\EventDispatcher;
+use Laminas\Ldap\Ldap;
+use PHPUnit\Framework\MockObject\MockObject;
+use SP\Core\Events\EventDispatcherInterface;
use SP\Providers\Auth\Ldap\LdapConnection;
use SP\Providers\Auth\Ldap\LdapException;
use SP\Providers\Auth\Ldap\LdapParams;
-use SP\Providers\Auth\Ldap\LdapTypeInterface;
+use SP\Providers\Auth\Ldap\LdapTypeEnum;
+use SP\Tests\UnitaryTestCase;
+use function PHPUnit\Framework\once;
/**
* Class LdapConnectionTest
*
- * @package SP\Tests\Providers\Auth\Ldap
+ * @group unitary
*/
-class LdapConnectionTest extends TestCase
+class LdapConnectionTest extends UnitaryTestCase
{
+ private LdapConnection $ldapConnection;
+ private EventDispatcherInterface|MockObject $eventDispatcher;
+ private Ldap|MockObject $ldap;
+ private LdapParams $ldapParams;
+
/**
- * @throws LdapException
+ * @throws \SP\Providers\Auth\Ldap\LdapException
*/
- public function testCheckParams()
+ public function testCheckConnection(): void
{
- $ldapConnection = $this->getLdapConnection();
+ $this->ldap
+ ->expects(self::once())
+ ->method('bind')
+ ->with($this->ldapParams->getBindDn(), $this->ldapParams->getBindPass());
- $ldapConnection->checkParams();
+ $this->eventDispatcher
+ ->expects(once())
+ ->method('notifyEvent')
+ ->with('ldap.check.connection');
- $this->assertTrue(true);
+ $this->ldapConnection->checkConnection();
}
/**
- * @param LdapParams|null $params
- *
- * @return LdapConnection
+ * @throws \SP\Providers\Auth\Ldap\LdapException
*/
- public function getLdapConnection(LdapParams $params = null)
+ public function testCheckConnectionError(): void
{
- $ev = new EventDispatcher();
+ $this->expectConnectError();
- if ($params === null) {
- $params = new LdapParams();
- $params->setServer('test.example.com');
- $params->setPort(10389);
- $params->setBindDn('cn=test,dc=example,dc=com');
- $params->setBindPass('testpass');
- $params->setGroup('cn=Test Group,ou=Groups,dc=example,dc=con');
- $params->setSearchBase('dc=example,dc=com');
- $params->setTlsEnabled(true);
- $params->setType(LdapTypeInterface::LDAP_STD);
- }
-
- return new LdapConnection($params, $ev);
+ $this->ldapConnection->checkConnection();
}
/**
- * @throws LdapException
+ * @return void
*/
- public function testCheckParamsNoSearchBase()
+ private function expectConnectError(): void
{
- $ldapConnection = $this->getLdapConnection();
+ $this->ldap
+ ->expects(self::once())
+ ->method('bind')
+ ->with($this->ldapParams->getBindDn(), $this->ldapParams->getBindPass())
+ ->willThrowException(new \Laminas\Ldap\Exception\LdapException());
- $params = $ldapConnection->getLdapParams();
- $params->setSearchBase('');
+ $this->eventDispatcher
+ ->expects(self::exactly(2))
+ ->method('notifyEvent')
+ ->with(...self::withConsecutive(['exception'], ['ldap.bind']));
+
+ $this->ldap
+ ->expects(self::exactly(2))
+ ->method('getLastError')
+ ->willReturn('error');
+
+ $errorCode = self::$faker->randomNumber();
+
+ $this->ldap
+ ->expects(self::once())
+ ->method('getLastErrorCode')
+ ->willReturn($errorCode);
$this->expectException(LdapException::class);
- $ldapConnection->checkParams();
+ $this->expectExceptionMessage('LDAP connection error');
+ $this->expectExceptionCode($errorCode);
}
/**
- * @throws LdapException
+ * @throws \SP\Providers\Auth\Ldap\LdapException
*/
- public function testCheckParamsNoServer()
+ public function testConnect(): void
{
- $ldapConnection = $this->getLdapConnection();
+ $this->ldap
+ ->expects(self::once())
+ ->method('bind')
+ ->with($this->ldapParams->getBindDn(), $this->ldapParams->getBindPass());
- $params = $ldapConnection->getLdapParams();
- $params->setServer('');
-
- $this->expectException(LdapException::class);
- $ldapConnection->checkParams();
+ $this->ldapConnection->connect();
}
/**
- * @throws LdapException
+ * @throws \SP\Providers\Auth\Ldap\LdapException
*/
- public function testCheckParamsNoBindDn()
+ public function testConnectError(): void
{
- $ldapConnection = $this->getLdapConnection();
+ $this->expectConnectError();
- $params = $ldapConnection->getLdapParams();
- $params->setBindDn('');
+ $this->ldapConnection->connect();
+ }
+
+ /**
+ * @throws \SP\Providers\Auth\Ldap\LdapException
+ */
+ public function testMutate(): void
+ {
+ $ldapParams = new LdapParams(
+ self::$faker->domainName,
+ LdapTypeEnum::STD,
+ 'cn=test1,dc=example,dc=com',
+ self::$faker->password
+ );
+
+ $ldapConnection = $this->ldapConnection->mutate($ldapParams);
+
+ $this->ldap
+ ->expects(self::once())
+ ->method('bind')
+ ->with($ldapParams->getBindDn(), $ldapParams->getBindPass());
+
+ $ldapConnection->connect();
+ }
+
+ /**
+ * @throws \SP\Providers\Auth\Ldap\LdapException
+ */
+ public function testCreateInstanceError(): void
+ {
+ $message = self::$faker->colorName;
+ $errorCode = self::$faker->randomNumber();
+
+ $this->ldap
+ ->expects(self::once())
+ ->method('setOptions')
+ ->willThrowException(
+ new \Laminas\Ldap\Exception\LdapException(null, $message, $errorCode)
+ );
$this->expectException(LdapException::class);
- $ldapConnection->checkParams();
+ $this->expectExceptionMessage($message);
+ $this->expectExceptionCode($errorCode);
+
+ new LdapConnection($this->ldap, $this->ldapParams, $this->eventDispatcher, true);
}
- public function testGetServerUri()
+ /**
+ * @throws \PHPUnit\Framework\MockObject\Exception
+ * @throws \SP\Core\Context\ContextException
+ * @throws \SP\Providers\Auth\Ldap\LdapException
+ */
+ protected function setUp(): void
{
- $ldapConnection = $this->getLdapConnection();
+ parent::setUp();
- $this->assertEquals('ldap://test.example.com:10389', $ldapConnection->getServerUri());
+ $this->ldapParams = new LdapParams(
+ self::$faker->domainName,
+ LdapTypeEnum::STD,
+ 'cn=test,dc=example,dc=com',
+ self::$faker->password
+ );
+ $this->ldapParams->setPort(10389);
+ $this->ldapParams->setGroup('cn=Test Group,ou=Groups,dc=example,dc=con');
+ $this->ldapParams->setSearchBase('dc=example,dc=com');
+ $this->ldapParams->setTlsEnabled(true);
+
+ $this->ldap = $this->createMock(Ldap::class);
+ $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
+
+ $this->ldapConnection =
+ new LdapConnection($this->ldap, $this->ldapParams, $this->eventDispatcher, true);
}
- public function testGetServerUriNoSchema()
- {
- $ldapConnection = $this->getLdapConnection();
-
- $params = $ldapConnection->getLdapParams();
- $params->setServer('test.example.com');
- $params->setPort(389);
-
- $this->assertEquals('ldap://test.example.com', $ldapConnection->getServerUri());
-
- $params->setPort(10389);
- $this->assertEquals('ldap://test.example.com:10389', $ldapConnection->getServerUri());
- }
-
- public function testGetServerUriLdaps()
- {
- $ldapConnection = $this->getLdapConnection();
-
- $params = $ldapConnection->getLdapParams();
- $params->setServer('ldaps://test.example.com');
- $params->setPort(10636);
-
- $this->assertEquals('ldaps://test.example.com:10636', $ldapConnection->getServerUri());
- }
}
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
index 7a66b89e..b24925a4 100644
--- a/tests/phpunit.xml
+++ b/tests/phpunit.xml
@@ -70,7 +70,6 @@
../lib/SP/DataModel
- ../lib/SP/Providers
../lib/SP/Html/Assets
../lib/SP/Html/DataGrid
../lib/SP/Config/ConfigData.php