diff --git a/.php-cs-fixer.cache b/.php-cs-fixer.cache
index a5e23b1..daf30a0 100644
--- a/.php-cs-fixer.cache
+++ b/.php-cs-fixer.cache
@@ -1 +1 @@
-{"php":"7.3.33","version":"3.4.0:v3.4.0#47177af1cfb9dab5d1cc4daf91b7179c2efe7fad","indent":"\t","lineEnding":"\n","rules":{"encoding":true,"full_opening_tag":true,"blank_line_after_namespace":true,"braces":{"position_after_anonymous_constructs":"same","position_after_control_structures":"same","position_after_functions_and_oop_constructs":"same"},"class_definition":true,"constant_case":true,"elseif":true,"function_declaration":{"closure_function_spacing":"one"},"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"on_multiline":"ignore"},"no_break_comment":true,"no_closing_tag":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":true,"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":{"elements":["property","method","const"]},"align_multiline_comment":true,"array_indentation":true,"binary_operator_spaces":{"default":"single_space"},"blank_line_after_opening_tag":true,"no_unused_imports":true},"hashes":{"appinfo\/routes.php":3044887257,"lib\/Responses\/SCIMJSONResponse.php":2876810868,"lib\/Responses\/SCIMListResponse.php":76345573,"lib\/Responses\/SCIMErrorResponse.php":1118832559,"lib\/Controller\/ASCIMGroup.php":3712028548,"lib\/Controller\/UserController.php":2528458696,"lib\/Controller\/ASCIMUser.php":430477040,"lib\/Controller\/GroupController.php":3769468563}}
\ No newline at end of file
+{"php":"8.3.2","version":"3.48.0","indent":"\t","lineEnding":"\n","rules":{"encoding":true,"full_opening_tag":true,"blank_line_after_namespace":true,"braces_position":true,"class_definition":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":{"closure_function_spacing":"one"},"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"on_multiline":"ignore"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":true,"single_import_per_statement":true,"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":{"elements":["property","method","const"]},"align_multiline_comment":true,"array_indentation":true,"binary_operator_spaces":{"default":"single_space"},"blank_line_after_opening_tag":true,"curly_braces_position":{"classes_opening_brace":"same_line","functions_opening_brace":"same_line"},"no_spaces_inside_parenthesis":true,"no_unused_imports":true,"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"alpha"}},"hashes":{"appinfo\/routes.php":"a6daac024d42530db25f8a0ef4e4b8fc","lib\/Controller\/GroupController.php":"c43793525f75ed56acbcdebae283ef1d","lib\/Controller\/ServiceProviderConfigurationController.php":"23f9ec133052c11f256873834d9e9a37","lib\/Controller\/UserController.php":"ce6845e793cb2d8af28ee9c411530b37","lib\/Responses\/SCIMJSONResponse.php":"7218478fc8e0eb92ce29236825a8c17a","lib\/Responses\/SCIMListResponse.php":"bccc6e1cb2ef0be0745c89dfe9c50635","lib\/Responses\/SCIMErrorResponse.php":"4b57fdb473f7172c748ed7baeae5f425","lib\/Service\/GroupService.php":"150281b6627a71fa5880992346575210","lib\/Service\/UserService.php":"4d9ed2664130e74d688acc2f3c364ebf","lib\/AppInfo\/Application.php":"6f51c1b09b83ffea7a7bebf34fc45aa9","lib\/Exception\/AuthException.php":"74af2c0e26c689eb5718d43f6bfcf0a0","lib\/Exception\/ContentTypeException.php":"38395fd6b2287f4a8eead0584133f194","lib\/Middleware\/ContentTypeMiddleware.php":"4b947c369e511e4bd6be652827393aa5","lib\/Middleware\/AuthMiddleware.php":"dd7b9c27697ce77f6c4284f822b1a815","lib\/Middleware\/ErrorMiddleware.php":"ccb5c3a607517e9e98386a58a2ae63b5","lib\/Util\/Util.php":"75a45e4c37bcc6dfbcdcdd4387662a8d"}}
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..be3f7b2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 877b179..603a0dc 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -5,13 +5,14 @@
SCIM Service Provider
Implements SCIM protocol as a Service Provider
- 0.0.1
+ 1.0.0-alpha.0
agpl
- Pierre Ozoux
+ IndieHosters
+ Audriga
SCIMServiceProvider
integration
- https://lab.libreho.st/libre.sh/docker/nextcloud/
+ https://lab.libreho.st/libre.sh/scim/scimserviceprovider
-
+
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 65f8ecd..097ad2a 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -1,46 +1,21 @@
[
['name' => 'service_provider_configuration#resource_types', 'url' => '/ResourceTypes', 'verb' => 'GET'],
['name' => 'service_provider_configuration#schemas', 'url' => '/Schemas', 'verb' => 'GET'],
['name' => 'service_provider_configuration#service_provider_config', 'url' => '/ServiceProviderConfig', 'verb' => 'GET'],
+
+ ['name' => 'user#index', 'url' => '/Users', 'verb' => 'GET'],
+ ['name' => 'user#show', 'url' => '/Users/{id}', 'verb' => 'GET'],
+ ['name' => 'user#create', 'url' => '/Users', 'verb' => 'POST'],
+ ['name' => 'user#update', 'url' => '/Users/{id}', 'verb' => 'PUT'],
+ ['name' => 'user#destroy', 'url' => '/Users/{id}', 'verb' => 'DELETE'],
+
+ ['name' => 'group#index', 'url' => '/Groups', 'verb' => 'GET'],
+ ['name' => 'group#show', 'url' => '/Groups/{id}', 'verb' => 'GET'],
+ ['name' => 'group#create', 'url' => '/Groups', 'verb' => 'POST'],
+ ['name' => 'group#update', 'url' => '/Groups/{id}', 'verb' => 'PUT'],
+ ['name' => 'group#destroy', 'url' => '/Groups/{id}', 'verb' => 'DELETE'],
]
];
-
-$config = require dirname(__DIR__) . '/lib/Config/config.php';
-$userAndGroupRoutes = [];
-
-if (isset($config['auth_type']) && !empty($config['auth_type']) && (strcmp($config['auth_type'], 'bearer') === 0)) {
- $userAndGroupRoutes = [
- ['name' => 'user_bearer#index', 'url' => '/bearer/Users', 'verb' => 'GET'],
- ['name' => 'user_bearer#show', 'url' => '/bearer/Users/{id}', 'verb' => 'GET'],
- ['name' => 'user_bearer#create', 'url' => '/bearer/Users', 'verb' => 'POST'],
- ['name' => 'user_bearer#update', 'url' => '/bearer/Users/{id}', 'verb' => 'PUT'],
- ['name' => 'user_bearer#destroy', 'url' => '/bearer/Users/{id}', 'verb' => 'DELETE'],
-
- ['name' => 'group_bearer#index', 'url' => '/bearer/Groups', 'verb' => 'GET'],
- ['name' => 'group_bearer#show', 'url' => '/bearer/Groups/{id}', 'verb' => 'GET'],
- ['name' => 'group_bearer#create', 'url' => '/bearer/Groups', 'verb' => 'POST'],
- ['name' => 'group_bearer#update', 'url' => '/bearer/Groups/{id}', 'verb' => 'PUT'],
- ['name' => 'group_bearer#destroy', 'url' => '/bearer/Groups/{id}', 'verb' => 'DELETE'],
- ];
-} else if (!isset($config['auth_type']) || empty($config['auth_type']) || (strcmp($config['auth_type'], 'basic') === 0)) {
- $userAndGroupRoutes = [
- ['name' => 'user#index', 'url' => '/Users', 'verb' => 'GET'],
- ['name' => 'user#show', 'url' => '/Users/{id}', 'verb' => 'GET'],
- ['name' => 'user#create', 'url' => '/Users', 'verb' => 'POST'],
- ['name' => 'user#update', 'url' => '/Users/{id}', 'verb' => 'PUT'],
- ['name' => 'user#destroy', 'url' => '/Users/{id}', 'verb' => 'DELETE'],
-
- ['name' => 'group#index', 'url' => '/Groups', 'verb' => 'GET'],
- ['name' => 'group#show', 'url' => '/Groups/{id}', 'verb' => 'GET'],
- ['name' => 'group#create', 'url' => '/Groups', 'verb' => 'POST'],
- ['name' => 'group#update', 'url' => '/Groups/{id}', 'verb' => 'PUT'],
- ['name' => 'group#destroy', 'url' => '/Groups/{id}', 'verb' => 'DELETE'],
- ];
-}
-
-$routes['routes'] = array_merge($routes['routes'], $userAndGroupRoutes);
-
-return $routes;
diff --git a/composer.json b/composer.json
index 8db0429..c450de9 100644
--- a/composer.json
+++ b/composer.json
@@ -1,8 +1,8 @@
{
"require-dev": {
"vimeo/psalm": "^4.23",
- "christophwurst/nextcloud": "v22.1.1",
- "nextcloud/coding-standard": "^1.0"
+ "nextcloud/ocp": "v26.0.9",
+ "nextcloud/coding-standard": "^1.1"
},
"config": {
"allow-plugins": {
diff --git a/composer.lock b/composer.lock
index 48b0b7a..5523d5e 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": "64b7aba10119e669997cbca8af52bd38",
+ "content-hash": "12168ba78199e8eb5da634f9390bd1d0",
"packages": [
{
"name": "audriga/scim-server-php",
@@ -80,26 +80,25 @@
},
{
"name": "brick/math",
- "version": "0.9.3",
+ "version": "0.11.0",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
- "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae"
+ "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae",
- "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae",
+ "url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478",
+ "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478",
"shasum": ""
},
"require": {
- "ext-json": "*",
- "php": "^7.1 || ^8.0"
+ "php": "^8.0"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.2",
- "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",
- "vimeo/psalm": "4.9.2"
+ "phpunit/phpunit": "^9.0",
+ "vimeo/psalm": "5.0.0"
},
"type": "library",
"autoload": {
@@ -124,19 +123,85 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
- "source": "https://github.com/brick/math/tree/0.9.3"
+ "source": "https://github.com/brick/math/tree/0.11.0"
},
"funding": [
{
"url": "https://github.com/BenMorel",
"type": "github"
+ }
+ ],
+ "time": "2023-01-15T23:15:59+00:00"
+ },
+ {
+ "name": "carbonphp/carbon-doctrine-types",
+ "version": "dev-main",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git",
+ "reference": "a31d3358a2a5d6ae947df1691d1f321418a5f3d5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/a31d3358a2a5d6ae947df1691d1f321418a5f3d5",
+ "reference": "a31d3358a2a5d6ae947df1691d1f321418a5f3d5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.1"
+ },
+ "conflict": {
+ "doctrine/dbal": "<4.0.0 || >=5.0.0"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^4.0.0",
+ "nesbot/carbon": "^2.71.0 || ^3.0.0",
+ "phpunit/phpunit": "^10.3"
+ },
+ "default-branch": true,
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Carbon\\Doctrine\\": "src/Carbon/Doctrine/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "KyleKatarn",
+ "email": "kylekatarnls@gmail.com"
+ }
+ ],
+ "description": "Types to use Carbon in Doctrine",
+ "keywords": [
+ "carbon",
+ "date",
+ "datetime",
+ "doctrine",
+ "time"
+ ],
+ "support": {
+ "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues",
+ "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/kylekatarnls",
+ "type": "github"
},
{
- "url": "https://tidelift.com/funding/github/packagist/brick/math",
+ "url": "https://opencollective.com/Carbon",
+ "type": "open_collective"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon",
"type": "tidelift"
}
],
- "time": "2021-08-15T20:50:18+00:00"
+ "time": "2023-12-10T15:33:53+00:00"
},
{
"name": "coenjacobs/mozart",
@@ -202,12 +267,12 @@
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
- "reference": "bf265da9f831e46e646c7a01b59ee8a33f8c0365"
+ "reference": "d718c589c01ce614e03ed0ab3be831e4201bfb79"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/inflector/zipball/bf265da9f831e46e646c7a01b59ee8a33f8c0365",
- "reference": "bf265da9f831e46e646c7a01b59ee8a33f8c0365",
+ "url": "https://api.github.com/repos/doctrine/inflector/zipball/d718c589c01ce614e03ed0ab3be831e4201bfb79",
+ "reference": "d718c589c01ce614e03ed0ab3be831e4201bfb79",
"shasum": ""
},
"require": {
@@ -285,7 +350,7 @@
"type": "tidelift"
}
],
- "time": "2023-01-15T14:40:19+00:00"
+ "time": "2024-01-15T18:12:41+00:00"
},
{
"name": "doctrine/lexer",
@@ -423,30 +488,31 @@
},
{
"name": "firebase/php-jwt",
- "version": "v6.3.2",
+ "version": "v6.10.0",
"source": {
"type": "git",
"url": "https://github.com/firebase/php-jwt.git",
- "reference": "ea7dda77098b96e666c5ef382452f94841e439cd"
+ "reference": "a49db6f0a5033aef5143295342f1c95521b075ff"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/firebase/php-jwt/zipball/ea7dda77098b96e666c5ef382452f94841e439cd",
- "reference": "ea7dda77098b96e666c5ef382452f94841e439cd",
+ "url": "https://api.github.com/repos/firebase/php-jwt/zipball/a49db6f0a5033aef5143295342f1c95521b075ff",
+ "reference": "a49db6f0a5033aef5143295342f1c95521b075ff",
"shasum": ""
},
"require": {
- "php": "^7.1||^8.0"
+ "php": "^7.4||^8.0"
},
"require-dev": {
"guzzlehttp/guzzle": "^6.5||^7.4",
- "phpspec/prophecy-phpunit": "^1.1",
- "phpunit/phpunit": "^7.5||^9.5",
+ "phpspec/prophecy-phpunit": "^2.0",
+ "phpunit/phpunit": "^9.5",
"psr/cache": "^1.0||^2.0",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0"
},
"suggest": {
+ "ext-sodium": "Support EdDSA (Ed25519) signatures",
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
},
"type": "library",
@@ -479,9 +545,9 @@
],
"support": {
"issues": "https://github.com/firebase/php-jwt/issues",
- "source": "https://github.com/firebase/php-jwt/tree/v6.3.2"
+ "source": "https://github.com/firebase/php-jwt/tree/v6.10.0"
},
- "time": "2022-12-19T17:10:46+00:00"
+ "time": "2023-12-01T16:26:39+00:00"
},
{
"name": "illuminate/collections",
@@ -642,12 +708,12 @@
"source": {
"type": "git",
"url": "https://github.com/illuminate/database.git",
- "reference": "606f2935697e94fc6a9e2eae430a7f279283f60c"
+ "reference": "f6f16450e733932b4c2c1468d8793c0a22fb45b3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/database/zipball/606f2935697e94fc6a9e2eae430a7f279283f60c",
- "reference": "606f2935697e94fc6a9e2eae430a7f279283f60c",
+ "url": "https://api.github.com/repos/illuminate/database/zipball/f6f16450e733932b4c2c1468d8793c0a22fb45b3",
+ "reference": "f6f16450e733932b4c2c1468d8793c0a22fb45b3",
"shasum": ""
},
"require": {
@@ -702,7 +768,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2022-12-19T10:24:20+00:00"
+ "time": "2023-06-11T21:11:10+00:00"
},
{
"name": "illuminate/macroable",
@@ -756,12 +822,12 @@
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
- "reference": "7895479ee9254069462bc9aa266eff20a5d46bae"
+ "reference": "ad030d68770e00a395822a4c243b931be3e4d3c7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/support/zipball/7895479ee9254069462bc9aa266eff20a5d46bae",
- "reference": "7895479ee9254069462bc9aa266eff20a5d46bae",
+ "url": "https://api.github.com/repos/illuminate/support/zipball/ad030d68770e00a395822a4c243b931be3e4d3c7",
+ "reference": "ad030d68770e00a395822a4c243b931be3e4d3c7",
"shasum": ""
},
"require": {
@@ -816,7 +882,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2022-12-19T10:24:20+00:00"
+ "time": "2023-06-11T21:11:10+00:00"
},
{
"name": "laravel/serializable-closure",
@@ -824,22 +890,23 @@
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
- "reference": "975c8239e2d8c9582fa5280cf8b9496aa717c173"
+ "reference": "d715a63f39ba076acf8be1e4a0901acdcc92228b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/975c8239e2d8c9582fa5280cf8b9496aa717c173",
- "reference": "975c8239e2d8c9582fa5280cf8b9496aa717c173",
+ "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/d715a63f39ba076acf8be1e4a0901acdcc92228b",
+ "reference": "d715a63f39ba076acf8be1e4a0901acdcc92228b",
"shasum": ""
},
"require": {
"php": "^7.3|^8.0"
},
"require-dev": {
- "nesbot/carbon": "^2.61",
+ "illuminate/support": "^8.0|^9.0|^10.0|^11.0",
+ "nesbot/carbon": "^2.61|^3.0",
"pestphp/pest": "^1.21.3",
"phpstan/phpstan": "^1.8.2",
- "symfony/var-dumper": "^5.4.11"
+ "symfony/var-dumper": "^5.4.11|^6.2.0|^7.0.0"
},
"default-branch": true,
"type": "library",
@@ -877,7 +944,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
- "time": "2022-12-28T12:34:46+00:00"
+ "time": "2024-01-26T17:22:21+00:00"
},
{
"name": "league/flysystem",
@@ -975,26 +1042,26 @@
},
{
"name": "league/mime-type-detection",
- "version": "1.11.0",
+ "version": "1.15.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/mime-type-detection.git",
- "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd"
+ "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd",
- "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd",
+ "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
+ "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
- "php": "^7.2 || ^8.0"
+ "php": "^7.4 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.2",
"phpstan/phpstan": "^0.12.68",
- "phpunit/phpunit": "^8.5.8 || ^9.3"
+ "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0"
},
"type": "library",
"autoload": {
@@ -1015,7 +1082,7 @@
"description": "Mime-type detection for Flysystem",
"support": {
"issues": "https://github.com/thephpleague/mime-type-detection/issues",
- "source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0"
+ "source": "https://github.com/thephpleague/mime-type-detection/tree/1.15.0"
},
"funding": [
{
@@ -1027,7 +1094,7 @@
"type": "tidelift"
}
],
- "time": "2022-04-17T13:12:02+00:00"
+ "time": "2024-01-28T23:22:08+00:00"
},
{
"name": "monolog/monolog",
@@ -1035,12 +1102,12 @@
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
- "reference": "1387e02612584ffa1a9e93384d2d63ba0a747e11"
+ "reference": "437cb3628f4cf6042cc10ae97fc2b8472e48ca1f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1387e02612584ffa1a9e93384d2d63ba0a747e11",
- "reference": "1387e02612584ffa1a9e93384d2d63ba0a747e11",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/437cb3628f4cf6042cc10ae97fc2b8472e48ca1f",
+ "reference": "437cb3628f4cf6042cc10ae97fc2b8472e48ca1f",
"shasum": ""
},
"require": {
@@ -1129,7 +1196,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-14T15:01:04+00:00"
+ "time": "2023-10-27T15:25:26+00:00"
},
{
"name": "nesbot/carbon",
@@ -1137,24 +1204,29 @@
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
- "reference": "09acf64155c16dc6f580f36569ae89344e9734a3"
+ "reference": "bdd61d32949b718aa3843ea5b342738242cd5966"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/09acf64155c16dc6f580f36569ae89344e9734a3",
- "reference": "09acf64155c16dc6f580f36569ae89344e9734a3",
+ "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bdd61d32949b718aa3843ea5b342738242cd5966",
+ "reference": "bdd61d32949b718aa3843ea5b342738242cd5966",
"shasum": ""
},
"require": {
+ "carbonphp/carbon-doctrine-types": "*",
"ext-json": "*",
"php": "^7.1.8 || ^8.0",
+ "psr/clock": "^1.0",
"symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php80": "^1.16",
"symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0"
},
+ "provide": {
+ "psr/clock-implementation": "1.0"
+ },
"require-dev": {
- "doctrine/dbal": "^2.0 || ^3.1.4",
- "doctrine/orm": "^2.7",
+ "doctrine/dbal": "^2.0 || ^3.1.4 || ^4.0",
+ "doctrine/orm": "^2.7 || ^3.0",
"friendsofphp/php-cs-fixer": "^3.0",
"kylekatarnls/multi-tester": "^2.0",
"ondrejmirtes/better-reflection": "*",
@@ -1232,7 +1304,7 @@
"type": "tidelift"
}
],
- "time": "2023-01-06T15:55:01+00:00"
+ "time": "2024-01-22T07:01:34+00:00"
},
{
"name": "nikic/fast-route",
@@ -1286,16 +1358,16 @@
},
{
"name": "php-di/invoker",
- "version": "2.3.3",
+ "version": "2.3.4",
"source": {
"type": "git",
"url": "https://github.com/PHP-DI/Invoker.git",
- "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786"
+ "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/cd6d9f267d1a3474bdddf1be1da079f01b942786",
- "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786",
+ "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86",
+ "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86",
"shasum": ""
},
"require": {
@@ -1329,7 +1401,7 @@
],
"support": {
"issues": "https://github.com/PHP-DI/Invoker/issues",
- "source": "https://github.com/PHP-DI/Invoker/tree/2.3.3"
+ "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4"
},
"funding": [
{
@@ -1337,7 +1409,7 @@
"type": "github"
}
],
- "time": "2021-12-13T09:22:56+00:00"
+ "time": "2023-09-08T09:24:21+00:00"
},
{
"name": "php-di/php-di",
@@ -1457,6 +1529,54 @@
},
"time": "2020-10-12T12:39:22+00:00"
},
+ {
+ "name": "psr/clock",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/clock.git",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Clock\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for reading the clock.",
+ "homepage": "https://github.com/php-fig/clock",
+ "keywords": [
+ "clock",
+ "now",
+ "psr",
+ "psr-20",
+ "time"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/clock/issues",
+ "source": "https://github.com/php-fig/clock/tree/1.0.0"
+ },
+ "time": "2022-11-25T14:36:26+00:00"
+ },
{
"name": "psr/container",
"version": "1.x-dev",
@@ -1511,17 +1631,17 @@
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
- "reference": "5a4f141ac2e5bc35e615134f127e1833158d2944"
+ "reference": "7037f4b0950474e9d1350e8df89b15f1842085f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-factory/zipball/5a4f141ac2e5bc35e615134f127e1833158d2944",
- "reference": "5a4f141ac2e5bc35e615134f127e1833158d2944",
+ "url": "https://api.github.com/repos/php-fig/http-factory/zipball/7037f4b0950474e9d1350e8df89b15f1842085f6",
+ "reference": "7037f4b0950474e9d1350e8df89b15f1842085f6",
"shasum": ""
},
"require": {
"php": ">=7.0.0",
- "psr/http-message": "^1.0"
+ "psr/http-message": "^1.0 || ^2.0"
},
"default-branch": true,
"type": "library",
@@ -1545,7 +1665,7 @@
"homepage": "https://www.php-fig.org/"
}
],
- "description": "Common interfaces for PSR-7 HTTP message factories",
+ "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
@@ -1557,32 +1677,31 @@
"response"
],
"support": {
- "source": "https://github.com/php-fig/http-factory/tree/master"
+ "source": "https://github.com/php-fig/http-factory"
},
- "time": "2022-07-14T07:21:53+00:00"
+ "time": "2023-09-22T11:16:44+00:00"
},
{
"name": "psr/http-message",
- "version": "dev-master",
+ "version": "1.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
- "reference": "efd67d1dc14a7ef4fc4e518e7dee91c271d524e4"
+ "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-message/zipball/efd67d1dc14a7ef4fc4e518e7dee91c271d524e4",
- "reference": "efd67d1dc14a7ef4fc4e518e7dee91c271d524e4",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
+ "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"shasum": ""
},
"require": {
- "php": ">=5.3.0"
+ "php": "^7.2 || ^8.0"
},
- "default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "1.1.x-dev"
}
},
"autoload": {
@@ -1611,9 +1730,9 @@
"response"
],
"support": {
- "source": "https://github.com/php-fig/http-message/tree/master"
+ "source": "https://github.com/php-fig/http-message/tree/1.1"
},
- "time": "2019-08-29T13:16:46+00:00"
+ "time": "2023-04-04T09:50:52+00:00"
},
{
"name": "psr/http-server-handler",
@@ -1621,17 +1740,17 @@
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-server-handler.git",
- "reference": "cada5cd1c6a9871031e07f26d0f7b08c9de19039"
+ "reference": "13403d43196ab3382d0a4ca28be32984282641f9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/cada5cd1c6a9871031e07f26d0f7b08c9de19039",
- "reference": "cada5cd1c6a9871031e07f26d0f7b08c9de19039",
+ "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/13403d43196ab3382d0a4ca28be32984282641f9",
+ "reference": "13403d43196ab3382d0a4ca28be32984282641f9",
"shasum": ""
},
"require": {
"php": ">=7.0",
- "psr/http-message": "^1.0"
+ "psr/http-message": "^1.0 || ^2.0"
},
"default-branch": true,
"type": "library",
@@ -1668,9 +1787,9 @@
"server"
],
"support": {
- "source": "https://github.com/php-fig/http-server-handler/tree/master"
+ "source": "https://github.com/php-fig/http-server-handler"
},
- "time": "2020-09-17T16:52:43+00:00"
+ "time": "2023-11-16T18:17:39+00:00"
},
{
"name": "psr/http-server-middleware",
@@ -1678,17 +1797,17 @@
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-server-middleware.git",
- "reference": "adcb26d2fb28018fea3319d0035e46e8d08eb8c8"
+ "reference": "459eeb7efeae55b4102a951c4ecc93a11ce58d0f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/adcb26d2fb28018fea3319d0035e46e8d08eb8c8",
- "reference": "adcb26d2fb28018fea3319d0035e46e8d08eb8c8",
+ "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/459eeb7efeae55b4102a951c4ecc93a11ce58d0f",
+ "reference": "459eeb7efeae55b4102a951c4ecc93a11ce58d0f",
"shasum": ""
},
"require": {
"php": ">=7.0",
- "psr/http-message": "^1.0",
+ "psr/http-message": "^1.0 || ^2.0",
"psr/http-server-handler": "^1.0"
},
"default-branch": true,
@@ -1726,9 +1845,9 @@
],
"support": {
"issues": "https://github.com/php-fig/http-server-middleware/issues",
- "source": "https://github.com/php-fig/http-server-middleware/tree/master"
+ "source": "https://github.com/php-fig/http-server-middleware"
},
- "time": "2020-09-17T16:41:19+00:00"
+ "time": "2023-09-22T11:17:21+00:00"
},
{
"name": "psr/log",
@@ -1877,21 +1996,20 @@
},
{
"name": "ramsey/collection",
- "version": "1.3.0",
+ "version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/ramsey/collection.git",
- "reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4"
+ "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ramsey/collection/zipball/ad7475d1c9e70b190ecffc58f2d989416af339b4",
- "reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4",
+ "url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
+ "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
"shasum": ""
},
"require": {
- "php": "^7.4 || ^8.0",
- "symfony/polyfill-php81": "^1.23"
+ "php": "^8.1"
},
"require-dev": {
"captainhook/plugin-composer": "^5.3",
@@ -1951,7 +2069,7 @@
],
"support": {
"issues": "https://github.com/ramsey/collection/issues",
- "source": "https://github.com/ramsey/collection/tree/1.3.0"
+ "source": "https://github.com/ramsey/collection/tree/2.0.0"
},
"funding": [
{
@@ -1963,29 +2081,27 @@
"type": "tidelift"
}
],
- "time": "2022-12-27T19:12:24+00:00"
+ "time": "2022-12-31T21:50:55+00:00"
},
{
"name": "ramsey/uuid",
- "version": "4.2.3",
+ "version": "4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
- "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df"
+ "reference": "d459bdbb08b1d893c56b1328c81fa0fdbda3ab54"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df",
- "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/d459bdbb08b1d893c56b1328c81fa0fdbda3ab54",
+ "reference": "d459bdbb08b1d893c56b1328c81fa0fdbda3ab54",
"shasum": ""
},
"require": {
- "brick/math": "^0.8 || ^0.9",
+ "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11",
"ext-json": "*",
- "php": "^7.2 || ^8.0",
- "ramsey/collection": "^1.0",
- "symfony/polyfill-ctype": "^1.8",
- "symfony/polyfill-php80": "^1.14"
+ "php": "^8.0",
+ "ramsey/collection": "^1.2 || ^2.0"
},
"replace": {
"rhumsaa/uuid": "self.version"
@@ -1997,34 +2113,31 @@
"doctrine/annotations": "^1.8",
"ergebnis/composer-normalize": "^2.15",
"mockery/mockery": "^1.3",
- "moontoast/math": "^1.1",
"paragonie/random-lib": "^2",
"php-mock/php-mock": "^2.2",
"php-mock/php-mock-mockery": "^1.3",
"php-parallel-lint/php-parallel-lint": "^1.1",
"phpbench/phpbench": "^1.0",
- "phpstan/extension-installer": "^1.0",
- "phpstan/phpstan": "^0.12",
- "phpstan/phpstan-mockery": "^0.12",
- "phpstan/phpstan-phpunit": "^0.12",
+ "phpstan/extension-installer": "^1.1",
+ "phpstan/phpstan": "^1.8",
+ "phpstan/phpstan-mockery": "^1.1",
+ "phpstan/phpstan-phpunit": "^1.1",
"phpunit/phpunit": "^8.5 || ^9",
- "slevomat/coding-standard": "^7.0",
+ "ramsey/composer-repl": "^1.4",
+ "slevomat/coding-standard": "^8.4",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^4.9"
},
"suggest": {
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
- "ext-ctype": "Enables faster processing of character classification using ctype functions.",
"ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.",
"ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.",
"paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
"ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
},
+ "default-branch": true,
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "4.x-dev"
- },
"captainhook": {
"force-install": true
}
@@ -2049,7 +2162,7 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
- "source": "https://github.com/ramsey/uuid/tree/4.2.3"
+ "source": "https://github.com/ramsey/uuid/tree/4.x"
},
"funding": [
{
@@ -2061,7 +2174,7 @@
"type": "tidelift"
}
],
- "time": "2021-09-25T23:10:38+00:00"
+ "time": "2024-01-22T21:44:20+00:00"
},
{
"name": "slim/php-view",
@@ -2069,22 +2182,22 @@
"source": {
"type": "git",
"url": "https://github.com/slimphp/PHP-View.git",
- "reference": "94cf4224f9a47b9d51d87b4450e5c0c2595ad0c7"
+ "reference": "ed5e37e8041959ec4e46b4bf6df5b94fed49684a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/slimphp/PHP-View/zipball/94cf4224f9a47b9d51d87b4450e5c0c2595ad0c7",
- "reference": "94cf4224f9a47b9d51d87b4450e5c0c2595ad0c7",
+ "url": "https://api.github.com/repos/slimphp/PHP-View/zipball/ed5e37e8041959ec4e46b4bf6df5b94fed49684a",
+ "reference": "ed5e37e8041959ec4e46b4bf6df5b94fed49684a",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0",
- "psr/http-message": "^1.0"
+ "psr/http-message": "^1.1"
},
"require-dev": {
- "phpunit/phpunit": "^9.5",
+ "phpunit/phpunit": "^9.6",
"slim/psr7": "^1.6",
- "squizlabs/php_codesniffer": "^3.7"
+ "squizlabs/php_codesniffer": "^3.8"
},
"default-branch": true,
"type": "library",
@@ -2117,20 +2230,20 @@
"issues": "https://github.com/slimphp/PHP-View/issues",
"source": "https://github.com/slimphp/PHP-View/tree/3.x"
},
- "time": "2022-12-01T16:27:12+00:00"
+ "time": "2024-01-01T20:52:51+00:00"
},
{
"name": "slim/psr7",
- "version": "1.6",
+ "version": "1.6.x-dev",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim-Psr7.git",
- "reference": "3471c22c1a0d26c51c78f6aeb06489d38cf46a4d"
+ "reference": "72d2b2bac94ab4575d369f605dbfafbe168d3163"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/3471c22c1a0d26c51c78f6aeb06489d38cf46a4d",
- "reference": "3471c22c1a0d26c51c78f6aeb06489d38cf46a4d",
+ "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/72d2b2bac94ab4575d369f605dbfafbe168d3163",
+ "reference": "72d2b2bac94ab4575d369f605dbfafbe168d3163",
"shasum": ""
},
"require": {
@@ -2149,7 +2262,7 @@
"adriansuter/php-autoload-override": "^1.3",
"ext-json": "*",
"http-interop/http-factory-tests": "^0.9.0",
- "php-http/psr7-integration-tests": "dev-master",
+ "php-http/psr7-integration-tests": "1.1",
"phpspec/prophecy": "^1.15",
"phpspec/prophecy-phpunit": "^2.0",
"phpstan/phpstan": "^1.8",
@@ -2197,9 +2310,9 @@
],
"support": {
"issues": "https://github.com/slimphp/Slim-Psr7/issues",
- "source": "https://github.com/slimphp/Slim-Psr7/tree/1.6"
+ "source": "https://github.com/slimphp/Slim-Psr7/tree/1.6.x"
},
- "time": "2022-11-05T18:50:24+00:00"
+ "time": "2023-04-17T16:02:20+00:00"
},
{
"name": "slim/slim",
@@ -2207,12 +2320,12 @@
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim.git",
- "reference": "a44d0a70d49ae86d1177503b7d734303d30ea9a6"
+ "reference": "7354f85722b89ac08763baf326a15cc11c162837"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/slimphp/Slim/zipball/a44d0a70d49ae86d1177503b7d734303d30ea9a6",
- "reference": "a44d0a70d49ae86d1177503b7d734303d30ea9a6",
+ "url": "https://api.github.com/repos/slimphp/Slim/zipball/7354f85722b89ac08763baf326a15cc11c162837",
+ "reference": "7354f85722b89ac08763baf326a15cc11c162837",
"shasum": ""
},
"require": {
@@ -2221,7 +2334,7 @@
"php": "^7.4 || ^8.0",
"psr/container": "^1.0 || ^2.0",
"psr/http-factory": "^1.0",
- "psr/http-message": "^1.0",
+ "psr/http-message": "^1.1 || ^2.0",
"psr/http-server-handler": "^1.0",
"psr/http-server-middleware": "^1.0",
"psr/log": "^1.1 || ^2.0 || ^3.0"
@@ -2229,19 +2342,19 @@
"require-dev": {
"adriansuter/php-autoload-override": "^1.4",
"ext-simplexml": "*",
- "guzzlehttp/psr7": "^2.4",
- "httpsoft/http-message": "^1.0",
- "httpsoft/http-server-request": "^1.0",
- "laminas/laminas-diactoros": "^2.17",
- "nyholm/psr7": "^1.5",
- "nyholm/psr7-server": "^1.0",
- "phpspec/prophecy": "^1.16",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpstan/phpstan": "^1.9",
- "phpunit/phpunit": "^9.5",
+ "guzzlehttp/psr7": "^2.6",
+ "httpsoft/http-message": "^1.1",
+ "httpsoft/http-server-request": "^1.1",
+ "laminas/laminas-diactoros": "^2.17 || ^3",
+ "nyholm/psr7": "^1.8",
+ "nyholm/psr7-server": "^1.1",
+ "phpspec/prophecy": "^1.18",
+ "phpspec/prophecy-phpunit": "^2.1",
+ "phpstan/phpstan": "^1.10",
+ "phpunit/phpunit": "^9.6",
"slim/http": "^1.3",
"slim/psr7": "^1.6",
- "squizlabs/php_codesniffer": "^3.7"
+ "squizlabs/php_codesniffer": "^3.8"
},
"suggest": {
"ext-simplexml": "Needed to support XML format in BodyParsingMiddleware",
@@ -2315,7 +2428,7 @@
"type": "tidelift"
}
],
- "time": "2022-12-01T16:30:46+00:00"
+ "time": "2024-01-01T20:50:49+00:00"
},
{
"name": "symfony/console",
@@ -2323,12 +2436,12 @@
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740"
+ "reference": "0aff1982feec6ac2a86f821957761b707c0071e6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/dccb8d251a9017d5994c988b034d3e18aaabf740",
- "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740",
+ "url": "https://api.github.com/repos/symfony/console/zipball/0aff1982feec6ac2a86f821957761b707c0071e6",
+ "reference": "0aff1982feec6ac2a86f821957761b707c0071e6",
"shasum": ""
},
"require": {
@@ -2393,7 +2506,7 @@
"homepage": "https://symfony.com",
"keywords": [
"cli",
- "command line",
+ "command-line",
"console",
"terminal"
],
@@ -2414,29 +2527,30 @@
"type": "tidelift"
}
],
- "time": "2023-01-01T08:32:19+00:00"
+ "time": "2024-01-21T09:52:19+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "2.5.x-dev",
+ "version": "dev-main",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
+ "reference": "2c438b99bb2753c1628c1e6f523991edea5b03a4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
- "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/2c438b99bb2753c1628c1e6f523991edea5b03a4",
+ "reference": "2c438b99bb2753c1628c1e6f523991edea5b03a4",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=8.1"
},
+ "default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.5-dev"
+ "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -2465,7 +2579,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/2.5"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/main"
},
"funding": [
{
@@ -2481,7 +2595,7 @@
"type": "tidelift"
}
],
- "time": "2022-01-02T09:53:40+00:00"
+ "time": "2024-01-02T14:07:37+00:00"
},
{
"name": "symfony/finder",
@@ -2489,12 +2603,12 @@
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f"
+ "reference": "ff4bce3c33451e7ec778070e45bd23f74214cd5d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/6071aebf810ad13fe8200c224f36103abb37cf1f",
- "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/ff4bce3c33451e7ec778070e45bd23f74214cd5d",
+ "reference": "ff4bce3c33451e7ec778070e45bd23f74214cd5d",
"shasum": ""
},
"require": {
@@ -2544,20 +2658,20 @@
"type": "tidelift"
}
],
- "time": "2023-01-14T19:14:44+00:00"
+ "time": "2023-07-31T08:02:31+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "dev-main",
+ "version": "1.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
+ "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
- "reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
+ "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": ""
},
"require": {
@@ -2573,7 +2687,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2611,7 +2725,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
},
"funding": [
{
@@ -2627,20 +2741,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "dev-main",
+ "version": "1.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "511a08c03c1960e08a883f4cffcacd219b758354"
+ "reference": "875e90aeea2777b6f135677f618529449334a612"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
- "reference": "511a08c03c1960e08a883f4cffcacd219b758354",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
+ "reference": "875e90aeea2777b6f135677f618529449334a612",
"shasum": ""
},
"require": {
@@ -2653,7 +2767,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2693,7 +2807,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
},
"funding": [
{
@@ -2709,20 +2823,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "dev-main",
+ "version": "1.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
+ "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
- "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
+ "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"shasum": ""
},
"require": {
@@ -2735,7 +2849,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2778,7 +2892,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
},
"funding": [
{
@@ -2794,20 +2908,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "dev-main",
+ "version": "1.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
+ "reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
- "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
+ "reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
@@ -2823,7 +2937,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2862,7 +2976,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
@@ -2878,20 +2992,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-07-28T09:04:16+00:00"
},
{
"name": "symfony/polyfill-php73",
- "version": "dev-main",
+ "version": "1.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
- "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9"
+ "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
- "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
+ "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5",
+ "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5",
"shasum": ""
},
"require": {
@@ -2901,7 +3015,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2942,7 +3056,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0"
},
"funding": [
{
@@ -2958,20 +3072,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-php80",
- "version": "dev-main",
+ "version": "1.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
- "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
+ "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
- "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
+ "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"shasum": ""
},
"require": {
@@ -2981,7 +3095,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3026,7 +3140,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
},
"funding": [
{
@@ -3042,117 +3156,34 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
- "name": "symfony/polyfill-php81",
+ "name": "symfony/service-contracts",
"version": "dev-main",
"source": {
"type": "git",
- "url": "https://github.com/symfony/polyfill-php81.git",
- "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a"
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "cea2eccfcd27ac3deb252bd67f78b9b8ffc4da84"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a",
- "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/cea2eccfcd27ac3deb252bd67f78b9b8ffc4da84",
+ "reference": "cea2eccfcd27ac3deb252bd67f78b9b8ffc4da84",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=8.1",
+ "psr/container": "^1.1|^2.0"
+ },
+ "conflict": {
+ "ext-psr": "<1.1|>=2"
},
"default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
- },
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Php81\\": ""
- },
- "classmap": [
- "Resources/stubs"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2022-11-03T14:55:06+00:00"
- },
- {
- "name": "symfony/service-contracts",
- "version": "2.5.x-dev",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/service-contracts.git",
- "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
- "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "psr/container": "^1.1",
- "symfony/deprecation-contracts": "^2.1|^3"
- },
- "conflict": {
- "ext-psr": "<1.1|>=2"
- },
- "suggest": {
- "symfony/service-implementation": ""
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.5-dev"
+ "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -3162,7 +3193,10 @@
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
- }
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -3189,7 +3223,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/2.5"
+ "source": "https://github.com/symfony/service-contracts/tree/main"
},
"funding": [
{
@@ -3205,38 +3239,38 @@
"type": "tidelift"
}
],
- "time": "2022-05-30T19:17:29+00:00"
+ "time": "2024-01-02T14:07:37+00:00"
},
{
"name": "symfony/string",
- "version": "5.4.x-dev",
+ "version": "6.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb"
+ "reference": "7a14736fb179876575464e4658fce0c304e8c15b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/0a01071610fd861cc160dfb7e2682ceec66064cb",
- "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb",
+ "url": "https://api.github.com/repos/symfony/string/zipball/7a14736fb179876575464e4658fce0c304e8c15b",
+ "reference": "7a14736fb179876575464e4658fce0c304e8c15b",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
+ "php": ">=8.1",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-intl-grapheme": "~1.0",
"symfony/polyfill-intl-normalizer": "~1.0",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php80": "~1.15"
+ "symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
- "symfony/translation-contracts": ">=3.0"
+ "symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "symfony/error-handler": "^4.4|^5.0|^6.0",
- "symfony/http-client": "^4.4|^5.0|^6.0",
- "symfony/translation-contracts": "^1.1|^2",
- "symfony/var-exporter": "^4.4|^5.0|^6.0"
+ "symfony/error-handler": "^5.4|^6.0|^7.0",
+ "symfony/http-client": "^5.4|^6.0|^7.0",
+ "symfony/intl": "^6.2|^7.0",
+ "symfony/translation-contracts": "^2.5|^3.0",
+ "symfony/var-exporter": "^5.4|^6.0|^7.0"
},
"type": "library",
"autoload": {
@@ -3275,7 +3309,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/5.4"
+ "source": "https://github.com/symfony/string/tree/6.4"
},
"funding": [
{
@@ -3291,57 +3325,55 @@
"type": "tidelift"
}
],
- "time": "2023-01-01T08:32:19+00:00"
+ "time": "2024-01-25T09:26:29+00:00"
},
{
"name": "symfony/translation",
- "version": "5.4.x-dev",
+ "version": "6.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
- "reference": "83d487b13b7fb4c0a6ad079f4e4c9b4525e1b695"
+ "reference": "637c51191b6b184184bbf98937702bcf554f7d04"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/83d487b13b7fb4c0a6ad079f4e4c9b4525e1b695",
- "reference": "83d487b13b7fb4c0a6ad079f4e4c9b4525e1b695",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/637c51191b6b184184bbf98937702bcf554f7d04",
+ "reference": "637c51191b6b184184bbf98937702bcf554f7d04",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
+ "php": ">=8.1",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php80": "^1.16",
- "symfony/translation-contracts": "^2.3"
+ "symfony/translation-contracts": "^2.5|^3.0"
},
"conflict": {
- "symfony/config": "<4.4",
- "symfony/console": "<5.3",
- "symfony/dependency-injection": "<5.0",
- "symfony/http-kernel": "<5.0",
- "symfony/twig-bundle": "<5.0",
- "symfony/yaml": "<4.4"
+ "symfony/config": "<5.4",
+ "symfony/console": "<5.4",
+ "symfony/dependency-injection": "<5.4",
+ "symfony/http-client-contracts": "<2.5",
+ "symfony/http-kernel": "<5.4",
+ "symfony/service-contracts": "<2.5",
+ "symfony/twig-bundle": "<5.4",
+ "symfony/yaml": "<5.4"
},
"provide": {
- "symfony/translation-implementation": "2.3"
+ "symfony/translation-implementation": "2.3|3.0"
},
"require-dev": {
+ "nikic/php-parser": "^4.18|^5.0",
"psr/log": "^1|^2|^3",
- "symfony/config": "^4.4|^5.0|^6.0",
- "symfony/console": "^5.4|^6.0",
- "symfony/dependency-injection": "^5.0|^6.0",
- "symfony/finder": "^4.4|^5.0|^6.0",
- "symfony/http-client-contracts": "^1.1|^2.0|^3.0",
- "symfony/http-kernel": "^5.0|^6.0",
- "symfony/intl": "^4.4|^5.0|^6.0",
+ "symfony/config": "^5.4|^6.0|^7.0",
+ "symfony/console": "^5.4|^6.0|^7.0",
+ "symfony/dependency-injection": "^5.4|^6.0|^7.0",
+ "symfony/finder": "^5.4|^6.0|^7.0",
+ "symfony/http-client-contracts": "^2.5|^3.0",
+ "symfony/http-kernel": "^5.4|^6.0|^7.0",
+ "symfony/intl": "^5.4|^6.0|^7.0",
"symfony/polyfill-intl-icu": "^1.21",
- "symfony/service-contracts": "^1.1.2|^2|^3",
- "symfony/yaml": "^4.4|^5.0|^6.0"
- },
- "suggest": {
- "psr/log-implementation": "To use logging capability in translator",
- "symfony/config": "",
- "symfony/yaml": ""
+ "symfony/routing": "^5.4|^6.0|^7.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/yaml": "^5.4|^6.0|^7.0"
},
"type": "library",
"autoload": {
@@ -3372,7 +3404,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/translation/tree/5.4"
+ "source": "https://github.com/symfony/translation/tree/6.4"
},
"funding": [
{
@@ -3388,32 +3420,30 @@
"type": "tidelift"
}
],
- "time": "2023-01-01T08:32:19+00:00"
+ "time": "2024-01-29T13:11:52+00:00"
},
{
"name": "symfony/translation-contracts",
- "version": "2.5.x-dev",
+ "version": "dev-main",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
- "reference": "79cebc7b8c230e88868a3a85693c1e30b44f750e"
+ "reference": "81a962876d52adf8ca7020f49e48f6f88cd5eddd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/79cebc7b8c230e88868a3a85693c1e30b44f750e",
- "reference": "79cebc7b8c230e88868a3a85693c1e30b44f750e",
+ "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/81a962876d52adf8ca7020f49e48f6f88cd5eddd",
+ "reference": "81a962876d52adf8ca7020f49e48f6f88cd5eddd",
"shasum": ""
},
"require": {
- "php": ">=7.2.5"
- },
- "suggest": {
- "symfony/translation-implementation": ""
+ "php": ">=8.1"
},
+ "default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.5-dev"
+ "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -3423,7 +3453,10 @@
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Translation\\": ""
- }
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -3450,7 +3483,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/translation-contracts/tree/2.5"
+ "source": "https://github.com/symfony/translation-contracts/tree/main"
},
"funding": [
{
@@ -3466,7 +3499,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-27T07:55:40+00:00"
+ "time": "2024-01-02T14:07:37+00:00"
},
{
"name": "voku/portable-ascii",
@@ -3710,50 +3743,6 @@
],
"time": "2022-06-21T18:19:50+00:00"
},
- {
- "name": "christophwurst/nextcloud",
- "version": "v22.1.1",
- "source": {
- "type": "git",
- "url": "https://github.com/ChristophWurst/nextcloud_composer.git",
- "reference": "8bb086cd016128b5ef8353662fd1852db3248d1e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/ChristophWurst/nextcloud_composer/zipball/8bb086cd016128b5ef8353662fd1852db3248d1e",
- "reference": "8bb086cd016128b5ef8353662fd1852db3248d1e",
- "shasum": ""
- },
- "require": {
- "php": "^7.3 || ~8.0.0",
- "psr/container": "^1.0",
- "psr/event-dispatcher": "^1.0",
- "psr/log": "^1.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "23.0.0-dev"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "AGPL-3.0-or-later"
- ],
- "authors": [
- {
- "name": "Christoph Wurst",
- "email": "christoph@winzerhof-wurst.at"
- }
- ],
- "description": "Composer package containing Nextcloud's public API (classes, interfaces)",
- "support": {
- "issues": "https://github.com/ChristophWurst/nextcloud_composer/issues",
- "source": "https://github.com/ChristophWurst/nextcloud_composer/tree/v22.1.1"
- },
- "abandoned": "nextcloud/ocp",
- "time": "2021-11-11T14:01:42+00:00"
- },
{
"name": "composer/package-versions-deprecated",
"version": "dev-master",
@@ -3834,12 +3823,12 @@
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
- "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2"
+ "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2",
- "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9",
+ "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9",
"shasum": ""
},
"require": {
@@ -3882,7 +3871,7 @@
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
- "source": "https://github.com/composer/pcre/tree/3.1.0"
+ "source": "https://github.com/composer/pcre/tree/3.1.1"
},
"funding": [
{
@@ -3898,7 +3887,7 @@
"type": "tidelift"
}
],
- "time": "2022-11-17T09:50:14+00:00"
+ "time": "2023-10-11T07:11:09+00:00"
},
{
"name": "composer/semver",
@@ -3906,12 +3895,12 @@
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
- "reference": "fa1ec24f0ab1efe642671ec15c51a3ab879f59bf"
+ "reference": "1d09200268e7d1052ded8e5da9c73c96a63d18f5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/semver/zipball/fa1ec24f0ab1efe642671ec15c51a3ab879f59bf",
- "reference": "fa1ec24f0ab1efe642671ec15c51a3ab879f59bf",
+ "url": "https://api.github.com/repos/composer/semver/zipball/1d09200268e7d1052ded8e5da9c73c96a63d18f5",
+ "reference": "1d09200268e7d1052ded8e5da9c73c96a63d18f5",
"shasum": ""
},
"require": {
@@ -3980,7 +3969,7 @@
"type": "tidelift"
}
],
- "time": "2023-01-13T15:47:53+00:00"
+ "time": "2023-08-31T12:20:31+00:00"
},
{
"name": "composer/xdebug-handler",
@@ -4086,81 +4075,52 @@
"time": "2019-12-04T15:06:13+00:00"
},
{
- "name": "doctrine/annotations",
- "version": "1.14.x-dev",
+ "name": "doctrine/deprecations",
+ "version": "1.1.x-dev",
"source": {
"type": "git",
- "url": "https://github.com/doctrine/annotations.git",
- "reference": "ad785217c1e9555a7d6c6c8c9f406395a5e2882b"
+ "url": "https://github.com/doctrine/deprecations.git",
+ "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/annotations/zipball/ad785217c1e9555a7d6c6c8c9f406395a5e2882b",
- "reference": "ad785217c1e9555a7d6c6c8c9f406395a5e2882b",
+ "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931",
+ "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931",
"shasum": ""
},
"require": {
- "doctrine/lexer": "^1 || ^2",
- "ext-tokenizer": "*",
- "php": "^7.1 || ^8.0",
- "psr/cache": "^1 || ^2 || ^3"
+ "php": "^7.1 || ^8.0"
},
"require-dev": {
- "doctrine/cache": "^1.11 || ^2.0",
- "doctrine/coding-standard": "^9 || ^10",
- "phpstan/phpstan": "~1.4.10 || ^1.8.0",
+ "doctrine/coding-standard": "^9",
+ "phpstan/phpstan": "1.4.10 || 1.10.15",
+ "phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
- "symfony/cache": "^4.4 || ^5.4 || ^6",
- "vimeo/psalm": "^4.10"
+ "psalm/plugin-phpunit": "0.18.4",
+ "psr/log": "^1 || ^2 || ^3",
+ "vimeo/psalm": "4.30.0 || 5.12.0"
},
"suggest": {
- "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
+ "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-4": {
- "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
+ "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
- "authors": [
- {
- "name": "Guilherme Blanco",
- "email": "guilhermeblanco@gmail.com"
- },
- {
- "name": "Roman Borschel",
- "email": "roman@code-factory.org"
- },
- {
- "name": "Benjamin Eberlei",
- "email": "kontakt@beberlei.de"
- },
- {
- "name": "Jonathan Wage",
- "email": "jonwage@gmail.com"
- },
- {
- "name": "Johannes Schmitt",
- "email": "schmittjoh@gmail.com"
- }
- ],
- "description": "Docblock Annotations Parser",
- "homepage": "https://www.doctrine-project.org/projects/annotations.html",
- "keywords": [
- "annotations",
- "docblock",
- "parser"
- ],
+ "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
+ "homepage": "https://www.doctrine-project.org/",
"support": {
- "issues": "https://github.com/doctrine/annotations/issues",
- "source": "https://github.com/doctrine/annotations/tree/1.14.2"
+ "issues": "https://github.com/doctrine/deprecations/issues",
+ "source": "https://github.com/doctrine/deprecations/tree/1.1.2"
},
- "time": "2022-12-15T06:48:22+00:00"
+ "time": "2023-09-27T20:04:15+00:00"
},
{
"name": "felixfbecker/advanced-json-rpc",
@@ -4264,107 +4224,18 @@
},
"time": "2022-06-19T17:15:06+00:00"
},
- {
- "name": "friendsofphp/php-cs-fixer",
- "version": "v3.13.2",
- "source": {
- "type": "git",
- "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
- "reference": "3952f08a81bd3b1b15e11c3de0b6bf037faa8496"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/3952f08a81bd3b1b15e11c3de0b6bf037faa8496",
- "reference": "3952f08a81bd3b1b15e11c3de0b6bf037faa8496",
- "shasum": ""
- },
- "require": {
- "composer/semver": "^3.2",
- "composer/xdebug-handler": "^3.0.3",
- "doctrine/annotations": "^1.13",
- "ext-json": "*",
- "ext-tokenizer": "*",
- "php": "^7.4 || ^8.0",
- "sebastian/diff": "^4.0",
- "symfony/console": "^5.4 || ^6.0",
- "symfony/event-dispatcher": "^5.4 || ^6.0",
- "symfony/filesystem": "^5.4 || ^6.0",
- "symfony/finder": "^5.4 || ^6.0",
- "symfony/options-resolver": "^5.4 || ^6.0",
- "symfony/polyfill-mbstring": "^1.23",
- "symfony/polyfill-php80": "^1.25",
- "symfony/polyfill-php81": "^1.25",
- "symfony/process": "^5.4 || ^6.0",
- "symfony/stopwatch": "^5.4 || ^6.0"
- },
- "require-dev": {
- "justinrainbow/json-schema": "^5.2",
- "keradus/cli-executor": "^2.0",
- "mikey179/vfsstream": "^1.6.10",
- "php-coveralls/php-coveralls": "^2.5.2",
- "php-cs-fixer/accessible-object": "^1.1",
- "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2",
- "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1",
- "phpspec/prophecy": "^1.15",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpunit/phpunit": "^9.5",
- "phpunitgoodpractices/polyfill": "^1.6",
- "phpunitgoodpractices/traits": "^1.9.2",
- "symfony/phpunit-bridge": "^6.0",
- "symfony/yaml": "^5.4 || ^6.0"
- },
- "suggest": {
- "ext-dom": "For handling output formats in XML",
- "ext-mbstring": "For handling non-UTF8 characters."
- },
- "bin": [
- "php-cs-fixer"
- ],
- "type": "application",
- "autoload": {
- "psr-4": {
- "PhpCsFixer\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Dariusz Rumiński",
- "email": "dariusz.ruminski@gmail.com"
- }
- ],
- "description": "A tool to automatically fix PHP code style",
- "support": {
- "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
- "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.13.2"
- },
- "funding": [
- {
- "url": "https://github.com/keradus",
- "type": "github"
- }
- ],
- "time": "2023-01-02T23:53:50+00:00"
- },
{
"name": "netresearch/jsonmapper",
- "version": "v4.1.0",
+ "version": "v4.4.0",
"source": {
"type": "git",
"url": "https://github.com/cweiske/jsonmapper.git",
- "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f"
+ "reference": "18133a2d8c24e10e58e02b700308ed3a4a60c97f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
- "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
+ "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/18133a2d8c24e10e58e02b700308ed3a4a60c97f",
+ "reference": "18133a2d8c24e10e58e02b700308ed3a4a60c97f",
"shasum": ""
},
"require": {
@@ -4375,7 +4246,7 @@
"php": ">=7.1"
},
"require-dev": {
- "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0",
+ "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0",
"squizlabs/php_codesniffer": "~3.5"
},
"type": "library",
@@ -4400,27 +4271,27 @@
"support": {
"email": "cweiske@cweiske.de",
"issues": "https://github.com/cweiske/jsonmapper/issues",
- "source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0"
+ "source": "https://github.com/cweiske/jsonmapper/tree/v4.4.0"
},
- "time": "2022-12-08T20:46:14+00:00"
+ "time": "2024-01-28T07:31:37+00:00"
},
{
"name": "nextcloud/coding-standard",
- "version": "v1.0.0",
+ "version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/nextcloud/coding-standard.git",
- "reference": "f3d1f9375e89c605deb1734f59a9f51ecbe80578"
+ "reference": "55def702fb9a37a219511e1d8c6fe8e37164c1fb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/f3d1f9375e89c605deb1734f59a9f51ecbe80578",
- "reference": "f3d1f9375e89c605deb1734f59a9f51ecbe80578",
+ "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/55def702fb9a37a219511e1d8c6fe8e37164c1fb",
+ "reference": "55def702fb9a37a219511e1d8c6fe8e37164c1fb",
"shasum": ""
},
"require": {
- "friendsofphp/php-cs-fixer": "^3.2",
- "php": "^7.3|^8.0"
+ "php": "^7.3|^8.0",
+ "php-cs-fixer/shim": "^3.17"
},
"type": "library",
"autoload": {
@@ -4441,9 +4312,52 @@
"description": "Nextcloud coding standards for the php cs fixer",
"support": {
"issues": "https://github.com/nextcloud/coding-standard/issues",
- "source": "https://github.com/nextcloud/coding-standard/tree/v1.0.0"
+ "source": "https://github.com/nextcloud/coding-standard/tree/v1.1.1"
},
- "time": "2021-11-10T08:44:10+00:00"
+ "time": "2023-06-01T12:05:01+00:00"
+ },
+ {
+ "name": "nextcloud/ocp",
+ "version": "v26.0.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nextcloud-deps/ocp.git",
+ "reference": "43bc0a0267d97b02966e0270e00e9d51192564af"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/43bc0a0267d97b02966e0270e00e9d51192564af",
+ "reference": "43bc0a0267d97b02966e0270e00e9d51192564af",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4 || ~8.0 || ~8.1",
+ "psr/container": "^1.1.1",
+ "psr/event-dispatcher": "^1.0",
+ "psr/log": "^1.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "26.0.0-dev"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "AGPL-3.0-or-later"
+ ],
+ "authors": [
+ {
+ "name": "Christoph Wurst",
+ "email": "christoph@winzerhof-wurst.at"
+ }
+ ],
+ "description": "Composer package containing Nextcloud's public API (classes, interfaces)",
+ "support": {
+ "issues": "https://github.com/nextcloud-deps/ocp/issues",
+ "source": "https://github.com/nextcloud-deps/ocp/tree/v26.0.9"
+ },
+ "time": "2023-11-10T00:31:54+00:00"
},
{
"name": "nikic/php-parser",
@@ -4451,12 +4365,12 @@
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039"
+ "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039",
- "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999",
+ "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999",
"shasum": ""
},
"require": {
@@ -4467,7 +4381,6 @@
"ircmaxell/php-yacc": "^0.0.7",
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
},
- "default-branch": true,
"bin": [
"bin/php-parse"
],
@@ -4498,9 +4411,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3"
+ "source": "https://github.com/nikic/PHP-Parser/tree/4.x"
},
- "time": "2023-01-16T22:05:37+00:00"
+ "time": "2023-12-10T21:03:43+00:00"
},
{
"name": "openlss/lib-array2xml",
@@ -4555,6 +4468,58 @@
},
"time": "2019-03-29T20:06:56+00:00"
},
+ {
+ "name": "php-cs-fixer/shim",
+ "version": "v3.48.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHP-CS-Fixer/shim.git",
+ "reference": "bf0c65f1b2d943306b3574d42ae806578ce9cc3e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/bf0c65f1b2d943306b3574d42ae806578ce9cc3e",
+ "reference": "bf0c65f1b2d943306b3574d42ae806578ce9cc3e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "php": "^7.4 || ^8.0"
+ },
+ "replace": {
+ "friendsofphp/php-cs-fixer": "self.version"
+ },
+ "suggest": {
+ "ext-dom": "For handling output formats in XML",
+ "ext-mbstring": "For handling non-UTF8 characters."
+ },
+ "bin": [
+ "php-cs-fixer",
+ "php-cs-fixer.phar"
+ ],
+ "type": "application",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Dariusz Rumiński",
+ "email": "dariusz.ruminski@gmail.com"
+ }
+ ],
+ "description": "A tool to automatically fix PHP code style",
+ "support": {
+ "issues": "https://github.com/PHP-CS-Fixer/shim/issues",
+ "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.48.0"
+ },
+ "time": "2024-01-19T21:45:09+00:00"
+ },
{
"name": "phpdocumentor/reflection-common",
"version": "dev-master",
@@ -4614,19 +4579,19 @@
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "566af9fb94c556de91562fcfcbc392f66680111b"
+ "reference": "0b48e261e0a7bcbf1bd118ffd08e52ea6cfd34af"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/566af9fb94c556de91562fcfcbc392f66680111b",
- "reference": "566af9fb94c556de91562fcfcbc392f66680111b",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/0b48e261e0a7bcbf1bd118ffd08e52ea6cfd34af",
+ "reference": "0b48e261e0a7bcbf1bd118ffd08e52ea6cfd34af",
"shasum": ""
},
"require": {
"ext-filter": "*",
"php": "^7.2 || ^8.0",
"phpdocumentor/reflection-common": "^2.2",
- "phpdocumentor/type-resolver": "1.x-dev@dev",
+ "phpdocumentor/type-resolver": "^1.7",
"phpstan/phpdoc-parser": "^1.7",
"webmozart/assert": "^1.9.1"
},
@@ -4662,7 +4627,7 @@
},
{
"name": "Jaap van Otterdijk",
- "email": "account@ijaap.nl"
+ "email": "opensource@ijaap.nl"
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
@@ -4670,7 +4635,7 @@
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master"
},
- "time": "2022-11-19T20:28:46+00:00"
+ "time": "2024-01-26T20:33:24+00:00"
},
{
"name": "phpdocumentor/type-resolver",
@@ -4678,15 +4643,16 @@
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "06f36c92b434ac686de06b6563e88046943bccbe"
+ "reference": "bc3dc91a5e9b14aa06d1d9e90647c5c5a2cc5353"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/06f36c92b434ac686de06b6563e88046943bccbe",
- "reference": "06f36c92b434ac686de06b6563e88046943bccbe",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/bc3dc91a5e9b14aa06d1d9e90647c5c5a2cc5353",
+ "reference": "bc3dc91a5e9b14aa06d1d9e90647c5c5a2cc5353",
"shasum": ""
},
"require": {
+ "doctrine/deprecations": "^1.0",
"php": "^7.4 || ^8.0",
"phpdocumentor/reflection-common": "^2.0",
"phpstan/phpdoc-parser": "^1.13"
@@ -4728,26 +4694,28 @@
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.x"
},
- "time": "2022-12-16T10:25:14+00:00"
+ "time": "2024-01-18T19:15:27+00:00"
},
{
"name": "phpstan/phpdoc-parser",
- "version": "1.15.3",
+ "version": "1.25.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
- "reference": "61800f71a5526081d1b5633766aa88341f1ade76"
+ "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/61800f71a5526081d1b5633766aa88341f1ade76",
- "reference": "61800f71a5526081d1b5633766aa88341f1ade76",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bd84b629c8de41aa2ae82c067c955e06f1b00240",
+ "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
+ "doctrine/annotations": "^2.0",
+ "nikic/php-parser": "^4.15",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.5",
@@ -4771,58 +4739,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
- "source": "https://github.com/phpstan/phpdoc-parser/tree/1.15.3"
+ "source": "https://github.com/phpstan/phpdoc-parser/tree/1.25.0"
},
- "time": "2022-12-20T20:56:55+00:00"
- },
- {
- "name": "psr/cache",
- "version": "1.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/cache.git",
- "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
- "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Cache\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
- }
- ],
- "description": "Common interface for caching libraries",
- "keywords": [
- "cache",
- "psr",
- "psr-6"
- ],
- "support": {
- "source": "https://github.com/php-fig/cache/tree/master"
- },
- "time": "2016-08-06T20:24:11+00:00"
+ "time": "2024-01-04T17:06:16+00:00"
},
{
"name": "psr/event-dispatcher",
@@ -4830,12 +4749,12 @@
"source": {
"type": "git",
"url": "https://github.com/php-fig/event-dispatcher.git",
- "reference": "e275e2d67d53964a3f13e056886ecd769edee021"
+ "reference": "977ffcf551e3bfb73d90aac3e8e1583fd8d2f89a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/e275e2d67d53964a3f13e056886ecd769edee021",
- "reference": "e275e2d67d53964a3f13e056886ecd769edee021",
+ "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/977ffcf551e3bfb73d90aac3e8e1583fd8d2f89a",
+ "reference": "977ffcf551e3bfb73d90aac3e8e1583fd8d2f89a",
"shasum": ""
},
"require": {
@@ -4873,22 +4792,22 @@
"psr-14"
],
"support": {
- "source": "https://github.com/php-fig/event-dispatcher/tree/master"
+ "source": "https://github.com/php-fig/event-dispatcher"
},
- "time": "2022-06-29T17:22:39+00:00"
+ "time": "2023-09-22T11:10:57+00:00"
},
{
"name": "sebastian/diff",
- "version": "4.0.4",
+ "version": "4.0.x-dev",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
+ "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
- "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
+ "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
"shasum": ""
},
"require": {
@@ -4933,7 +4852,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
- "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
+ "source": "https://github.com/sebastianbergmann/diff/tree/4.0"
},
"funding": [
{
@@ -4941,428 +4860,7 @@
"type": "github"
}
],
- "time": "2020-10-26T13:10:38+00:00"
- },
- {
- "name": "symfony/event-dispatcher",
- "version": "5.4.x-dev",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "abf49cc084c087d94b4cb939c3f3672971784e0c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abf49cc084c087d94b4cb939c3f3672971784e0c",
- "reference": "abf49cc084c087d94b4cb939c3f3672971784e0c",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/event-dispatcher-contracts": "^2|^3",
- "symfony/polyfill-php80": "^1.16"
- },
- "conflict": {
- "symfony/dependency-injection": "<4.4"
- },
- "provide": {
- "psr/event-dispatcher-implementation": "1.0",
- "symfony/event-dispatcher-implementation": "2.0"
- },
- "require-dev": {
- "psr/log": "^1|^2|^3",
- "symfony/config": "^4.4|^5.0|^6.0",
- "symfony/dependency-injection": "^4.4|^5.0|^6.0",
- "symfony/error-handler": "^4.4|^5.0|^6.0",
- "symfony/expression-language": "^4.4|^5.0|^6.0",
- "symfony/http-foundation": "^4.4|^5.0|^6.0",
- "symfony/service-contracts": "^1.1|^2|^3",
- "symfony/stopwatch": "^4.4|^5.0|^6.0"
- },
- "suggest": {
- "symfony/dependency-injection": "",
- "symfony/http-kernel": ""
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\EventDispatcher\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/event-dispatcher/tree/5.4"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2023-01-01T08:32:19+00:00"
- },
- {
- "name": "symfony/event-dispatcher-contracts",
- "version": "2.5.x-dev",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/event-dispatcher-contracts.git",
- "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1",
- "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "psr/event-dispatcher": "^1"
- },
- "suggest": {
- "symfony/event-dispatcher-implementation": ""
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.5-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
- }
- },
- "autoload": {
- "psr-4": {
- "Symfony\\Contracts\\EventDispatcher\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Generic abstractions related to dispatching event",
- "homepage": "https://symfony.com",
- "keywords": [
- "abstractions",
- "contracts",
- "decoupling",
- "interfaces",
- "interoperability",
- "standards"
- ],
- "support": {
- "source": "https://github.com/symfony/event-dispatcher-contracts/tree/2.5"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2022-01-02T09:53:40+00:00"
- },
- {
- "name": "symfony/filesystem",
- "version": "5.4.x-dev",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/filesystem.git",
- "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/648bfaca6a494f3e22378123bcee2894045dc9d8",
- "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-mbstring": "~1.8",
- "symfony/polyfill-php80": "^1.16"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Filesystem\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides basic utilities for the filesystem",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/filesystem/tree/5.4"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2023-01-14T19:14:44+00:00"
- },
- {
- "name": "symfony/options-resolver",
- "version": "5.4.x-dev",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/options-resolver.git",
- "reference": "b03c99236445492f20c61666e8f7e5d388b078e5"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b03c99236445492f20c61666e8f7e5d388b078e5",
- "reference": "b03c99236445492f20c61666e8f7e5d388b078e5",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/polyfill-php73": "~1.0",
- "symfony/polyfill-php80": "^1.16"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\OptionsResolver\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides an improved replacement for the array_replace PHP function",
- "homepage": "https://symfony.com",
- "keywords": [
- "config",
- "configuration",
- "options"
- ],
- "support": {
- "source": "https://github.com/symfony/options-resolver/tree/5.4"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2023-01-01T08:32:19+00:00"
- },
- {
- "name": "symfony/process",
- "version": "5.4.x-dev",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/process.git",
- "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/c5ba874c9b636dbccf761e22ce750e88ec3f55e1",
- "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/polyfill-php80": "^1.16"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Process\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Executes commands in sub-processes",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/process/tree/5.4"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2023-01-01T08:32:19+00:00"
- },
- {
- "name": "symfony/stopwatch",
- "version": "5.4.x-dev",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/stopwatch.git",
- "reference": "bd2b066090fd6a67039371098fa25a84cb2679ec"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/stopwatch/zipball/bd2b066090fd6a67039371098fa25a84cb2679ec",
- "reference": "bd2b066090fd6a67039371098fa25a84cb2679ec",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/service-contracts": "^1|^2|^3"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Stopwatch\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides a way to profile code",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/stopwatch/tree/5.4"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2023-01-01T08:32:19+00:00"
+ "time": "2023-05-07T05:35:17+00:00"
},
{
"name": "vimeo/psalm",
@@ -5593,5 +5091,5 @@
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
- "plugin-api-version": "2.2.0"
+ "plugin-api-version": "2.6.0"
}
diff --git a/lib/Adapter/Groups/NextcloudGroupAdapter.php b/lib/Adapter/Groups/NextcloudGroupAdapter.php
deleted file mode 100644
index dd6c0fb..0000000
--- a/lib/Adapter/Groups/NextcloudGroupAdapter.php
+++ /dev/null
@@ -1,110 +0,0 @@
-logger = $container->get(LoggerInterface::class);
- $this->userManager = $container->get(IUserManager::class);
- $this->request = $container->get(IRequest::class);
- }
-
- /**
- * Transform an NC group into a SCIM group
- */
- public function getCoreGroup(?IGroup $ncGroup): ?CoreGroup
- {
- $this->logger->debug(
- "[" . NextcloudGroupAdapter::class . "] entering getCoreGroup() method"
- );
-
- $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . "/index.php/apps/scimserviceprovider";
-
- if (!isset($ncGroup)) {
- $this->logger->error(
- "[" . NextcloudGroupAdapter::class . "] passed NC group in getCoreGroup() method is null"
- );
-
- return null;
- }
-
- $coreGroup = new CoreGroup();
- $coreGroup->setId($ncGroup->getGID());
- $coreGroup->setDisplayName($ncGroup->getDisplayName());
-
- $ncGroupMembers = $ncGroup->getUsers();
-
- if (isset($ncGroupMembers) && !empty($ncGroupMembers)) {
- $coreGroupMembers = [];
-
- foreach ($ncGroupMembers as $ncGroupMember) {
- $coreGroupMember = new MultiValuedAttribute();
- $coreGroupMember->setValue($ncGroupMember->getUID());
- $coreGroupMember->setRef($baseUrl . "/Users/" . $ncGroupMember->getUID());
- $coreGroupMember->setDisplay($ncGroupMember->getDisplayName());
-
- $coreGroupMembers[] = $coreGroupMember;
- }
-
- $coreGroup->setMembers($coreGroupMembers);
- }
-
- return $coreGroup;
- }
-
- /**
- * Transform a SCIM group into an NC group
- *
- * Note: the second parameter is needed, since we can't instantiate an NC group
- * ourselves and need to receive an instance, passed from somewhere
- */
- public function getNCGroup(?CoreGroup $coreGroup, IGroup $ncGroup): ?IGroup
- {
- $this->logger->debug(
- "[" . NextcloudGroupAdapter::class . "] entering getNCGroup() method"
- );
-
- if (!isset($coreGroup) || !isset($ncGroup)) {
- $this->logger->error(
- "[" . NextcloudGroupAdapter::class . "] passed Core Group in getNCGroup() method is null"
- );
-
- return null;
- }
-
- $ncGroup->setDisplayName($coreGroup->getDisplayName());
-
- if ($coreGroup->getMembers() !== null && !empty($coreGroup->getMembers())) {
- foreach ($coreGroup->getMembers() as $coreGroupMember) {
- // If user with this uid exists, then add it as a member of the group
- if ($coreGroupMember->getValue() !== null && !empty($coreGroupMember->getValue())) {
- if ($this->userManager->userExists($coreGroupMember->getValue())) {
- $ncGroup->addUser($this->userManager->get($coreGroupMember->getValue()));
- }
- }
- }
- }
-
- return $ncGroup;
- }
-}
diff --git a/lib/Adapter/Users/NextcloudUserAdapter.php b/lib/Adapter/Users/NextcloudUserAdapter.php
deleted file mode 100644
index 52609cd..0000000
--- a/lib/Adapter/Users/NextcloudUserAdapter.php
+++ /dev/null
@@ -1,125 +0,0 @@
-logger = $container->get(LoggerInterface::class);
- $this->config = $container->get(IConfig::class);
- $this->userManager = $container->get(IUserManager::class);
- $this->secureRandom = $container->get(ISecureRandom::class);
- }
-
- /**
- * Transform an NC User into a SCIM user
- */
- public function getCoreUser(?IUser $ncUser): ?CoreUser
- {
- $this->logger->debug(
- "[" . NextcloudUserAdapter::class . "] entering getCoreUser() method"
- );
-
- if (!isset($ncUser)) {
- $this->logger->error(
- "[" . NextcloudUserAdapter::class . "] passed NC user in getCoreUser() method is null"
- );
-
- return null;
- }
-
- $coreUser = new CoreUser();
- $coreUser->setId($ncUser->getUID());
-
- $coreUserName = new Name();
- $coreUserName->setFormatted($ncUser->getDisplayName());
- $coreUser->setName($coreUserName);
-
- $coreUser->setUserName($ncUser->getUID());
- $coreUser->setDisplayName($ncUser->getDisplayName());
- $coreUser->setActive($ncUser->isEnabled());
-
- $ncUserExternalId = $this->config->getUserValue($ncUser->getUID(), Application::APP_ID, 'externalId', '');
- $coreUser->setExternalId($ncUserExternalId);
-
- if ($ncUser->getEMailAddress() !== null && !empty($ncUser->getEMailAddress())) {
- $coreUserEmail = new MultiValuedAttribute();
- $coreUserEmail->setValue($ncUser->getEMailAddress());
- $coreUserEmail->setPrimary(true);
-
- $coreUser->setEmails(array($coreUserEmail));
- }
-
- return $coreUser;
- }
-
- /**
- * Transform a SCIM user into an NC User
- *
- * Note: we need the second parameter, since we can't instantiate an NC user in PHP
- * ourselves and need to receive an instance that we can populate with data from the SCIM user
- */
- public function getNCUser(?CoreUser $coreUser, IUser $ncUser): ?IUser
- {
- $this->logger->debug(
- "[" . NextcloudUserAdapter::class . "] entering getNCUser() method"
- );
-
- if (!isset($coreUser) || !isset($ncUser)) {
- $this->logger->error(
- "[" . NextcloudUserAdapter::class . "] passed Core User in getNCUser() method is null"
- );
-
- return null;
- }
-
- if ($coreUser->getDisplayName() !== null && !empty($coreUser->getDisplayName())) {
- $ncUser->setDisplayName($coreUser->getDisplayName());
- }
-
- if ($coreUser->getActive() !== null) {
- $ncUser->setEnabled($coreUser->getActive());
- }
-
- if ($coreUser->getExternalId() !== null && !empty($coreUser->getExternalId())) {
- $this->config->setUserValue($ncUser->getUID(), Application::APP_ID, 'externalId', $coreUser->getExternalId());
- }
-
- if ($coreUser->getEmails() !== null && !empty($coreUser->getEmails())) {
- // Here, we use the first email of the SCIM user to set as the NC user's email
- // TODO: is this ok or should we rather first iterate and search for a primary email of the SCIM user
- if ($coreUser->getEmails()[0] !== null && !empty($coreUser->getEmails()[0])) {
- if ($coreUser->getEmails()[0]->getValue() !== null && !empty($coreUser->getEmails()[0]->getValue())) {
- $ncUser->setEMailAddress($coreUser->getEmails()[0]->getValue());
- }
- }
- }
-
- return $ncUser;
- }
-}
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 4220a8c..4a9d090 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -2,160 +2,43 @@
namespace OCA\SCIMServiceProvider\AppInfo;
-use Error;
-use OCA\SCIMServiceProvider\Adapter\Groups\NextcloudGroupAdapter;
-use OCA\SCIMServiceProvider\Adapter\Users\NextcloudUserAdapter;
-use OCA\SCIMServiceProvider\Controller\GroupBearerController;
-use OCA\SCIMServiceProvider\Controller\GroupController;
-use OCA\SCIMServiceProvider\Controller\UserBearerController;
-use OCA\SCIMServiceProvider\Controller\UserController;
-use OCA\SCIMServiceProvider\DataAccess\Groups\NextcloudGroupDataAccess;
-use OCA\SCIMServiceProvider\DataAccess\Users\NextcloudUserDataAccess;
-use OCA\SCIMServiceProvider\Middleware\BearerAuthMiddleware;
-use OCA\SCIMServiceProvider\Repositories\Groups\NextcloudGroupRepository;
-use OCA\SCIMServiceProvider\Repositories\Users\NextcloudUserRepository;
-use OCA\SCIMServiceProvider\Service\GroupService;
-use OCA\SCIMServiceProvider\Service\SCIMGroup;
-use OCA\SCIMServiceProvider\Service\SCIMUser;
-use OCA\SCIMServiceProvider\Service\UserService;
-use OCA\SCIMServiceProvider\Util\Authentication\BearerAuthenticator;
+use OCA\SCIMServiceProvider\Middleware\AuthMiddleware;
+use OCA\SCIMServiceProvider\Middleware\ContentTypeMiddleware;
+use OCA\SCIMServiceProvider\Middleware\ErrorMiddleware;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
-use OCP\IConfig;
-use OCP\IGroupManager;
-use OCP\IRequest;
-use OCP\IUserManager;
-use OCP\Security\ISecureRandom;
-use Opf\Util\Util;
-use Psr\Container\ContainerInterface;
/**
* The main entry point of the entire application
*/
-class Application extends App implements IBootstrap
-{
- public const APP_ID = 'scimserviceprovider';
+class Application extends App implements IBootstrap {
+ public const APP_ID = 'scimserviceprovider';
+ public const APP_NAME = 'SCIM';
- public function __construct(array $urlParams = [])
- {
- parent::__construct(self::APP_ID, $urlParams);
- }
+ public function __construct() {
+ parent::__construct(self::APP_ID);
+ }
- /**
- * This method is used for registering services, needed as dependencies via dependency injection (DI)
- *
- * Note: "service" here means simply a class that is needed as a dependency somewhere
- * and needs to be injected as such via a DI container (as per PSR-11)
- */
- public function register(IRegistrationContext $context): void
- {
- require realpath(dirname(__DIR__) . '/../vendor/autoload.php');
- $config = require dirname(__DIR__) . '/Config/config.php';
- $context->registerService('SCIMUser', function(ContainerInterface $c) {
- return new SCIMUser(
- $c->get(IUserManager::class),
- $c->get(IConfig::class)
- );
- });
+ /**
+ * This method is used for registering services, needed as dependencies via dependency injection (DI)
+ *
+ * Note: "service" here means simply a class that is needed as a dependency somewhere
+ * and needs to be injected as such via a DI container (as per PSR-11)
+ */
+ public function register(IRegistrationContext $context): void {
+ require_once(__DIR__ . '/../../vendor/autoload.php');
+ $context->registerMiddleware(ErrorMiddleware::class);
+ $context->registerMiddleware(AuthMiddleware::class);
+ $context->registerMiddleware(ContentTypeMiddleware::class);
+ }
- $context->registerService(UserService::class, function(ContainerInterface $c) {
- return new UserService($c);
- });
-
- $context->registerService(GroupService::class, function(ContainerInterface $c) {
- return new GroupService($c);
- });
-
- $context->registerService('UserRepository', function(ContainerInterface $c) {
- return new NextcloudUserRepository($c);
- });
-
- $context->registerService('UserAdapter', function(ContainerInterface $c) {
- return new NextcloudUserAdapter($c);
- });
-
- $context->registerService('UserDataAccess', function(ContainerInterface $c) {
- return new NextcloudUserDataAccess($c);
- });
-
-
- $context->registerService('SCIMGroup', function(ContainerInterface $c) {
- return new SCIMGroup(
- $c->get(IGroupManager::class)
- );
- });
-
- $context->registerService('GroupRepository', function(ContainerInterface $c) {
- return new NextcloudGroupRepository($c);
- });
-
- $context->registerService('GroupAdapter', function(ContainerInterface $c) {
- return new NextcloudGroupAdapter($c);
- });
-
- $context->registerService('GroupDataAccess', function(ContainerInterface $c) {
- return new NextcloudGroupDataAccess($c);
- });
-
- if (isset($config['auth_type']) && !empty($config['auth_type']) && (strcmp($config['auth_type'], 'bearer') === 0)) {
- // If the auth_type is set to "bearer", then use Bearer token endpoints
- // For bearer tokens, we also need to register the bearer token auth middleware
- $context->registerService(BearerAuthenticator::class, function(ContainerInterface $c) {
- return new BearerAuthenticator($c);
- });
-
- $context->registerService(BearerAuthMiddleware::class, function(ContainerInterface $c) {
- return new BearerAuthMiddleware($c);
- });
-
- $context->registerMiddleware(BearerAuthMiddleware::class);
-
- $context->registerService(UserBearerController::class, function (ContainerInterface $c) {
- return new UserBearerController(
- self::APP_ID,
- $c->get(IRequest::class),
- $c->get(UserService::class)
- );
- });
-
- $context->registerService(GroupBearerController::class, function (ContainerInterface $c) {
- return new GroupBearerController(
- self::APP_ID,
- $c->get(IRequest::class),
- $c->get(GroupService::class)
- );
- });
- } else if (!isset($config['auth_type']) || empty($config['auth_type']) || (strcmp($config['auth_type'], 'basic') === 0)) {
- // Otherwise, if auth_type is set to "basic" or if it's not set at all, use Basic auth
- $context->registerService(UserController::class, function (ContainerInterface $c) {
- return new UserController(
- self::APP_ID,
- $c->get(IRequest::class),
- $c->get(UserService::class)
- );
- });
-
- $context->registerService(GroupController::class, function (ContainerInterface $c) {
- return new GroupController(
- self::APP_ID,
- $c->get(IRequest::class),
- $c->get(GroupService::class)
- );
- });
- } else {
- // In the case of any other auth_type value, complain with an error message
- throw new Error("Unknown auth type was set in config file");
- }
- }
-
- /**
- * This method is called for starting (i.e., booting) the application
- *
- * Note: here the method body is empty, since we don't need to do any extra work in it
- */
- public function boot(IBootContext $context): void
- {
- }
+ /**
+ * This method is called for starting (i.e., booting) the application
+ *
+ * Note: here the method body is empty, since we don't need to do any extra work in it
+ */
+ public function boot(IBootContext $context): void {
+ }
}
diff --git a/lib/Config/config.php b/lib/Config/config.php
deleted file mode 100644
index b058570..0000000
--- a/lib/Config/config.php
+++ /dev/null
@@ -1,14 +0,0 @@
- 'bearer',
-
- // Config values for JWTs
- 'jwt' => [
- 'secret' => 'secret'
- ]
-];
diff --git a/lib/Controller/GroupBearerController.php b/lib/Controller/GroupBearerController.php
deleted file mode 100644
index 8a42e66..0000000
--- a/lib/Controller/GroupBearerController.php
+++ /dev/null
@@ -1,99 +0,0 @@
-groupService = $groupService;
- }
-
- /**
- * @NoCSRFRequired
- * @PublicPage
- *
- * @param string $filter
- * @return SCIMListResponse
- * returns a list of groups and their data
- */
- public function index(string $filter = ''): SCIMListResponse
- {
- return $this->groupService->getAll($filter);
- }
-
- /**
- * @NoCSRFRequired
- * @PublicPage
- *
- * gets group info
- *
- * @param string $id
- * @return SCIMJSONResponse
- */
- // TODO: Add filtering support here as well
- public function show(string $id): SCIMJSONResponse
- {
- return $this->groupService->getOneById($id);
- }
-
- /**
- * @NoCSRFRequired
- * @PublicPage
- *
- * @param string $displayName
- * @param array $members
- * @return SCIMJSONResponse
- */
- public function create(string $displayName = '', array $members = []): SCIMJSONResponse
- {
- return $this->groupService->create($displayName, $members);
- }
-
- /**
- * @NoCSRFRequired
- * @PublicPage
- *
- * @param string $id
- *
- * @param string $displayName
- * @param array $members
- * @return SCIMJSONResponse
- */
- public function update(string $id, string $displayName = '', array $members = []): SCIMJSONResponse
- {
- return $this->groupService->update($id, $displayName, $members);
- }
-
- /**
- * @NoCSRFRequired
- * @PublicPage
- *
- * @param string $id
- * @return Response
- */
- public function destroy(string $id): Response
- {
- return $this->groupService->destroy($id);
- }
-}
diff --git a/lib/Controller/GroupController.php b/lib/Controller/GroupController.php
index e9eccde..397e194 100644
--- a/lib/Controller/GroupController.php
+++ b/lib/Controller/GroupController.php
@@ -4,91 +4,107 @@ declare(strict_types=1);
namespace OCA\SCIMServiceProvider\Controller;
+use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse;
+use OCA\SCIMServiceProvider\Responses\SCIMListResponse;
+use OCA\SCIMServiceProvider\Service\GroupService;
+use OCA\SCIMServiceProvider\Util\Util;
use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;
-use OCA\SCIMServiceProvider\Responses\SCIMListResponse;
-use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse;
-use OCA\SCIMServiceProvider\Service\GroupService;
+use Opf\Models\SCIM\Standard\Groups\CoreGroup;
-class GroupController extends ApiController
-{
- /** @var GroupService */
- private $groupService;
+class GroupController extends ApiController {
+ private GroupService $groupService;
- public function __construct(
- string $appName,
- IRequest $request,
- GroupService $groupService
- ) {
- parent::__construct(
- $appName,
- $request
- );
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ GroupService $groupService
+ ) {
+ parent::__construct($appName, $request);
- $this->groupService = $groupService;
- }
+ $this->groupService = $groupService;
+ }
- /**
- * @NoCSRFRequired
- *
- * @param string $filter
- * @return SCIMListResponse
- * returns a list of groups and their data
- */
- public function index(string $filter = ''): SCIMListResponse
- {
- return $this->groupService->getAll($filter);
- }
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @return SCIMListResponse
+ */
+ public function index(): SCIMJSONResponse {
+ $params = $this->request->getParams();
+ $params = Util::parsePagination($params);
+ $scimGroups = $this->groupService->getAll($params["startIndex"], $params["count"]);
+ $list = [];
+ foreach ($scimGroups as $scimGroup) {
+ $list[] = $scimGroup->toSCIM(false, Util::getBaseUrl($this->request));
+ }
+ $total = $this->groupService->countAll();
+ return new SCIMListResponse($list, $params["startIndex"], $total);
+ }
- /**
- * @NoCSRFRequired
- *
- * gets group info
- *
- * @param string $id
- * @return SCIMJSONResponse
- */
- // TODO: Add filtering support here as well
- public function show(string $id): SCIMJSONResponse
- {
- return $this->groupService->getOneById($id);
- }
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @param string $id
+ * @return SCIMJSONResponse
+ */
+ // TODO: Add filtering support here as well
+ public function show(string $id): SCIMJSONResponse {
+ $scimGroup = $this->groupService->get($id);
+ return new SCIMJSONResponse($scimGroup->toSCIM(false, Util::getBaseUrl($this->request)));
+ }
- /**
- * @NoCSRFRequired
- *
- * @param string $displayName
- * @param array $members
- * @return SCIMJSONResponse
- */
- public function create(string $displayName = '', array $members = []): SCIMJSONResponse
- {
- return $this->groupService->create($displayName, $members);
- }
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @param string $displayName
+ * @param array $members
+ * @return SCIMJSONResponse
+ */
+ // public function create(string $displayName, array $members = []): SCIMJSONResponse
+ public function create(): SCIMJSONResponse {
+ $params = $this->request->getParams();
- /**
- * @NoCSRFRequired
- *
- * @param string $id
- *
- * @param string $displayName
- * @param array $members
- * @return SCIMJSONResponse
- */
- public function update(string $id, string $displayName = '', array $members = []): SCIMJSONResponse
- {
- return $this->groupService->update($id, $displayName, $members);
- }
+ $scimGroup = new CoreGroup();
+ $scimGroup->fromSCIM($params);
- /**
- * @NoCSRFRequired
- *
- * @param string $id
- * @return Response
- */
- public function destroy(string $id): Response
- {
- return $this->groupService->destroy($id);
- }
+ $scimGroup = $this->groupService->create($scimGroup);
+ return new SCIMJSONResponse($scimGroup->toSCIM(false, Util::getBaseUrl($this->request)), 201);
+ }
+
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @param string $id
+ * @return SCIMJSONResponse
+ */
+ public function update(string $id): SCIMJSONResponse {
+ $params = $this->request->getParams();
+
+ $scimGroup = new CoreGroup();
+ $scimGroup->fromSCIM($params);
+
+ $scimGroup = $this->groupService->update($id, $scimGroup);
+ return new SCIMJSONResponse($scimGroup->toSCIM(false, Util::getBaseUrl($this->request)));
+ }
+
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @param string $id
+ * @return Response
+ */
+ public function destroy(string $id): Response {
+ $this->groupService->destroy($id);
+
+ $response = new Response();
+ $response->setStatus(204);
+ return $response;
+ }
}
diff --git a/lib/Controller/ServiceProviderConfigurationController.php b/lib/Controller/ServiceProviderConfigurationController.php
index 7a95901..48171d1 100644
--- a/lib/Controller/ServiceProviderConfigurationController.php
+++ b/lib/Controller/ServiceProviderConfigurationController.php
@@ -12,50 +12,46 @@ use OCP\IRequest;
use Opf\Util\Util as SCIMUtil;
use Psr\Log\LoggerInterface;
-class ServiceProviderConfigurationController extends ApiController
-{
- /** @var LoggerInterface */
- private $logger;
+class ServiceProviderConfigurationController extends ApiController {
+ private LoggerInterface $logger;
- public function __construct(string $appName,
- IRequest $request,
- LoggerInterface $logger) {
- parent::__construct($appName,
- $request);
- $this->logger = $logger;
- }
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ LoggerInterface $logger,
+ ) {
+ parent::__construct($appName, $request);
+ $this->logger = $logger;
+ }
- /**
- * @NoCSRFRequired
- * @PublicPage
- */
- public function resourceTypes(): SCIMListResponse
- {
- $baseUrl =
- $this->request->getServerProtocol() . "://"
- . $this->request->getServerHost() . "/"
- . Util::SCIM_APP_URL_PATH;
- $resourceTypes = SCIMUtil::getResourceTypes($baseUrl);
- return new SCIMListResponse($resourceTypes);
- }
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ */
+ public function resourceTypes(): SCIMListResponse {
+ $baseUrl =
+ $this->request->getServerProtocol() . "://"
+ . $this->request->getServerHost() . "/"
+ . Util::SCIM_APP_URL_PATH;
+ $resourceTypes = SCIMUtil::getResourceTypes($baseUrl);
+ return new SCIMListResponse($resourceTypes);
+ }
- /**
- * @NoCSRFRequired
- * @PublicPage
- */
- public function schemas(): SCIMListResponse
- {
- $schemas = SCIMUtil::getSchemas();
- return new SCIMListResponse($schemas);
- }
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ */
+ public function schemas(): SCIMListResponse {
+ $schemas = SCIMUtil::getSchemas();
+ return new SCIMListResponse($schemas);
+ }
- /**
- * @NoCSRFRequired
- * @PublicPage
- */
- public function serviceProviderConfig(): SCIMJSONResponse
- {
- $serviceProviderConfig = SCIMUtil::getServiceProviderConfig();
- return new SCIMJSONResponse($serviceProviderConfig);
- }
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ */
+ public function serviceProviderConfig(): SCIMJSONResponse {
+ $serviceProviderConfig = SCIMUtil::getServiceProviderConfig();
+ return new SCIMJSONResponse($serviceProviderConfig);
+ }
}
diff --git a/lib/Controller/UserBearerController.php b/lib/Controller/UserBearerController.php
deleted file mode 100644
index bf6ea16..0000000
--- a/lib/Controller/UserBearerController.php
+++ /dev/null
@@ -1,121 +0,0 @@
-userService = $userService;
- }
-
- /**
- * @NoCSRFRequired
- * @PublicPage
- *
- * @param string $filter
- * @return SCIMListResponse
- * returns a list of users and their data
- */
- public function index(string $filter = ''): SCIMListResponse
- {
- return $this->userService->getAll($filter);
- }
-
- /**
- * @NoCSRFRequired
- * @PublicPage
- *
- * gets user info
- *
- * @param string $id
- * @return SCIMJSONResponse
- */
- // TODO: Add filtering support here as well
- public function show(string $id): SCIMJSONResponse
- {
- return $this->userService->getOneById($id);
- }
-
- /**
- * @NoCSRFRequired
- * @PublicPage
- *
- * @param bool $active
- * @param string $displayName
- * @param array $emails
- * @param string $externalId
- * @param string $userName
- * @return SCIMJSONResponse
- */
- public function create(
- bool $active = true,
- string $displayName = '',
- array $emails = [],
- string $externalId = '',
- string $userName = ''
- ): SCIMJSONResponse
- {
- return $this->userService->create(
- $active,
- $displayName,
- $emails,
- $externalId,
- $userName
- );
- }
-
- /**
- * @NoCSRFRequired
- * @PublicPage
- *
- * @param string $id
- *
- * @param bool $active
- * @param string $displayName
- * @param array $emails
- * @return SCIMJSONResponse
- */
- public function update(
- string $id,
- bool $active,
- string $displayName = '',
- array $emails = []
- ): SCIMJSONResponse
- {
- return $this->userService->update($id, $active, $displayName, $emails);
- }
-
- /**
- * @NoCSRFRequired
- * @PublicPage
- *
- * @param string $id
- * @return Response
- */
- public function destroy(string $id): Response
- {
- return $this->userService->destroy($id);
- }
-}
diff --git a/lib/Controller/UserController.php b/lib/Controller/UserController.php
index 6c8236a..8ef1e14 100644
--- a/lib/Controller/UserController.php
+++ b/lib/Controller/UserController.php
@@ -4,112 +4,106 @@ declare(strict_types=1);
namespace OCA\SCIMServiceProvider\Controller;
+use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse;
+use OCA\SCIMServiceProvider\Responses\SCIMListResponse;
+use OCA\SCIMServiceProvider\Service\UserService;
+use OCA\SCIMServiceProvider\Util\Util;
use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;
-use OCA\SCIMServiceProvider\Responses\SCIMListResponse;
-use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse;
-use OCA\SCIMServiceProvider\Service\UserService;
+use Opf\Models\SCIM\Standard\Users\CoreUser;
-class UserController extends ApiController
-{
- /** @var UserService */
- private $userService;
+class UserController extends ApiController {
+ private UserService $userService;
- public function __construct(
- string $appName,
- IRequest $request,
- UserService $userService
- ) {
- parent::__construct(
- $appName,
- $request
- );
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ UserService $userService
+ ) {
+ parent::__construct($appName, $request);
- $this->userService = $userService;
- }
+ $this->userService = $userService;
+ }
- /**
- * @NoCSRFRequired
- *
- * @param string $filter
- * @return SCIMListResponse
- * returns a list of users and their data
- */
- public function index(string $filter = ''): SCIMListResponse
- {
- return $this->userService->getAll($filter);
- }
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @return SCIMListResponse
+ */
+ public function index(): SCIMJSONResponse {
+ $params = $this->request->getParams();
+ $params = Util::parsePagination($params);
+ $scimUsers = $this->userService->getAll($params["startIndex"], $params["count"]);
+ $list = [];
+ foreach ($scimUsers as $scimUser) {
+ $list[] = $scimUser->toSCIM(false, Util::getBaseUrl($this->request));
+ }
+ $total = $this->userService->countAll();
+ return new SCIMListResponse($list, $params["startIndex"], $total);
+ }
- /**
- * @NoCSRFRequired
- *
- * gets user info
- *
- * @param string $id
- * @return SCIMJSONResponse
- */
- // TODO: Add filtering support here as well
- public function show(string $id): SCIMJSONResponse
- {
- return $this->userService->getOneById($id);
- }
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @param string $id
+ * @return SCIMJSONResponse
+ */
+ // TODO: Add filtering support here as well
+ public function show(string $id): SCIMJSONResponse {
+ $scimUser = $this->userService->get($id);
+ return new SCIMJSONResponse($scimUser->toSCIM(false, Util::getBaseUrl($this->request)));
+ }
- /**
- * @NoCSRFRequired
- *
- * @param bool $active
- * @param string $displayName
- * @param array $emails
- * @param string $externalId
- * @param string $userName
- * @return SCIMJSONResponse
- */
- public function create(
- bool $active = true,
- string $displayName = '',
- array $emails = [],
- string $externalId = '',
- string $userName = ''
- ): SCIMJSONResponse
- {
- return $this->userService->create(
- $active,
- $displayName,
- $emails,
- $externalId,
- $userName
- );
- }
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @param string $displayName
+ * @param array $members
+ * @return SCIMJSONResponse
+ */
+ public function create(): SCIMJSONResponse {
+ $params = $this->request->getParams();
- /**
- * @NoCSRFRequired
- *
- * @param string $id
- *
- * @param bool $active
- * @param string $displayName
- * @param array $emails
- * @return SCIMJSONResponse
- */
- public function update(
- string $id,
- bool $active,
- string $displayName = '',
- array $emails = []
- ): SCIMJSONResponse
- {
- return $this->userService->update($id, $active, $displayName, $emails);
- }
+ $scimUser = new CoreUser();
+ $scimUser->fromSCIM($params);
- /**
- * @NoCSRFRequired
- *
- * @param string $id
- * @return Response
- */
- public function destroy(string $id): Response
- {
- return $this->userService->destroy($id);
- }
+ $scimGroup = $this->userService->create($scimUser);
+ return new SCIMJSONResponse($scimGroup->toSCIM(false, Util::getBaseUrl($this->request)), 201);
+ }
+
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @param string $id
+ * @return SCIMJSONResponse
+ */
+ public function update(string $id): SCIMJSONResponse {
+ $params = $this->request->getParams();
+
+ $scimUser = new CoreUser();
+ $scimUser->fromSCIM($params);
+
+ $scimUser = $this->userService->update($id, $scimUser);
+ return new SCIMJSONResponse($scimUser->toSCIM(false, Util::getBaseUrl($this->request)));
+ }
+
+ /**
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @param string $id
+ * @return Response
+ */
+ public function destroy(string $id): Response {
+ $this->userService->destroy($id);
+
+ $response = new Response();
+ $response->setStatus(204);
+ return $response;
+ }
}
diff --git a/lib/DataAccess/Groups/NextcloudGroupDataAccess.php b/lib/DataAccess/Groups/NextcloudGroupDataAccess.php
deleted file mode 100644
index e60f87a..0000000
--- a/lib/DataAccess/Groups/NextcloudGroupDataAccess.php
+++ /dev/null
@@ -1,173 +0,0 @@
-logger = $container->get(LoggerInterface::class);
- $this->userManager = $container->get(IUserManager::class);
- $this->groupManager = $container->get(IGroupManager::class);
- }
-
- /**
- * Read all groups
- */
- public function getAll(): ?array
- {
- $ncGroups = $this->groupManager->search('', null, 0);
-
- $this->logger->info(
- "[" . NextcloudGroupDataAccess::class . "] fetched " . count($ncGroups) . " groups"
- );
-
- return $ncGroups;
- }
-
- /**
- * Read a single group by ID
- */
- public function getOneById($id): ?IGroup
- {
- $ncGroup = $this->groupManager->get($id);
-
- if (!isset($ncGroup)) {
- $this->logger->error(
- "[" . NextcloudGroupDataAccess::class . "] group with ID: " . $id . " is null"
- );
- } else {
- $this->logger->info(
- "[" . NextcloudGroupDataAccess::class . "] fetched group with ID: " . $id
- );
- }
-
- return $ncGroup;
- }
-
- /**
- * Create a new group
- */
- public function create($displayName): ?IGroup
- {
- // Note: the createGroup() function requires a $gid parameter
- // However, looking at the NC DB, it seems that the gid of a group
- // and its displayName can have the same value, hence here we pass the
- // displayName parameter to createGroup() and don't need to generate
- // a unique gid for a given group during creation
- $createdNcGroup = $this->groupManager->createGroup($displayName);
-
- if (!isset($createdNcGroup)) {
- $this->logger->error(
- "[" . NextcloudGroupDataAccess::class . "] creation of group with displayName: " . $displayName . " failed"
- );
- return null;
- }
-
- return $createdNcGroup;
- }
-
- /**
- * Update an existing group by ID
- *
- * Note: here, we pass the second parameter, since it carries the data to be updated
- * and we need to pass this data to the group that is to be updated
- */
- public function update(string $id, IGroup $newGroupData): ?IGroup
- {
- $ncGroupToUpdate = $this->groupManager->get($id);
-
- if (!isset($ncGroupToUpdate)) {
- $this->logger->error(
- "[" . NextcloudGroupDataAccess::class . "] group to be updated with ID: " . $id . " doesn't exist"
- );
- return null;
- }
-
- if ($newGroupData->getDisplayName() !== null) {
- $ncGroupToUpdate->setDisplayName($newGroupData->getDisplayName());
- }
-
- if ($newGroupData->getUsers() !== null && !empty($newGroupData->getUsers())) {
- $newNcGroupMembers = [];
-
- foreach ($newGroupData->getUsers() as $newNcGroupMember) {
- // First check if the user is an existing one and only then try to place it as a member of the group
- if ($this->userManager->userExists($newNcGroupMember->getUID())) {
- $ncUserToAdd = $this->userManager->get($newNcGroupMember->getUID());
- $newNcGroupMembers[] = $ncUserToAdd;
- } else {
- $this->logger->error(
- "[" . NextcloudGroupDataAccess::class . "] user from new group data with ID: " . $id . " doesn't exist"
- );
- }
- }
-
- $currentNcGroupMembers = $ncGroupToUpdate->getUsers();
- if (isset($currentNcGroupMembers) && !empty($currentNcGroupMembers)) {
- // If the group can't remove users from itself, then we abort and return null
- if (!$ncGroupToUpdate->canRemoveUser()) {
- return null;
- }
-
- // Else, if we can remove users, then we remove all current users
- foreach ($currentNcGroupMembers as $currentNcGroupMember) {
- $ncGroupToUpdate->removeUser($currentNcGroupMember);
- }
- }
-
- // After having deleted the current members, we try to replace them with the new ones
- if (!$ncGroupToUpdate->canAddUser()) {
- return null;
- }
-
- foreach ($newNcGroupMembers as $newNcGroupMember) {
- $ncGroupToUpdate->addUser($newNcGroupMember);
- }
- }
-
- // Return the now updated NC group
- return $this->groupManager->get($id);
- }
-
- /**
- * Delete an existing group by ID
- */
- public function delete($id): bool
- {
- $ncGroupToDelete = $this->groupManager->get($id);
-
- if (!isset($ncGroupToDelete)) {
- $this->logger->error(
- "[" . NextcloudGroupDataAccess::class . "] group to be deleted with ID: " . $id . " doesn't exist"
- );
-
- return false;
- }
-
- if ($ncGroupToDelete->delete()) {
- return true;
- }
-
- $this->logger->error(
- "[" . NextcloudGroupDataAccess::class . "] couldn't delete group with ID: " . $id
- );
-
- return false;
- }
-}
diff --git a/lib/DataAccess/Users/NextcloudUserDataAccess.php b/lib/DataAccess/Users/NextcloudUserDataAccess.php
deleted file mode 100644
index 857919c..0000000
--- a/lib/DataAccess/Users/NextcloudUserDataAccess.php
+++ /dev/null
@@ -1,144 +0,0 @@
-logger = $container->get(LoggerInterface::class);
- $this->secureRandom = $container->get(ISecureRandom::class);
- $this->userManager = $container->get(IUserManager::class);
- $this->config = $container->get(IConfig::class);
- }
-
- /**
- * Read all users
- */
- public function getAll(): ?array
- {
- $ncUsers = $this->userManager->search('', null, 0);
-
- $this->logger->info(
- "[" . NextcloudUserDataAccess::class . "] fetched " . count($ncUsers) . " users"
- );
-
- return $ncUsers;
- }
-
- /**
- * Read a single user by ID
- */
- public function getOneById($id): ?IUser
- {
- $ncUser = $this->userManager->get($id);
-
- if (!isset($ncUser)) {
- $this->logger->error(
- "[" . NextcloudUserDataAccess::class . "] user with ID: " . $id . " is null"
- );
- } else {
- $this->logger->info(
- "[" . NextcloudUserDataAccess::class . "] fetched user with ID: " . $id
- );
- }
-
- return $ncUser;
- }
-
- /**
- * Create a new user
- */
- public function create($username): ?IUser
- {
- $createdNcUser = $this->userManager->createUser($username, $this->secureRandom->generate(64));
-
- if ($createdNcUser === false) {
- $this->logger->error(
- "[" . NextcloudUserDataAccess::class . "] creation of user with userName: " . $username . " failed"
- );
- return null;
- }
-
- return $createdNcUser;
- }
-
- /**
- * Update an existing user by ID
- *
- * Note: here, we pass the second parameter, since it carries the data to be updated
- * and we need to pass this data to the user that is to be updated
- */
- public function update(string $id, IUser $newUserData): ?IUser
- {
- $ncUserToUpdate = $this->userManager->get($id);
-
- if ($ncUserToUpdate === null) {
- $this->logger->error(
- "[" . NextcloudUserDataAccess::class . "] user to be updated with ID: " . $id . " doesn't exist"
- );
-
- return null;
- }
-
- if ($newUserData->getDisplayName() !== null) {
- $ncUserToUpdate->setDisplayName($newUserData->getDisplayName());
- }
-
- if ($newUserData->isEnabled() !== null && $newUserData->isEnabled()) {
- $ncUserToUpdate->setEnabled($newUserData->isEnabled());
- }
-
- if ($newUserData->getEMailAddress() !== null && !empty($newUserData->getEMailAddress())) {
- $ncUserToUpdate->setEMailAddress($newUserData->getEMailAddress());
- }
-
- // Return the now updated NC user
- return $this->userManager->get($id);
- }
-
- /**
- * Delete an existing user by ID
- */
- public function delete($id): bool
- {
- $ncUserToDelete = $this->userManager->get($id);
-
- if ($ncUserToDelete === null) {
- $this->logger->error(
- "[" . NextcloudUserDataAccess::class . "] user to be deleted with ID: " . $id . " doesn't exist"
- );
-
- return false;
- }
-
- if ($ncUserToDelete->delete()) {
- return true;
- }
-
- $this->logger->error(
- "[" . NextcloudUserDataAccess::class . "] couldn't delete user with ID: " . $id
- );
-
- return false;
- }
-}
diff --git a/lib/Exception/AuthException.php b/lib/Exception/AuthException.php
index ca618fc..6848c64 100644
--- a/lib/Exception/AuthException.php
+++ b/lib/Exception/AuthException.php
@@ -4,6 +4,8 @@ namespace OCA\SCIMServiceProvider\Exception;
use Exception;
-class AuthException extends Exception
-{
-}
\ No newline at end of file
+class AuthException extends Exception {
+ public function __construct(string $message) {
+ parent::__construct($message, 401);
+ }
+}
diff --git a/lib/Exception/ContentTypeException.php b/lib/Exception/ContentTypeException.php
index 5faa3cf..75c2d29 100644
--- a/lib/Exception/ContentTypeException.php
+++ b/lib/Exception/ContentTypeException.php
@@ -4,6 +4,5 @@ namespace OCA\SCIMServiceProvider\Exception;
use Exception;
-class ContentTypeException extends Exception
-{
+class ContentTypeException extends Exception {
}
diff --git a/lib/Middleware/AuthMiddleware.php b/lib/Middleware/AuthMiddleware.php
new file mode 100644
index 0000000..3d6e1e6
--- /dev/null
+++ b/lib/Middleware/AuthMiddleware.php
@@ -0,0 +1,110 @@
+request = $request;
+ $this->userSession = $userSession;
+ $this->userManager = $userManager;
+ $this->groupManager = $groupManager;
+ $this->config = $config;
+ $this->logger = $logger;
+ }
+
+ public function beforeController($controller, $methodName) {
+ $currentRoute = $this->request->getParams()["_route"];
+ $publicRoutes = [
+ "scimserviceprovider.service_provider_configuration.resource_types",
+ "scimserviceprovider.service_provider_configuration.schemas",
+ "scimserviceprovider.service_provider_configuration.service_provider_config"
+ ];
+
+ // Don't require an auth header for public routes
+ if (in_array($currentRoute, $publicRoutes)) {
+ return;
+ }
+
+ $authHeader = $this->request->getHeader('Authorization');
+
+ if (empty($authHeader)) {
+ throw new AuthException("No Authorization header supplied");
+ }
+
+ $authHeaderSplit = explode(' ', $authHeader);
+ if (count($authHeaderSplit) !== 2) {
+ throw new AuthException("Incorrect authorization header");
+ }
+
+ switch ($authHeaderSplit[0]) {
+ case 'Basic':
+ $user = $this->userSession->getUser();
+ if ($user == null) {
+ throw new AuthException("Not logged-in");
+ }
+ break;
+ case 'Bearer':
+ $user = $this->authenticateBearerToken($authHeaderSplit[1]);
+ break;
+ default:
+ throw new AuthException("Incorrect authorization type");
+ break;
+ }
+
+ // For now only allow admin users
+ if (!$this->groupManager->isAdmin($user->getUID())) {
+ throw new AuthException("Not admin");
+ }
+ }
+
+ private function authenticateBearerToken(string $token): ?IUser {
+ $e = new AuthException("Bearer token is invalid");
+ $jwtPayload = [];
+ $jwtSecret = $this->config->getAppValue(Application::APP_ID, "jwt-secret");
+ if (empty($jwtSecret)) {
+ $this->logger->error("jwt-secret not configued");
+ throw $e;
+ }
+ try {
+ $jwtPayload = (array) JWT::decode($token, new Key($jwtSecret, 'HS256'));
+ } catch (Exception $e2) {
+ $this->logger->error($e2->getMessage());
+ throw $e;
+ }
+
+ $username = $jwtPayload['sub'];
+
+ // If we managed to find a user with that username, then auth succeeded
+ $user = $this->userManager->get($username);
+ if ($user === null) {
+ $this->logger->error("User with this username doesn't exist");
+ throw $e;
+ }
+
+ $this->userSession->setUser($user);
+ return $user;
+ }
+}
diff --git a/lib/Middleware/BearerAuthMiddleware.php b/lib/Middleware/BearerAuthMiddleware.php
deleted file mode 100644
index b5339f9..0000000
--- a/lib/Middleware/BearerAuthMiddleware.php
+++ /dev/null
@@ -1,70 +0,0 @@
-request = $container->get(IRequest::class);
- $this->bearerAuthenticator = $container->get(BearerAuthenticator::class);
- }
-
- public function beforeController($controller, $methodName)
- {
- $currentRoute = $this->request->getParams()["_route"];
- $publicRoutes = [
- "scimserviceprovider.service_provider_configuration.resource_types",
- "scimserviceprovider.service_provider_configuration.schemas",
- "scimserviceprovider.service_provider_configuration.service_provider_config"
- ];
-
- // Don't require an auth header for public routes
- if (in_array($currentRoute, $publicRoutes)) {
- return;
- }
-
- $authHeader = $this->request->getHeader('Authorization');
-
- if (empty($authHeader)) {
- throw new AuthException("No Authorization header supplied");
- }
-
- $authHeaderSplit = explode(' ', $authHeader);
- if (count($authHeaderSplit) !== 2 || strcmp($authHeaderSplit[0], "Bearer") !== 0) {
- throw new AuthException("Incorrect Bearer token format");
- }
-
- $token = $authHeaderSplit[1];
-
- // Currently the second parameter to authenticate() is an empty array
- // (the second parameter is meant to carry authorization information)
- if (!$this->bearerAuthenticator->authenticate($token, [])) {
- throw new AuthException("Bearer token is invalid");
- }
- }
-
- public function afterException($controller, $methodName, Exception $exception)
- {
- if ($exception instanceof AuthException) {
- return new SCIMErrorResponse(['message' => $exception->getMessage()], 401);
- }
- }
-}
diff --git a/lib/Middleware/ContentTypeMiddleware.php b/lib/Middleware/ContentTypeMiddleware.php
index 8d8a28f..b2e3503 100644
--- a/lib/Middleware/ContentTypeMiddleware.php
+++ b/lib/Middleware/ContentTypeMiddleware.php
@@ -4,57 +4,47 @@ declare(strict_types=1);
namespace OCA\SCIMServiceProvider\Middleware;
-use Exception;
use OCA\SCIMServiceProvider\Exception\ContentTypeException;
-use OCA\SCIMServiceProvider\Responses\SCIMErrorResponse;
use OCP\AppFramework\Middleware;
use OCP\IRequest;
use Psr\Container\ContainerInterface;
-class ContentTypeMiddleware extends Middleware
-{
- /** @var IRequest */
- private $request;
+class ContentTypeMiddleware extends Middleware {
+ /** @var IRequest */
+ private $request;
- public function __construct(ContainerInterface $container)
- {
- $this->request = $container->get(IRequest::class);
- }
-
- public function beforeController($controller, $methodName)
- {
- $requestMethod = $this->request->getMethod();
+ public function __construct(ContainerInterface $container) {
+ $this->request = $container->get(IRequest::class);
+ }
+
+ public function beforeController($controller, $methodName) {
+ $requestMethod = $this->request->getMethod();
- // If the incoming request is POST or PUT => check the Content-Type header and the request body
- if (in_array(strtolower($requestMethod), array("post", "put"))) {
- $contentTypeHeader = $this->request->getHeader("Content-Type");
- if (!isset($contentTypeHeader) || empty($contentTypeHeader)) {
- throw new ContentTypeException("Content-Type header not set");
- }
+ // If the incoming request is POST or PUT => check the Content-Type header and the request body
+ if (in_array(strtolower($requestMethod), array("post", "put"))) {
+ $contentTypeHeader = $this->request->getHeader("Content-Type");
+ if (!isset($contentTypeHeader) || empty($contentTypeHeader)) {
+ throw new ContentTypeException("Content-Type header not set");
+ }
- // Accept both "application/scim+json" and "application/json" as valid headers
- // See https://www.rfc-editor.org/rfc/rfc7644.html#section-3.8
- if (
- strpos($contentTypeHeader, "application/scim+json") === false
- && strpos($contentTypeHeader, "application/json") === false
- ) {
- throw new ContentTypeException("Content-Type header is not application/scim+json or application/json");
- }
+ // Accept both "application/scim+json" and "application/json" as valid headers
+ // See https://www.rfc-editor.org/rfc/rfc7644.html#section-3.8
+ if (
+ strpos($contentTypeHeader, "application/scim+json") === false
+ && strpos($contentTypeHeader, "application/json") === false
+ ) {
+ throw new ContentTypeException("Content-Type header is not application/scim+json or application/json");
+ }
- // Verify that the request body is indeed valid JSON
- $requestBody = $this->request->getParams();
- if (isset($requestBody) && !empty($requestBody)) {
- $requestBody = array_keys($requestBody)[0];
+ // Verify that the request body is indeed valid JSON
+ $requestBody = $this->request->getParams();
+ if (isset($requestBody) && !empty($requestBody)) {
+ $requestBody = array_keys($requestBody)[0];
- if (json_decode($requestBody) === false) {
- throw new ContentTypeException("Request body is not valid JSON");
- }
- }
- }
- }
-
- public function afterException($controller, $methodName, Exception $exception)
- {
- return new SCIMErrorResponse(['message' => $exception->getMessage()], 400);
- }
-}
\ No newline at end of file
+ if (json_decode($requestBody) === false) {
+ throw new ContentTypeException("Request body is not valid JSON");
+ }
+ }
+ }
+ }
+}
diff --git a/lib/Middleware/ErrorMiddleware.php b/lib/Middleware/ErrorMiddleware.php
new file mode 100644
index 0000000..50a52c9
--- /dev/null
+++ b/lib/Middleware/ErrorMiddleware.php
@@ -0,0 +1,16 @@
+dataAccess = $container->get('GroupDataAccess');
- $this->adapter = $container->get('GroupAdapter');
- $this->logger = $container->get(LoggerInterface::class);
- }
-
- /**
- * Read all groups in SCIM format
- */
- public function getAll(
- $filter = '',
- $startIndex = 0,
- $count = 0,
- $attributes = [],
- $excludedAttributes = []
- ): array {
- $this->logger->info(
- "[" . NextcloudGroupRepository::class . "] reading all groups"
- );
-
- // Read all NC groups
- $ncGroups = $this->dataAccess->getAll();
- $scimGroups = [];
-
- $this->logger->info(
- "[" . NextcloudGroupRepository::class . "] fetched " . count($ncGroups) . " NC groups"
- );
-
- foreach ($ncGroups as $ncGroup) {
- $scimGroup = $this->adapter->getCoreGroup($ncGroup);
- $scimGroups[] = $scimGroup;
- }
-
- $this->logger->info(
- "[" . NextcloudGroupRepository::class . "] transformed " . count($scimGroups) . " SCIM groups"
- );
-
- if (isset($filter) && !empty($filter)) {
- $scimGroupsToFilter = [];
- foreach ($scimGroups as $scimGroup) {
- $scimGroupsToFilter[] = $scimGroup->toSCIM(false);
- }
-
- $filteredScimData = FilterUtil::performFiltering($filter, $scimGroupsToFilter);
-
- $scimGroups = [];
- foreach ($filteredScimData as $filteredScimGroup) {
- $scimGroup = new CoreGroup();
- $scimGroup->fromSCIM($filteredScimGroup);
- $scimGroups[] = $scimGroup;
- }
-
- return $scimGroups;
- }
-
- return $scimGroups;
- }
-
- /**
- * Read a single group by ID in SCIM format
- */
- public function getOneById(
- string $id,
- $filter = '',
- $startIndex = 0,
- $count = 0,
- $attributes = [],
- $excludedAttributes = []
- ): ?CoreGroup {
- $this->logger->info(
- "[" . NextcloudGroupRepository::class . "] reading group with ID: " . $id
- );
-
- $ncGroup = $this->dataAccess->getOneById($id);
- return $this->adapter->getCoreGroup($ncGroup);
- }
-
- /**
- * Create a group from SCIM data
- */
- public function create($object): ?CoreGroup
- {
- $scimGroupToCreate = new CoreGroup();
- $scimGroupToCreate->fromSCIM($object);
-
- $displayName = $scimGroupToCreate->getDisplayName();
- $ncGroupCreated = $this->dataAccess->create($displayName);
-
- $this->logger->info(
- "[" . NextcloudGroupRepository::class . "] creating group with displayName: " . $displayName
- );
-
- if (isset($ncGroupCreated)) {
- // Set the rest of the properties of the NC group with the adapter
- $ncGroupCreated = $this->adapter->getNCGroup($scimGroupToCreate, $ncGroupCreated);
- return $this->adapter->getCoreGroup($ncGroupCreated);
- }
-
- $this->logger->error(
- "[" . NextcloudGroupRepository::class . "] creation of group with displayName: " . $displayName . " failed"
- );
-
- return null;
- }
-
- /**
- * Update a group by ID from SCIM data
- */
- public function update(string $id, $object): ?CoreGroup
- {
- $this->logger->info(
- "[" . NextcloudGroupRepository::class . "] updating group with ID: " . $id
- );
-
- $scimGroupToUpdate = new CoreGroup();
- $scimGroupToUpdate->fromSCIM($object);
-
- $ncGroup = $this->dataAccess->getOneById($id);
-
- if (isset($ncGroup)) {
- $ncGroupToUpdate = $this->adapter->getNCGroup($scimGroupToUpdate, $ncGroup);
- $ncGroupUpdated = $this->dataAccess->update($id, $ncGroupToUpdate);
-
- if (isset($ncGroupUpdated)) {
- return $this->adapter->getCoreGroup($ncGroupUpdated);
- }
- }
-
- $this->logger->error(
- "[" . NextcloudGroupRepository::class . "] update of group with ID: " . $id . " failed"
- );
-
- return null;
- }
-
- /**
- * Delete a group by ID
- */
- public function delete(string $id): bool
- {
- $this->logger->info(
- "[" . NextcloudGroupRepository::class . "] deleting group with ID: " . $id
- );
-
- return $this->dataAccess->delete($id);
- }
-}
diff --git a/lib/Repositories/Users/NextcloudUserRepository.php b/lib/Repositories/Users/NextcloudUserRepository.php
deleted file mode 100644
index 9e3b6a8..0000000
--- a/lib/Repositories/Users/NextcloudUserRepository.php
+++ /dev/null
@@ -1,177 +0,0 @@
-dataAccess = $container->get('UserDataAccess');
- $this->adapter = $container->get('UserAdapter');
- $this->logger = $container->get(LoggerInterface::class);
- }
-
- /**
- * Read all users in SCIM format
- */
- public function getAll(
- $filter = '',
- $startIndex = 0,
- $count = 0,
- $attributes = [],
- $excludedAttributes = []
- ): array {
- $this->logger->info(
- "[" . NextcloudUserRepository::class . "] reading all users"
- );
-
- // Read all NC users
- $ncUsers = $this->dataAccess->getAll();
- $scimUsers = [];
-
- $this->logger->info(
- "[" . NextcloudUserRepository::class . "] fetched " . count($ncUsers) . " NC users"
- );
-
- foreach ($ncUsers as $ncUser) {
- $scimUser = $this->adapter->getCoreUser($ncUser);
- $scimUsers[] = $scimUser;
- }
-
- $this->logger->info(
- "[" . NextcloudUserRepository::class . "] transformed " . count($scimUsers) . " SCIM users"
- );
-
- if (isset($filter) && !empty($filter)) {
- $scimUsersToFilter = [];
- foreach ($scimUsers as $scimUser) {
- $scimUsersToFilter[] = $scimUser->toSCIM(false);
- }
-
- $filteredScimData = FilterUtil::performFiltering($filter, $scimUsersToFilter);
-
- $scimUsers = [];
- foreach ($filteredScimData as $filteredScimUser) {
- $scimUser = new CoreUser();
- $scimUser->fromSCIM($filteredScimUser);
- $scimUsers[] = $scimUser;
- }
-
- return $scimUsers;
- }
-
- return $scimUsers;
- }
-
- /**
- * Read a single user by ID in SCIM format
- */
- public function getOneById(
- string $id,
- $filter = '',
- $startIndex = 0,
- $count = 0,
- $attributes = [],
- $excludedAttributes = []
- ): ?CoreUser {
- $this->logger->info(
- "[" . NextcloudUserRepository::class . "] reading user with ID: " . $id
- );
-
- $ncUser = $this->dataAccess->getOneById($id);
- $scimUser = $this->adapter->getCoreUser($ncUser);
-
- if (isset($filter) && !empty($filter)) {
- $scimUsersToFilter = array($scimUser->toSCIM(false));
- $filteredScimData = FilterUtil::performFiltering($filter, $scimUsersToFilter);
-
- if (!empty($filteredScimData)) {
- $scimUser = new CoreUser();
- $scimUser->fromSCIM($filteredScimData[0]);
- return $scimUser;
- }
- }
-
- return $scimUser;
- }
-
- /**
- * Create a user from SCIM data
- */
- public function create($object): ?CoreUser
- {
- $scimUserToCreate = new CoreUser();
- $scimUserToCreate->fromSCIM($object);
-
- $username = $scimUserToCreate->getUserName();
- $ncUserCreated = $this->dataAccess->create($username);
-
- $this->logger->info(
- "[" . NextcloudUserRepository::class . "] creating user with userName: " . $username
- );
-
- if (isset($ncUserCreated)) {
- // Set the rest of the properties of the NC user via the adapter
- $ncUserCreated = $this->adapter->getNCUser($scimUserToCreate, $ncUserCreated);
- return $this->adapter->getCoreUser($ncUserCreated);
- }
-
- $this->logger->error(
- "[" . NextcloudUserRepository::class . "] creation of user with username: " . $username . " failed"
- );
-
- return null;
- }
-
- /**
- * Update a user by ID from SCIM data
- */
- public function update(string $id, $object): ?CoreUser
- {
- $this->logger->info(
- "[" . NextcloudUserRepository::class . "] updating user with ID: " . $id
- );
-
- $scimUserToUpdate = new CoreUser();
- $scimUserToUpdate->fromSCIM($object);
-
- $ncUser = $this->dataAccess->getOneById($id);
-
- if (isset($ncUser)) {
- $ncUserToUpdate = $this->adapter->getNCUser($scimUserToUpdate, $ncUser);
- $ncUserUpdated = $this->dataAccess->update($id, $ncUserToUpdate);
-
- if (isset($ncUserUpdated)) {
- return $this->adapter->getCoreUser($ncUserUpdated);
- }
- }
-
- $this->logger->error(
- "[" . NextcloudUserRepository::class . "] update of user with ID: " . $id . " failed"
- );
-
- return null;
- }
-
- /**
- * Delete a user by ID
- */
- public function delete(string $id): bool
- {
- $this->logger->info(
- "[" . NextcloudUserRepository::class . "] deleting user with ID: " . $id
- );
-
- return $this->dataAccess->delete($id);
- }
-}
diff --git a/lib/Responses/SCIMErrorResponse.php b/lib/Responses/SCIMErrorResponse.php
index ab37d42..2c5d985 100644
--- a/lib/Responses/SCIMErrorResponse.php
+++ b/lib/Responses/SCIMErrorResponse.php
@@ -2,39 +2,21 @@
namespace OCA\SCIMServiceProvider\Responses;
-use OCP\AppFramework\Http\Response;
+use Exception;
/**
* Class SCIMErrorResponse
*
*/
class SCIMErrorResponse extends SCIMJSONResponse {
- /**
- * response data
- * @var array|object
- */
- protected $data;
- /**
- * Returns the rendered json
- * @return string the rendered json
- * @since 6.0.0
- * @throws \Exception If data could not get encoded
- */
- public function render() {
- $message = [
+ public function __construct(Exception $e) {
+ $data = [
'schemas' => ['urn:ietf:params:scim:api:messages:2.0:Error'],
- 'detail' => $this->data['message'],
+ 'detail' => $e->getMessage(),
'scimType' => '',
- 'status' => $this->getStatus()
+ 'status' => $e->getCode(),
];
- $response = json_encode($message, JSON_UNESCAPED_SLASHES);
-
- if ($response === false) {
- throw new Exception(sprintf('Could not json_encode due to invalid ' .
- 'non UTF-8 characters in the array: %s', var_export($this->data, true)));
- }
-
- return $response;
+ parent::__construct($data, $e->getCode());
}
}
diff --git a/lib/Responses/SCIMJSONResponse.php b/lib/Responses/SCIMJSONResponse.php
index 47576f9..a07a21f 100644
--- a/lib/Responses/SCIMJSONResponse.php
+++ b/lib/Responses/SCIMJSONResponse.php
@@ -2,6 +2,7 @@
namespace OCA\SCIMServiceProvider\Responses;
+use Exception;
use OCP\AppFramework\Http\Response;
/**
diff --git a/lib/Responses/SCIMListResponse.php b/lib/Responses/SCIMListResponse.php
index 835e6fd..248f6e9 100644
--- a/lib/Responses/SCIMListResponse.php
+++ b/lib/Responses/SCIMListResponse.php
@@ -2,56 +2,27 @@
namespace OCA\SCIMServiceProvider\Responses;
-use OCP\AppFramework\Http\Response;
-
-use OCA\SCIMServiceProvider\Exceptions\SCIMException;
-
/**
* Class SCIMListResponse
*
*/
-class SCIMListResponse extends Response {
- /**
- * response data
- * @var array|object
- */
- protected $data;
-
-
+class SCIMListResponse extends SCIMJSONResponse {
/**
* constructor of SCIMListResponse
- * @param array|object $data the object or array that should be transformed
- * @param int $statusCode the Http status code, defaults to 200
+ * @param array $items array that should be transformed
* @since 6.0.0
*/
- public function __construct($data = [], $statusCode = 200) {
- parent::__construct();
-
- $this->data = $data;
- $this->setStatus($statusCode);
- $this->addHeader('Content-Type', 'application/scim+json; charset=utf-8');
- }
-
- /**
- * Returns the rendered json
- * @return string the rendered json
- * @since 6.0.0
- * @throws \Exception If data could not get encoded
- */
- public function render() {
- $scimReponse = [
- 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:ListResponse'],
- 'startIndex' => 1, // todo pagination
- 'Resources' => $this->data,
- 'totalResults' => sizeof($this->data)
- ];
- $response = json_encode($scimReponse, JSON_UNESCAPED_SLASHES);
-
- if ($response === false) {
- throw new SCIMException(sprintf('Could not json_encode due to invalid ' .
- 'non UTF-8 characters in the array: %s', var_export($scimReponse, true)));
+ public function __construct(array $items = [], int $startIndex = 1, int $total = null) {
+ if ($total === null) {
+ $total = sizeof($items);
}
-
- return $response;
+ $data = [
+ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:ListResponse'],
+ 'startIndex' => $startIndex,
+ 'itemsPerPage' => sizeof($items),
+ 'totalResults' => $total,
+ 'Resources' => $items,
+ ];
+ parent::__construct($data);
}
}
diff --git a/lib/Service/GroupService.php b/lib/Service/GroupService.php
index 3840d3a..5965407 100644
--- a/lib/Service/GroupService.php
+++ b/lib/Service/GroupService.php
@@ -6,153 +6,196 @@ namespace OCA\SCIMServiceProvider\Service;
use Exception;
use OCA\SCIMServiceProvider\AppInfo\Application;
-use OCA\SCIMServiceProvider\Responses\SCIMErrorResponse;
-use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse;
-use OCA\SCIMServiceProvider\Responses\SCIMListResponse;
-use OCA\SCIMServiceProvider\Util\Util;
-use OCP\AppFramework\Http\Response;
+use OCP\IGroup;
use OCP\IGroupManager;
-use OCP\IRequest;
-use Psr\Container\ContainerInterface;
+use OCP\IUserManager;
+use Opf\Models\SCIM\Standard\Groups\CoreGroup;
+use Opf\Models\SCIM\Standard\Meta;
+use Opf\Models\SCIM\Standard\MultiValuedAttribute;
use Psr\Log\LoggerInterface;
-class GroupService
-{
- /** @var LoggerInterface */
- private $logger;
+class GroupService {
- /** @var \OCA\SCIMServiceProvider\Repositories\Groups\NextcloudGroupRepository */
- private $repository;
+ private LoggerInterface $logger;
+ private IGroupManager $groupManager;
+ private IUserManager $userManager;
- /** @var IGroupManager */
- private $groupManager;
- /** @var IRequest */
- private $request;
+ public function __construct(LoggerInterface $logger, IGroupManager $groupManager, IUserManager $userManager) {
+ $this->logger = $logger;
+ $this->groupManager = $groupManager;
+ $this->userManager = $userManager;
+ }
- public function __construct(ContainerInterface $container)
- {
- $this->logger = $container->get(LoggerInterface::class);
- $this->repository = $container->get('GroupRepository');
- $this->groupManager = $container->get(IGroupManager::class);
- $this->request = $container->get(IRequest::class);
- }
- public function getAll(string $filter = ''): SCIMListResponse
- {
- $this->logger->info("Reading all groups");
+ private function toSCIM(IGroup $ncGroup): CoreGroup {
+ $scimGroup = new CoreGroup();
+ $scimGroup->setId($ncGroup->getGID());
+ $scimGroup->setDisplayName($ncGroup->getDisplayName());
- $baseUrl = $this->request->getServerProtocol() . "://"
- . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH;
+ $meta = new Meta();
+ $meta->setResourceType("Group");
+ $scimGroup->setMeta($meta);
- $groups = $this->repository->getAll($filter);
+ return $scimGroup;
+ }
- $scimGroups = [];
- if (!empty($groups)) {
- foreach ($groups as $group) {
- $scimGroups[] = $group->toSCIM(false, $baseUrl);
- }
- }
- return new SCIMListResponse($scimGroups);
- }
-
- public function getOneById(string $id): SCIMJSONResponse
- {
- $this->logger->info("Reading group with ID: " . $id);
+ private function getSCIMMembers(IGroup $ncGroup): array {
+ $members = [];
+ foreach ($ncGroup->getUsers() as $ncGroupMember) {
+ $this->logger->info($ncGroupMember->getUID());
+ $member = new MultiValuedAttribute();
+ $member->setType("User");
+ $member->setRef("Users/" . $ncGroupMember->getUID());
+ $member->setValue($ncGroupMember->getUID());
+ $member->setDisplay($ncGroupMember->getDisplayName());
- $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH;
+ $members[] = $member;
+ }
+ return $members;
+ }
- $group = $this->repository->getOneById($id);
- if (!isset($group) || empty($group)) {
- $this->logger->error("Group with ID " . $id . " not found");
- return new SCIMErrorResponse(['message' => 'Group not found'], 404);
- }
- return new SCIMJSONResponse($group->toSCIM(false, $baseUrl));
- }
+ private function updateGroup(IGroup $ncGroup, CoreGroup $scimGroup) {
+ $displayName = $scimGroup->getDisplayName();
+ if (isset($displayName)) {
+ $ncGroup->setDisplayName($displayName);
+ }
- public function create(string $displayName = '', array $members = []): SCIMJSONResponse
- {
- $id = urlencode($displayName);
- // Validate name
- if (empty($id)) {
- $this->logger->error('Group name not supplied', ['app' => 'provisioning_api']);
- return new SCIMErrorResponse(['message' => 'Invalid group name'], 400);
- }
- // Check if it exists
- if ($this->groupManager->groupExists($id)) {
- $this->logger->error("Group to be created already exists");
- return new SCIMErrorResponse(['message' => 'Group exists'], 409);
- }
+ $scimMembers = $scimGroup->getMembers();
+ if (isset($scimMembers)) {
+ foreach ($ncGroup->getUsers() as $ncUser) {
+ $found = false;
+ foreach ($scimMembers as $scimMember) {
+ if ($ncUser->getUID() === $scimMember->getValue()) {
+ $found = true;
+ break;
+ }
+ }
+ if (!$found) {
+ $this->logger->info("remove " . $ncUser->getUID() . " from " . $ncGroup->getGID());
+ $ncGroup->removeUser($ncUser);
+ }
+ }
+ foreach ($scimMembers as $scimMember) {
+ $this->logger->info($scimMember->getValue());
+ $this->logger->info(json_encode($scimMember->jsonSerialize()));
+ $user = $this->userManager->get($scimMember->getValue());
+ if (!isset($user)) {
+ throw new Exception("User " . $scimMember->getValue() . " not found", 404);
+ }
+ if (!$ncGroup->inGroup($user)) {
+ $this->logger->info("add " . $user->getUID() . " from " . $ncGroup->getGID());
+ $ncGroup->addUser($user);
+ $this->logger->info(json_encode($ncGroup->getUsers()));
+ }
+ }
+ }
+ }
- try {
- $this->logger->info("Creating group with displayName: " . $displayName);
+ public function countAll(): int {
+ $ncGroups = $this->groupManager->search("");
+ return sizeof($ncGroups);
+ }
- $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH;
+ /*
+ * @param string $filter
+ * @return OCP\IGroup\IGroup[]
+ */
+ public function getAll(int $startIndex, int $count = null): array {
+ $this->logger->info("Reading all groups");
- $data = [
- 'displayName' => $displayName,
- 'members' => $members
- ];
+ if ($count === 0) {
+ return [];
+ }
- $createdGroup = $this->repository->create($data);
- if (isset($createdGroup) && !empty($createdGroup)) {
- return new SCIMJSONResponse($createdGroup->toSCIM(false, $baseUrl), 201);
- } else {
- $this->logger->error("Creating group failed");
- return new SCIMErrorResponse(['message' => 'Creating group failed'], 400);
- }
- } catch (Exception $e) {
- $this->logger->warning('Failed createGroup attempt with SCIMException exception.', ['app' => Application::APP_ID]);
- throw $e;
- }
- }
+ $ncGroups = $this->groupManager->search("", $count, $startIndex - 1);
- public function update(string $id, string $displayName = '', array $members = []): SCIMJSONResponse
- {
- $this->logger->info("Updating group with ID: " . $id);
+ $scimGroups = [];
+ foreach ($ncGroups as $ncGroup) {
+ $scimGroup = $this->toSCIM($ncGroup);
+ $members = $this->getSCIMMembers($ncGroup);
+ $scimGroup->setMembers($members);
+ $scimGroups[] = $scimGroup;
+ }
- $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH;
+ return $scimGroups;
+ }
- $group = $this->repository->getOneById($id);
- if (!isset($group) || empty($group)) {
- $this->logger->error("Group with ID " . $id . " not found for update");
- return new SCIMErrorResponse(['message' => 'Group not found'], 404);
- }
+ public function get(string $id): CoreGroup {
+ if (!$this->groupManager->groupExists($id)) {
+ throw new Exception("Not found", 404);
+ }
- $data = [
- 'displayName' => $displayName,
- 'members' => $members
- ];
+ $ncGroup = $this->groupManager->get($id);
+ $scimGroup = $this->toSCIM($ncGroup);
- $updatedGroup = $this->repository->update($id, $data);
- if (isset($updatedGroup) && !empty($updatedGroup)) {
- return new SCIMJSONResponse($updatedGroup->toSCIM(false, $baseUrl));
- } else {
- $this->logger->error("Updating group with ID " . $id . " failed");
- return new SCIMErrorResponse(['message' => 'Updating group failed'], 400);
- }
- }
- public function destroy(string $id): Response
- {
- $this->logger->info("Deleting group with ID: " . $id);
+ $members = $this->getSCIMMembers($ncGroup);
+ $scimGroup->setMembers($members);
- if ($id === 'admin') {
- // Cannot delete admin group
- $this->logger->error("Deleting admin group is not allowed");
- return new SCIMErrorResponse(['message' => 'Can\'t delete admin group'], 403);
- }
+ return $scimGroup;
+ }
- $deleteRes = $this->repository->delete($id);
- if ($deleteRes) {
- $response = new Response();
- $response->setStatus(204);
- return $response;
- } else {
- $this->logger->error("Deletion of group with ID " . $id . " failed");
- return new SCIMErrorResponse(['message' => 'Couldn\'t delete group'], 503);
- }
- }
+ public function create(CoreGroup $scimGroup): CoreGroup {
+ // Validate name
+ if (empty($scimGroup->getDisplayName())) {
+ $this->logger->error('Group name not supplied', ['app' => 'provisioning_api']);
+ throw new Exception('Invalid group name', 400);
+ }
+ // Check if it exists
+ if ($this->groupManager->groupExists($scimGroup->getDisplayName())) {
+ $this->logger->error("Group to be created already exists");
+ throw new Exception('Group exists', 409);
+ }
+
+ try {
+ $this->logger->info("Creating group with displayName: " . $scimGroup->getDisplayName());
+
+ $ncGroup = $this->groupManager->createGroup($scimGroup->getDisplayName());
+ $this->updateGroup($ncGroup, $scimGroup);
+ } catch (Exception $e) {
+ $this->logger->warning('Failed createGroup attempt with SCIMException exception.', ['app' => Application::APP_ID]);
+ throw $e;
+ }
+
+ return $this->get($ncGroup->getGID());
+ }
+
+ public function update(string $id, CoreGroup $scimGroup): CoreGroup {
+ $this->logger->info("Updating group with ID: " . $id);
+
+ if (!$this->groupManager->groupExists($id)) {
+ throw new Exception('Group not found', 404);
+ }
+
+ $this->logger->info($scimGroup->toSCIM());
+ // $this->atomic(function () use ($id, $scimGroup) {
+ $ncGroup = $this->groupManager->get($id);
+ $this->updateGroup($ncGroup, $scimGroup);
+ // }, $this->db);
+
+
+ $this->logger->info(json_encode($ncGroup->getUsers()));
+
+ return $this->get($id);
+ }
+
+ public function destroy(string $id): void {
+ $this->logger->info("Deleting group with ID: " . $id);
+
+ if ($id === 'admin') {
+ // Cannot delete admin group
+ $this->logger->error("Deleting admin group is not allowed");
+ throw new Exception('Can\'t delete admin group', 403);
+ }
+
+
+ if (!$this->groupManager->groupExists($id)) {
+ throw new Exception('Group not found', 404);
+ }
+ $ncGroup = $this->groupManager->get($id);
+ $ncGroup->delete();
+ }
}
diff --git a/lib/Service/SCIMGroup.php b/lib/Service/SCIMGroup.php
deleted file mode 100644
index cc897f5..0000000
--- a/lib/Service/SCIMGroup.php
+++ /dev/null
@@ -1,58 +0,0 @@
-groupManager = $groupManager;
- }
-
- /**
- * creates an object with all group data
- *
- * @param string $groupId
- * @param bool $includeScopes
- * @return array
- * @throws Exception
- */
- public function get(string $groupId): array {
- $groupId = urldecode($groupId);
-
- // Check the group exists
- $group = $this->groupManager->get($groupId);
- if ($group === null) {
- return [];
- }
-
- $members = array();
- foreach ($this->groupManager->get($groupId)->getUsers() as $member) {
- $members[] = [
- 'value' => $member->getUID(),
- '$ref' => '/Users/' . $member->getUID(),
- 'display' => $member->getDisplayName()
- ];
- }
-
- return [
- 'schemas' => ['urn:ietf:params:scim:schemas:core:2.0:Group'],
- 'id' => $groupId,
- 'displayName' => $group->getDisplayName(),
- 'externalId' => '1234', // todo
- 'meta' => [
- 'resourceType' => 'Group',
- 'location' => '/Groups/' . $groupId,
- 'created' => '1970-01-01T00:00:00.000Z',
- 'lastModified' => '1970-01-01T00:00:00.000Z'
- ],
- 'members' => $members
- ];
- }
-}
diff --git a/lib/Service/SCIMUser.php b/lib/Service/SCIMUser.php
deleted file mode 100644
index 8801247..0000000
--- a/lib/Service/SCIMUser.php
+++ /dev/null
@@ -1,85 +0,0 @@
-userManager = $userManager;
- $this->config = $config;
- }
-
- /**
- * creates an object with all user data
- *
- * @param string $userId
- * @param bool $includeScopes
- * @return array
- * @throws Exception
- */
- public function get(string $userId): array {
- // Check if the target user exists
- $targetUserObject = $this->userManager->get($userId);
- if ($targetUserObject === null) {
- return [];
- }
-
- $enabled = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'enabled', 'true') === 'true';
- $externalId = $this->config->getUserValue($targetUserObject->getUID(), Application::APP_ID, 'externalId', '');
- $email = $targetUserObject->getSystemEMailAddress();
-
-
- $SCIMUser = [
- 'schemas' => ["urn:ietf:params:scim:schemas:core:2.0:User"],
- 'id' => $userId,
- 'name' => [
- 'formatted' => $targetUserObject->getDisplayName()
- ],
- 'meta' => [
- 'resourceType' => 'User',
- 'location' => '/Users/' . $userId,
- 'created' => '1970-01-01T00:00:00.000Z',
- 'lastModified' => '1970-01-01T00:00:00.000Z'
- ],
- 'userName' => $userId,
- 'displayName' => $targetUserObject->getDisplayName(),
- 'active' => $enabled
- ];
- if ($externalId !== '') {
- $SCIMUser['externalId'] = $externalId;
- }
- if ($email !== null) {
- $SCIMUser['emails'] = [ // todo if no emails
- [
- 'primary' => true,
- 'value' => $email
- ]
- ];
- }
-
- return $SCIMUser;
- }
-
- /**
- * Sets externalId on user
- *
- * @param string $userId
- * @param string $externalId
- * @throws Exception
- */
- public function setExternalId(string $userId, string $externalId) {
- $this->config->setUserValue($userId, Application::APP_ID, 'externalId', $externalId);
- }
-
-}
diff --git a/lib/Service/UserService.php b/lib/Service/UserService.php
index 74291c1..4039840 100644
--- a/lib/Service/UserService.php
+++ b/lib/Service/UserService.php
@@ -5,146 +5,148 @@ declare(strict_types=1);
namespace OCA\SCIMServiceProvider\Service;
use Exception;
-use OCA\SCIMServiceProvider\AppInfo\Application;
-use OCA\SCIMServiceProvider\Responses\SCIMErrorResponse;
-use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse;
-use OCA\SCIMServiceProvider\Responses\SCIMListResponse;
-use OCA\SCIMServiceProvider\Util\Util;
-use OCP\AppFramework\Http\Response;
-use OCP\IRequest;
-use Psr\Container\ContainerInterface;
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\Security\ISecureRandom;
+use Opf\Models\SCIM\Standard\Meta;
+use Opf\Models\SCIM\Standard\MultiValuedAttribute;
+use Opf\Models\SCIM\Standard\Users\CoreUser;
use Psr\Log\LoggerInterface;
-class UserService
-{
- /** @var LoggerInterface */
- private $logger;
+class UserService {
+ /** @var LoggerInterface */
+ private $logger;
- /** @var \OCA\SCIMServiceProvider\Repositories\Users\NextcloudUserRepository */
- private $repository;
+ private IUserManager $userManager;
- /** @var IRequest */
- private $request;
+ /** @var \OCP\Security\ISecureRandom */
+ private $secureRandom;
- public function __construct(ContainerInterface $container)
- {
- $this->logger = $container->get(LoggerInterface::class);
- $this->repository = $container->get('UserRepository');
- $this->request = $container->get(IRequest::class);
- }
+ public function __construct(LoggerInterface $logger, IUserManager $userManager, ISecureRandom $secureRandom) {
+ $this->logger = $logger;
+ $this->userManager = $userManager;
+ $this->secureRandom = $secureRandom;
+ }
- public function getAll(string $filter = ''): SCIMListResponse
- {
- $this->logger->info("Reading all users");
+ private function toSCIM(IUser $ncUser): CoreUser {
+ $scimUser = new CoreUser();
+ $scimUser->setId($ncUser->getUID());
+ $scimUser->setUserName($ncUser->getUID());
+ $scimUser->setDisplayName($ncUser->getDisplayName());
+ $scimUser->setActive($ncUser->isEnabled());
- $baseUrl = $this->request->getServerProtocol() . "://"
- . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH;
+ $emails = [];
+ if (!empty($ncUser->getSystemEMailAddress())) {
+ $email = new MultiValuedAttribute();
+ $email->setValue($ncUser->getSystemEMailAddress());
+ $emails[] = $email;
+ }
+ $scimUser->setEmails($emails);
- $users = $this->repository->getAll($filter);
+ $meta = new Meta();
+ $meta->setResourceType("User");
- $scimUsers = [];
- if (!empty($users)) {
- foreach ($users as $user) {
- $scimUsers[] = $user->toSCIM(false, $baseUrl);
- }
- }
+ $scimUser->setMeta($meta);
- return new SCIMListResponse($scimUsers);
- }
+ return $scimUser;
+ }
- public function getOneById(string $id): SCIMJSONResponse
- {
- $this->logger->info("Reading user with ID: " . $id);
- $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH;
+ private function updateUser(IUser $ncUser, CoreUser $scimUser) {
+ $displayName = $scimUser->getDisplayName();
+ if (isset($displayName)) {
+ $ncUser->setDisplayName($displayName);
+ }
- $user = $this->repository->getOneById($id);
- if (!isset($user) || empty($user)) {
- $this->logger->error("User with ID " . $id . " not found");
- return new SCIMErrorResponse(['message' => 'User not found'], 404);
- }
- return new SCIMJSONResponse($user->toSCIM(false, $baseUrl));
- }
+ $emails = $scimUser->getEmails();
+ if (isset($emails)) {
+ if (sizeof($emails) > 0) {
+ $ncUser->setSystemEMailAddress($emails[0]->getValue());
+ } else {
+ $ncUser->setSystemEMailAddress("");
+ }
+ }
- public function create(
- bool $active = true,
- string $displayName = '',
- array $emails = [],
- string $externalId = '',
- string $userName = ''
- ): SCIMJSONResponse
- {
- try {
- $this->logger->info("Creating user with userName: " . $userName);
+ $active = $scimUser->getActive();
+ if ($active !== null) {
+ $ncUser->setEnabled($active);
+ }
+ }
- $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH;
+ public function countAll(): int {
+ $count = 0;
+ foreach ($this->userManager->countUsers() as $key => $value) {
+ $count = $count + $value;
+ }
+ return $count;
+ }
- $data = [
- 'active' => $active,
- 'displayName' => $displayName,
- 'emails' => $emails,
- 'externalId' => $externalId,
- 'userName' => $userName
- ];
+ public function getAll(int $startIndex, int $count = null): array {
+ $this->logger->info("Reading all users");
- $createdUser = $this->repository->create($data);
- if (isset($createdUser) && !empty($createdUser)) {
- return new SCIMJSONResponse($createdUser->toSCIM(false, $baseUrl), 201);
- } else {
- $this->logger->error("Creating user failed");
- return new SCIMErrorResponse(['message' => 'Creating user failed'], 400);
- }
- } catch (Exception $e) {
- $this->logger->warning('Failed createUser attempt with SCIMException exeption.', ['app' => Application::APP_ID]);
- throw $e;
- }
- }
+ if ($count === 0) {
+ return [];
+ }
- public function update(
- string $id,
- bool $active,
- string $displayName = '',
- array $emails = []
- ): SCIMJSONResponse
- {
- $this->logger->info("Updating user with ID: " . $id);
+ $ncUsers = $this->userManager->search("", $count, $startIndex - 1);
- $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH;
+ $scimUsers = [];
+ foreach ($ncUsers as $ncUser) {
+ $scimUsers[] = $this->toSCIM($ncUser);
+ }
- $user = $this->repository->getOneById($id);
- if (!isset($user) || empty($user)) {
- $this->logger->error("User with ID " . $id . " not found for update");
- return new SCIMErrorResponse(['message' => 'User not found'], 404);
- }
+ return $scimUsers;
+ }
- $data = [
- 'active' => $active,
- 'displayName' => $displayName,
- 'emails' => $emails
- ];
- $updatedUser = $this->repository->update($id, $data);
- if (isset($updatedUser) && !empty($updatedUser)) {
- return new SCIMJSONResponse($updatedUser->toSCIM(false, $baseUrl));
- } else {
- $this->logger->error("Updating user with ID " . $id . " failed");
- return new SCIMErrorResponse(['message' => 'Updating user failed'], 400);
- }
- }
+ public function get(string $id): CoreUser {
+ $this->logger->info("Reading user with ID: " . $id);
- public function destroy(string $id): Response
- {
- $this->logger->info("Deleting user with ID: " . $id);
+ if (!$this->userManager->userExists($id)) {
+ throw new Exception("Not found", 404);
+ }
- $deleteRes = $this->repository->delete($id);
+ $ncUser = $this->userManager->get($id);
+ return $this->toSCIM($ncUser);
+ }
- if ($deleteRes) {
- $response = new Response();
- $response->setStatus(204);
- return $response;
- } else {
- $this->logger->error("Deletion of user with ID " . $id . " failed");
- return new SCIMErrorResponse(['message' => 'Couldn\'t delete user'], 503);
- }
- }
+ public function create(CoreUser $scimUser): CoreUser {
+ $this->logger->info("Creating user with userName: " . $scimUser->getUserName());
+
+
+ if ($this->userManager->userExists($scimUser->getUserName())) {
+ $this->logger->error("User to be created already exists");
+ throw new Exception('User exists', 409);
+ }
+
+ $ncUser = $this->userManager->createUser($scimUser->getUserName(), $this->secureRandom->generate(64));
+ $this->updateUser($ncUser, $scimUser);
+
+ return $this->get($ncUser->getUID());
+ }
+
+ public function update(string $id, CoreUser $scimUser): CoreUser {
+ $this->logger->info("Updating user with ID: " . $id);
+
+ if (!$this->userManager->userExists($id)) {
+ throw new Exception("Not found", 404);
+ }
+
+ $this->logger->info($scimUser->toSCIM());
+
+ $ncUser = $this->userManager->get($id);
+ $this->updateUser($ncUser, $scimUser);
+
+ return $this->get($id);
+ }
+
+ public function destroy(string $id): void {
+ $this->logger->info("Deleting user with ID: " . $id);
+
+ if (!$this->userManager->userExists($id)) {
+ throw new Exception('User not found', 404);
+ }
+ $ncUser = $this->userManager->get($id);
+ $ncUser->delete();
+ }
}
diff --git a/lib/Util/Authentication/BearerAuthenticator.php b/lib/Util/Authentication/BearerAuthenticator.php
deleted file mode 100644
index 08a81a4..0000000
--- a/lib/Util/Authentication/BearerAuthenticator.php
+++ /dev/null
@@ -1,56 +0,0 @@
-logger = $container->get(LoggerInterface::class);
- $this->userManager = $container->get(IUserManager::class);
- }
-
- public function authenticate(string $credentials, array $authorizationInfo): bool
- {
- $jwtPayload = [];
- $jwtSecret = Util::getConfigFile()['jwt']['secret'];
- try {
- $jwtPayload = (array) JWT::decode($credentials, new Key($jwtSecret, 'HS256'));
- } catch (Exception $e) {
- $this->logger->error($e->getMessage());
- return false;
- }
-
- // If the 'user' claim is missing from the JWT, then auth is considered to have failed
- if (!isset($jwtPayload['user']) || empty($jwtPayload['user'])) {
- $this->logger->error("No \"user\" claim found in JWT");
- return false;
- }
-
- $username = $jwtPayload['user'];
-
- // If we managed to find a user with that username, then auth succeeded
- $user = $this->userManager->get($username);
- if ($user !== null) {
- return true;
- }
-
- $this->logger->error("User with this username doesn't exist");
- return false;
- }
-}
diff --git a/lib/Util/Util.php b/lib/Util/Util.php
index 7f869b8..93d11f2 100644
--- a/lib/Util/Util.php
+++ b/lib/Util/Util.php
@@ -2,15 +2,32 @@
namespace OCA\SCIMServiceProvider\Util;
-class Util
-{
- public const SCIM_APP_URL_PATH = "index.php/apps/scimserviceprovider";
+use OCP\IRequest;
- public static function getConfigFile()
- {
- $configFilePath = dirname(__DIR__) . '/Config/config.php';
- $config = require($configFilePath);
+class Util {
+ public const SCIM_APP_URL_PATH = "index.php/apps/scimserviceprovider";
- return $config;
- }
+ public static function getBaseUrl(IRequest $request) : string {
+ return $request->getServerProtocol() . "://" . $request->getServerHost() . "/" . Util::SCIM_APP_URL_PATH;
+ }
+
+ public static function parsePagination(array $params): array {
+ if (isset($params["startIndex"])) {
+ $startIndex = intval($params["startIndex"]);
+ if ($startIndex < 1) {
+ $startIndex = 1;
+ }
+ $params["startIndex"] = $startIndex;
+ } else {
+ $params["startIndex"] = 1;
+ }
+ if (isset($params["count"])) {
+ $count = intval($params["count"]);
+ if ($count < 0) {
+ $count = 0;
+ }
+ $params["count"] = $count;
+ }
+ return $params;
+ }
}