angularsingle-sign-onsiteminder

Angular 4 + Siteminder HTTP headers issue


I have been struggling for a couple weeks to "integrate" Siteminder authentication with my nodejs/angular 4 web application.

On server side (node) I have:

app.get('*', function(req, res) {
  //read Siteminder headers
  if (authenticated) {
    res.sendFile(path.join(__dirname, 'dist/index.html'));
  }else{
    res.sendFile(path.join(__dirname, 'dist/accessDenied.html'));
  }          
}

Angular router handles the rest.

And this works for initial access control (api and services that retrieve data are on a different machine, this is just a front-end/client application).

However, now users want roles, like edit/view and I need to find a way to pass those roles from Siteminder headers to angular front-end to handle permissions. I've played around with interceptors with no luck, seems to only work with requests created from within angular app. I've also tried some suggestions found on related questions that were asked on the Siteminder / node /angular topic but still no luck.

I'm very new with node/angular, thanks for your patience and help.


Solution

  • I ended up finding the answer myself, posting details below, in case anyone is interested. Decided to use Angular universal express engine, following this example.

    Essentially what this does is it allows Angular to run on server side, where it can access request headers, and then they can be injected for use on the client side.

    In my main.server.ts:

    app.engine('html',  (_, options, callback) => {
        let engine = ngExpressEngine({
            bootstrap: ServerAppModule,
            providers: [ { provide: 'headers', useFactory: () => options.req.headers } ]
        });
    
        engine(_, options, callback)
    });
    
    app.set('view engine', 'html');
    app.set('views', 'dist');
    
    app.use('/', express.static('dist', {index: false}));
    
    ROUTES.forEach(route => {
      app.get(route, (req, res) => {
    
        console.log('Yaaay Siteminder headers:');
        console.dir(req.headers);
    
        res.render('index', {
          req: req,
          res: res
        });
      });
    });
    

    And then in my app.component.ts:

    export class AppComponent implements OnInit {
    
         constructor(private cache: TransferState, private injector: Injector, @Inject(PLATFORM_ID) private platformId: Object) {}
    
        ngOnInit() {
            if (isPlatformServer(this.platformId)) 
           {                
              this.cache.set('user_role', this.injector.get('headers').sm_role);                
            }
        }  
    
    }
    

    After which I can just inject private cache: TransferState in any of my components and can use the headers anywhere, for fine tuned access.

    Et voilĂ .