77use App \Exceptions \InvalidArgumentException ;
88use App \Exceptions \NotFoundException ;
99use App \Exceptions \WrongCredentialsException ;
10+ use App \Model \Entity \ExternalLogin ;
1011use App \Model \Entity \Group ;
1112use App \Model \Entity \Login ;
1213use App \Model \Entity \SecurityEvent ;
1314use App \Model \Entity \User ;
1415use App \Model \Entity \UserUiData ;
16+ use App \Model \Repository \ExternalLogins ;
1517use App \Model \Repository \Logins ;
1618use App \Model \Repository \SecurityEvents ;
1719use App \Exceptions \BadRequestException ;
@@ -36,6 +38,12 @@ class UsersPresenter extends BasePresenter
3638 */
3739 public $ logins ;
3840
41+ /**
42+ * @var ExternalLogins
43+ * @inject
44+ */
45+ public $ externalLogins ;
46+
3947 /**
4048 * @var SecurityEvents
4149 * @inject
@@ -294,7 +302,7 @@ private function changeUserEmail(User $user, ?string $email)
294302 }
295303
296304 if (filter_var ($ email , FILTER_VALIDATE_EMAIL ) === false ) {
297- throw new InvalidArgumentException ("Provided email is not in correct format " );
305+ throw new InvalidArgumentException (' email ' , "Provided email is not in correct format " );
298306 }
299307
300308 $ oldEmail = $ user ->getEmail ();
@@ -375,7 +383,7 @@ private function changeUserPassword(
375383
376384 if (!$ password || !$ passwordConfirm ) {
377385 // old password was provided but the new ones not, illegal state
378- throw new InvalidArgumentException ("New password was not provided " );
386+ throw new InvalidArgumentException (' password|passwordConfirm ' , "New password was not provided " );
379387 }
380388
381389 // passwords need to be handled differently
@@ -764,4 +772,76 @@ public function actionSetAllowed(string $id)
764772 $ this ->users ->flush ();
765773 $ this ->sendSuccessResponse ($ this ->userViewFactory ->getUser ($ user ));
766774 }
775+
776+ public function checkUpdateExternalLogin (string $ id , string $ service )
777+ {
778+ $ user = $ this ->users ->findOrThrow ($ id );
779+ if (!$ this ->userAcl ->canSetExternalIds ($ user )) {
780+ throw new ForbiddenRequestException ();
781+ }
782+
783+ // in the future, we might consider cross-checking the service ID
784+ }
785+
786+ /**
787+ * Add or update existing external ID of given authentication service.
788+ * @POST
789+ * @param string $id identifier of the user
790+ * @param string $service identifier of the authentication service (login type)
791+ * @Param(type="post", name="externalId", validation="string:1..128")
792+ * @throws InvalidArgumentException
793+ */
794+ public function actionUpdateExternalLogin (string $ id , string $ service )
795+ {
796+ $ user = $ this ->users ->findOrThrow ($ id );
797+
798+ // make sure the external ID is not used for another user
799+ $ externalId = $ this ->getRequest ()->getPost ("externalId " );
800+ $ anotherUser = $ this ->externalLogins ->getUser ($ service , $ externalId );
801+ if ($ anotherUser ) {
802+ if ($ anotherUser ->getId () !== $ id ) {
803+ // oopsie, this external ID is alreay used for a different user
804+ throw new InvalidArgumentException ('externalId ' , "This ID is already used by another user. " );
805+ }
806+ // otherwise the external ID is already set to this user, so there is nothing to change...
807+ } else {
808+ // create/update external login entry
809+ $ login = $ this ->externalLogins ->findByUser ($ user , $ service );
810+ if ($ login ) {
811+ $ login ->setExternalId ($ externalId );
812+ } else {
813+ $ login = new ExternalLogin ($ user , $ service , $ externalId );
814+ }
815+
816+ $ this ->externalLogins ->persist ($ login );
817+ }
818+
819+ $ this ->sendSuccessResponse ($ this ->userViewFactory ->getUser ($ user ));
820+ }
821+
822+ public function checkRemoveExternalLogin (string $ id , string $ service )
823+ {
824+ $ user = $ this ->users ->findOrThrow ($ id );
825+ if (!$ this ->userAcl ->canSetExternalIds ($ user )) {
826+ throw new ForbiddenRequestException ();
827+ }
828+
829+ // in the future, we might consider cross-checking the service ID
830+ }
831+
832+ /**
833+ * Remove external ID of given authentication service.
834+ * @DELETE
835+ * @param string $id identifier of the user
836+ * @param string $service identifier of the authentication service (login type)
837+ */
838+ public function actionRemoveExternalLogin (string $ id , string $ service )
839+ {
840+ $ user = $ this ->users ->findOrThrow ($ id );
841+ $ login = $ this ->externalLogins ->findByUser ($ user , $ service );
842+ if ($ login ) {
843+ $ this ->externalLogins ->remove ($ login );
844+ }
845+ $ this ->sendSuccessResponse ($ this ->userViewFactory ->getUser ($ user ));
846+ }
767847}
0 commit comments