2020use OCA \UserOIDC \Listener \InternalTokenRequestedListener ;
2121use OCA \UserOIDC \Listener \TimezoneHandlingListener ;
2222use OCA \UserOIDC \Listener \TokenInvalidatedListener ;
23+ use OCA \UserOIDC \MagentaBearer \MBackend ;
2324use OCA \UserOIDC \Service \ID4MeService ;
25+ use OCA \UserOIDC \Service \ProvisioningEventService ;
26+ use OCA \UserOIDC \Service \ProvisioningService ;
2427use OCA \UserOIDC \Service \SettingsService ;
2528use OCA \UserOIDC \Service \TokenService ;
2629use OCA \UserOIDC \User \Backend ;
3134use OCP \IConfig ;
3235use OCP \IL10N ;
3336use OCP \IRequest ;
37+ use OCP \ISession ;
3438use OCP \IURLGenerator ;
3539use OCP \IUserManager ;
3640use OCP \IUserSession ;
41+ use OCP \Security \ISecureRandom ;
42+
43+ // this is needed only for the special, shortened client login flow
44+ use Psr \Container \ContainerInterface ;
3745use Throwable ;
3846
3947class Application extends App implements IBootstrap {
@@ -48,11 +56,19 @@ public function __construct(array $urlParams = []) {
4856 }
4957
5058 public function register (IRegistrationContext $ context ): void {
59+ // Register the composer autoloader required for the added jwt-token libs
60+ include_once __DIR__ . '/../../vendor/autoload.php ' ;
61+
62+ // override registration of provisioning srevice to use event-based solution
63+ $ this ->getContainer ()->registerService (ProvisioningService::class, function (ContainerInterface $ c ): ProvisioningService {
64+ return $ c ->get (ProvisioningEventService::class);
65+ });
66+
5167 /** @var IUserManager $userManager */
5268 $ userManager = $ this ->getContainer ()->get (IUserManager::class);
5369
5470 /* Register our own user backend */
55- $ this ->backend = $ this ->getContainer ()->get (Backend ::class);
71+ $ this ->backend = $ this ->getContainer ()->get (MBackend ::class);
5672
5773 $ config = $ this ->getContainer ()->get (IConfig::class);
5874 if (version_compare ($ config ->getSystemValueString ('version ' , '0.0.0 ' ), '32.0.0 ' , '>= ' )) {
@@ -84,10 +100,73 @@ public function boot(IBootContext $context): void {
84100 try {
85101 $ context ->injectFn (\Closure::fromCallable ([$ this , 'registerRedirect ' ]));
86102 $ context ->injectFn (\Closure::fromCallable ([$ this , 'registerLogin ' ]));
103+
104+ // this is the custom auto-redirect for MagentaCLOUD client access
105+ $ context ->injectFn (\Closure::fromCallable ([$ this , 'registerNmcClientFlow ' ]));
87106 } catch (Throwable $ e ) {
88107 }
89108 }
90109
110+ /**
111+ * This is the automatic redirect exclusively for Nextcloud/Magentacloud clients completely skipping consent layer
112+ */
113+ private function registerNmcClientFlow (IRequest $ request ,
114+ IURLGenerator $ urlGenerator ,
115+ ProviderMapper $ providerMapper ,
116+ ISession $ session ,
117+ ISecureRandom $ random ): void {
118+ $ providers = $ this ->getCachedProviders ($ providerMapper );
119+
120+ // Handle immediate redirect on client first-time login
121+ $ isClientLoginFlow = false ;
122+
123+ try {
124+ $ isClientLoginFlow = $ request ->getPathInfo () === '/login/flow ' ;
125+ } catch (Exception $ e ) {
126+ // in case any errors happen when checking for the path do not apply redirect logic as it is only needed for the login
127+ }
128+
129+ if ($ isClientLoginFlow ) {
130+ // only redirect if Telekom provider registered
131+ $ tproviders = array_values (array_filter ($ providers , function ($ p ) {
132+ return strtolower ($ p ->getIdentifier ()) === 'telekom ' ;
133+ }));
134+
135+ if (count ($ tproviders ) == 0 ) {
136+ // always show normal login flow as error fallback
137+ return ;
138+ }
139+
140+ $ stateToken = $ random ->generate (64 , ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS );
141+ $ session ->set ('client.flow.state.token ' , $ stateToken );
142+
143+ // call the service to get the params, but suppress the template
144+ // compute grant redirect Url to go directly to Telekom login
145+ $ redirectUrl = $ urlGenerator ->linkToRoute ('core.ClientFlowLogin.grantPage ' , [
146+ 'stateToken ' => $ stateToken ,
147+ // grantPage service operation is deriving oauth2 client name (again),
148+ // so we simply pass on clientIdentifier or empty string
149+ 'clientIdentifier ' => $ request ->getParam ('clientIdentifier ' , '' ),
150+ 'direct ' => $ request ->getParam ('direct ' , '0 ' )
151+ ]);
152+
153+ if ($ redirectUrl === null ) {
154+
155+ // always show normal login flow as error fallback
156+ return ;
157+ }
158+
159+ // direct login, consent layer later
160+ $ targetUrl = $ urlGenerator ->linkToRoute (self ::APP_ID . '.login.login ' , [
161+ 'providerId ' => $ tproviders [0 ]->getId (),
162+ 'redirectUrl ' => $ redirectUrl
163+ ]);
164+
165+ header ('Location: ' . $ targetUrl );
166+ exit ();
167+ }
168+ }
169+
91170 private function checkLoginToken (TokenService $ tokenService ): void {
92171 $ tokenService ->checkLoginToken ();
93172 }
0 commit comments