1616use OCA \UserOIDC \Listener \TimezoneHandlingListener ;
1717use OCA \UserOIDC \Service \ID4MeService ;
1818use OCA \UserOIDC \Service \SettingsService ;
19- use OCA \UserOIDC \User \Backend ;
19+ use OCA \UserOIDC \Service \ProvisioningService ;
20+ use OCA \UserOIDC \Service \ProvisioningEventService ;
21+ use OCA \UserOIDC \MagentaBearer \MBackend ;
2022use OCP \AppFramework \App ;
2123use OCP \AppFramework \Bootstrap \IBootContext ;
2224use OCP \AppFramework \Bootstrap \IBootstrap ;
2729use OCP \IUserManager ;
2830use OCP \IUserSession ;
2931use Throwable ;
32+ use Psr \Container \ContainerInterface ;
33+
34+ // this is needed only for the special, shortened client login flow
35+ use OCP \Security \ISecureRandom ;
36+ use OCP \ISession ;
3037
3138class Application extends App implements IBootstrap {
3239 public const APP_ID = 'user_oidc ' ;
@@ -40,15 +47,20 @@ public function __construct(array $urlParams = []) {
4047 }
4148
4249 public function register (IRegistrationContext $ context ): void {
50+ // Register the composer autoloader required for the added jwt-token libs
51+ include_once __DIR__ . '/../../vendor/autoload.php ' ;
52+
53+ // override registration of provisioning srevice to use event-based solution
54+ $ this ->getContainer ()->registerService (ProvisioningService::class, function (ContainerInterface $ c ): ProvisioningService {
55+ return $ c ->get (ProvisioningEventService::class);
56+ });
57+
4358 /** @var IUserManager $userManager */
4459 $ userManager = $ this ->getContainer ()->get (IUserManager::class);
4560
4661 /* Register our own user backend */
47- $ this ->backend = $ this ->getContainer ()->get (Backend::class);
48- // this was done before but OC_User::useBackend calls OC::$server->getUserManager()->registerBackend anyway
49- // so the backend was registered twice, leading to wrong user count (double)
50- // $userManager->registerBackend($this->backend);
51- // TODO check if it can be replaced by $userManager->registerBackend($this->backend); in our case
62+ $ this ->backend = $ this ->getContainer ()->get (MBackend::class);
63+ $ userManager ->registerBackend ($ this ->backend );
5264 OC_User::useBackend ($ this ->backend );
5365
5466 $ context ->registerEventListener (LoadAdditionalScriptsEvent::class, TimezoneHandlingListener::class);
@@ -65,10 +77,70 @@ public function boot(IBootContext $context): void {
6577 try {
6678 $ context ->injectFn (\Closure::fromCallable ([$ this , 'registerRedirect ' ]));
6779 $ context ->injectFn (\Closure::fromCallable ([$ this , 'registerLogin ' ]));
80+ // this is the custom auto-redirect for MagentaCLOUD client access
81+ $ context ->injectFn (\Closure::fromCallable ([$ this , 'registerNmcClientFlow ' ]));
6882 } catch (Throwable $ e ) {
6983 }
7084 }
7185
86+ /**
87+ * This is the automatic redirect exclusively for Nextcloud/Magentacloud clients
88+ * completely skipping consent layer
89+ */
90+ private function registerNmcClientFlow (IRequest $ request ,
91+ IURLGenerator $ urlGenerator ,
92+ ProviderMapper $ providerMapper ,
93+ ISession $ session ,
94+ ISecureRandom $ random ): void {
95+ $ providers = $ this ->getCachedProviders ($ providerMapper );
96+
97+ // Handle immediate redirect on client first-time login
98+ $ isClientLoginFlow = false ;
99+ try {
100+ $ isClientLoginFlow = $ request ->getPathInfo () === '/login/flow ' ;
101+ } catch (Exception $ e ) {
102+ // in case any errors happen when checking for the path do not apply redirect logic as it is only needed for the login
103+ }
104+ if ($ isClientLoginFlow ) {
105+ // only redirect if Telekom provider registered
106+ $ tproviders = array_values (array_filter ($ providers , function ($ p ) {
107+ return strtolower ($ p ->getIdentifier ()) === "telekom " ;
108+ }));
109+ if (count ($ tproviders ) == 0 ) {
110+ // always show normal login flow as error fallback
111+ return ;
112+ }
113+
114+ $ stateToken = $ random ->generate (
115+ 64 ,
116+ ISecureRandom::CHAR_LOWER .ISecureRandom::CHAR_UPPER .ISecureRandom::CHAR_DIGITS
117+ );
118+ $ session ->set ('client.flow.state.token ' , $ stateToken );
119+
120+ // call the service to get the params, but suppress the template
121+ // compute grant redirect Url to go directly to Telekom login
122+ $ redirectUrl = $ urlGenerator ->linkToRoute ('core.ClientFlowLogin.grantPage ' , [
123+ 'stateToken ' => $ stateToken ,
124+ // grantPage service operation is deriving oauth2 client name (again),
125+ // so we simply pass on clientIdentifier or empty string
126+ 'clientIdentifier ' => $ request ->getParam ('clientIdentifier ' , '' ),
127+ 'direct ' => $ request ->getParam ('direct ' , '0 ' )
128+ ]);
129+ if ($ redirectUrl === null ) {
130+ // always show normal login flow as error fallback
131+ return ;
132+ }
133+
134+ // direct login, consent layer later
135+ $ targetUrl = $ urlGenerator ->linkToRoute (self ::APP_ID . '.login.login ' , [
136+ 'providerId ' => $ tproviders [0 ]->getId (),
137+ 'redirectUrl ' => $ redirectUrl
138+ ]);
139+ header ('Location: ' . $ targetUrl );
140+ exit ();
141+ }
142+ }
143+
72144 private function registerRedirect (IRequest $ request , IURLGenerator $ urlGenerator , SettingsService $ settings , ProviderMapper $ providerMapper ): void {
73145 $ providers = $ this ->getCachedProviders ($ providerMapper );
74146 $ redirectUrl = $ request ->getParam ('redirect_url ' );
0 commit comments