How to disable or bypass MSAL authentication when running Angular e2e tests?
Asked Answered
N

3

10

I want to set up some end to end tests for my Angular application, which requires the use of the MSAL library to authenticate with some downstream services. When I try to run my e2e tests locally, the MSAL library is forcing me to authenticate with a username/password.

This is a problem because our CI/CD e2e testing should not have any human-intervention; thus I am looking for a way to either bypass the MSAL authentication or set up a service-account to login. Unfortunately there is not a lot of documentation surrounding MSAL for Angular (especially when it comes to e2e testing), but this seems like a common issue that others may have run into.

I've tried to disable the MsalModule from our app.module.ts file but I am still prompted for login when I try to run the application. I've also seen some articles trying to programmatically log in, but this does not work for us as MSAL is technically not an Angular component we are able to touch.

app.module.ts:

@NgModule({
  ...
  imports: [
    ...
    MsalModule.forRoot({
      clientID: '<client_id>',
      authority: <microsoft_authority_url>,
      validateAuthority: true,
      redirectUri: "http://localhost:4200/",
      cacheLocation : "localStorage",
      postLogoutRedirectUri: "http://localhost:4200/",
      navigateToLoginRequestUrl: true,
      popUp: true,
      consentScopes: [ "user.read"],
      unprotectedResources: ["https://www.microsoft.com/en-us/"],
      protectedResourceMap: protectedResourceMap,
      logger: loggerCallback,
      correlationId: '1234',
      level: LogLevel.Info,
      piiLoggingEnabled: true
    })
  ],
  entryComponents: [SaveDialogComponent,
                    GenericDialog, MassChangeDialogComponent],
  providers: [TitleCasePipe,
    {provide: HTTP_INTERCEPTORS, useClass: MsalInterceptor, multi: true}],
  bootstrap: [AppComponent]
})
export class AppModule { }

Expected result: removing the MSAL authentication module should allow our application to run without needing to log in.

Actual result: application is still prompting for log in, or does not render correctly.

Nutwood answered 14/6, 2019 at 14:48 Comment(2)
Thanks for asking this question ... I'm running into the same issue. Did you come up with a solution to your question?Margetts
@Margetts we did come up with a solution, I believe we were able to disable the msal feature but can’t remember the specifics. I will reach out to my coworker and see if he remembers how he fixed thisNutwood
T
17

I solved that by adding a property enableMsal into my environment.test.ts (and same property with value true in prod environment):

export const environment = {
  production: false,
  enableMsal: false,
};

Then used it in routing module (by default called app-routing.module.ts, like this:

//... 
const guards: any[] = environment.enableMsal ? [MsalGuard] : [];

const routes: Routes = [
  {path: '', redirectTo: '/main', pathMatch: 'full'},
  {path: 'main', component: MainComponent, canActivate: guards},
  {path: 'other', component: OtherComponent, canActivate: guards},
];
//...

In case you don't know how to configure multiple environments, angular has a good guide here.

Trant answered 24/11, 2019 at 19:22 Comment(0)
C
7

To Bypass MSAL you can mock the implementation of MsalGuard, MsalService and MsalInterceptor inside main-skip-login.ts which is a replica of main.ts file.

import { MsalGuard, MsalInterceptor, MsalService } from '@azure/msal-angular';

MsalGuard.prototype.canActivate = () => true;

MsalInterceptor.prototype.intercept = (req, next) => {
  const access = localStorage.getItem('access_token');
  req = req.clone({
    setHeaders: {
      Authorization: `Bearer ${access}`
    }
  });
  return next.handle(req);
};

MsalService.prototype.getAccount = (): any => {
  if (!localStorage.getItem('access_token')) return undefined;
  return {
    idToken: {
      scope: [],
      // other claims if required
    }
  };
};

Then create a configuration named e2e inside angular.json and replace main.ts with main-skip-login.ts.

"configurations": {
            "e2e": {
              "fileReplacements": [
                {
                  "replace": "src/main.ts",
                  "with": "src/main-skip.login.ts"
                }
              ]
}}

Now you can run project with this configuration and set localStorage with authentic token to bypass MSAL auth flow. You can also play with mocking logic to get the desired outcome.

Chlorine answered 24/6, 2020 at 16:54 Comment(0)
N
1

In order to resolve this issue, we set up another config file for running e2e tests.

We utilized a custom ngular.routing.module that does not contain the property canActivate: [MsalGuard]

Nutwood answered 3/9, 2019 at 13:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.