Angular ADAL requires authentication for non authenticated routes - angularjs

Scenario is AngularJS 1.6.5 SPA, c# WebAPI and Azure AD (AAD) for authentication. I'm using Angular-ADAL library to handle the authentication and angular-route to handle routes. Strange thing is that routes that CAN be anonymous (i.e. DO NOT require the requireADLogin: true in the route definition) but need to go to the backend (for example to get an image or to get data from the API), get intercepted by ADAL and never get to the backend/API.
My routes are defined like so, when I want a route protected:
.when('/clasesDeDocumento', {
templateUrl: 'app/views/mantenedores/clasesDeDocumento/clasesDeDocumento.html',
controller: 'clasesDeDocumentoController',
controllerAs: 'vm',
requireADLogin: true,
title: "clases de documentos"
})
And similar to the above, but without the requiredADLogin: true when not protected.
According to the documentation:
Routes that do not specify the requireADLogin=true property are added to the anonymousEndpoints array automatically.
Clicking on an unprotected link does not take you to the Azaure Authentication page, however the backend/API request gets intercepted and an error is thrown.
I have solved this (manually) adding an anonymousEndpoints array, but for larger applications, this would not be feasible.
Any ideas?

This is expected behavior. The requireADLogin and anonymousEndpoints parameters are used for the different purpose.
The requireADLogin is used for the whether the routes are needle to protect. If it is true, the app will requires users to authenticate first before they can access the route.
The anonymousEndpoints parameter is used help the adal library to determine whether the $http service required to inject the token. And by default, the route URL will be added into the anonymousEndpoints if we doesn't specify the requireADLogin parameter to true(refer the routeChangeHandler).

Related

By what mechanism does AngularJS fetch remote partials?

According to the doc, $sceDelegateProvider can be used to whitelist domains from which Angular may fetch partials hosted on a different domain than the app, to support such a route configuration:
$routeProvider.when('/test1/', {
templateUrl: 'https://serverName.com/html/test1.html',
controller: 'test1'
});
A comment in the repo (and a lack of imagination) lead to me to believe remote partials would be fetched via JSONP. Can anyone confirm that?

Adal Infinite redirection + Edge + Trusted sites

Background:
I have a single page app (built using Angular) which uses adal and adal-angular to authenticate against Azure Active Directory.
Have been using version 1.0.7 of adal and adal-angular (tried using 1.0.14 as well but still no luck) and ui-router for routing.
Issue:
Few of our users are getting continuous authentication loop while trying to access the web application on Edge browser specifically.
Note that it works fine with IE, Chrome and Firefox. Surprisingly it also works fine when Edge is opened in InPrivate window.
This issue is device specific, user specific and only occurs in Edge.
Workaround:
When my site is added to the trusted sites (via Control Panel -> Internet Options), the authentication loop issue is resolved and everything works seamlessly.
Any idea why this is happening?
From what I’m assuming as of now is that it’s a cookie issue when adal writes to the auth cookie to the site and Edge can’t seem to read it?
Also any suggestions for a better fix/workaround for this? As I can’t tell all my users to go and add my website to their trusted sites collection.
Code snippet of app.js:
function authenticationInit(adalAuthenticationServiceProvider, $httpProvider, $locationProvider) {
$locationProvider.html5Mode(false);
var endpoints = {
// Map the location of a request to an API to a the identifier of the associated resource
"EndPointKey": window.config.aadEndPointUrl,
"EndPointValue": window.config.aadResouceIdUrl
};
adalAuthenticationServiceProvider.init(
{
instance: window.config.AADAuthenticationInstance,
tenant: window.config.tenant,
clientId: window.config.clientId,
extraQueryParameter: 'nux=1',
endpoints: endpoints
}, $httpProvider);
}
function registerRoutes($stateProvider) {
$stateProvider
.state('home', {
templateUrl: getViewUrl('widgets'),
controller: 'WidgetsController',
controllerAs: 'widget',
url: '/dashboard'
})
.state('terms',
{
templateUrl: getViewUrl('terms'),
controller: 'TermsController',
controllerAs: 'terms',
url: '/terms'
})
}
$rootScope.$on('$locationChangeStart', function (e) {
if (adalAuthenticationService.userInfo.isAuthenticated == false) { // Will be executed during first time login and token expiration
adalAuthenticationService.login();
}
});
$rootScope.$on("adal:loginSuccess", function (e) { // Will be executed after AAD authentication is successful
NavigationFactory.navigateTo('home');
});
Have raised the same query here- https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/537
adal uses localStorage to save the tokens and reads data from it later on (you also have the option to change it to session storage). The point is that if adal is not able to write into local storage, you will not get the tokens. There is a setting in Microsoft Edge that lets the websites store data. To enable this, go to: Settings>Advanced Settings and enable: 'Let sites save protected media license on my device'. I hope this fixes your issue.

Parsing Oauth 2.0 return parameters in angular-ui-router

I'm attempting to authenticate a user using Google's Oauth 2.0 API. When my app HREF's to the Google authentication page, it successfully passes information back to my AngularJS app. However, I'm not sure how best to handle the returned URL-encoded data.
This is the format it is returned as:
#access_token=...
&token_type=Bearer
&expires_in=3600
My main problem is that this string begins with # instead of ? as is traditionally done with URL encoded parameters.
In my stateProvider config, I've implemented the callback state as such:
.state 'auth.googlecallback',
url: '/googlecallback/#{accessToken}&token_type={tokenType}&expires_in={expiresIn}'
templateUrl: 'views/auth/googlecallback.html'
controller: 'GoogleCallbackCtrl as gVm'
The above URL is an example of what I have tried. When the url is simply /googlecallback/, the page loads successfully, even when navigated to using the Google Oauth link. But the moment I had the # symbol, the state breaks and I can't parse the state params for the data inside.
I've looked into using the angular-oauth library on GitHub, but it hasn't been updated in 2 years, and it doesn't appear to allow Oauth authentication for more than just Google (I want to use Facebook and Google).
What is the correct way to handle the the Oauth URL data in angular-ui-router?
To be frank, I don't think this will actually answer your question, but I was helping some friends with this earlier today. They were unable to handle the URI via the ui-router. Instead, they had to delegate parsing the parameters and making the appropriate request to their view controller. Using the Angular $location service and some remapping functions, we were able to get the parameters out of the # query syntax into a hash that he was able to push back to the server in his request. The code looked similarly to the following:
var paramsArray = $location.hash().split('&')
var payload = {};
angular.forEach(paramsArray, function (param) {
var arr = param.split('='),
key = param[0],
value = param[1];
payload[key] = value;
});
This could absolutely be simplified but this was what he was trying to accomplish for his strategy.
That all being said, I'm personally not a fan of trying to accomplish OAuth strategy on the client. You have private keys that usually need to get exchanged to complete the full handshake. If possible, it would be best if you did the following:
Redirect the client to the appropriate OAuth path
Have the redirect go to a server endpoint that can process the oauth request and complete the handshake.
Have the server endpoint that the oauth request redirected to, redirect to your success landing page with any additional response
objects required by your application.
Doing this would protect your private keys and most web frameworks have modules/packages/gems/plugins/etc. for implementing oauth for all the mainstream providers. Hope this helps you in the right direction.

UI Router and Satellizer force login

I know this question isn't very specific, but I have no idea how to solve this issue or where I should begin..
I'm using Satellizer for authentication with UI-Router. the problem is I have 2 routes /sign_in and /profile the /sign_in issue a request to the server returning the user info (when successful login)... this currentUser info is used all over the application...
the problem is when a user try to go to /profile before login, it renders the empty view... how do I enforce user to login first before accessing these "restricted" views ?!
again I know this isn't a specific question but I really don't know where to start
Have a look into handling the routechangestart event on UI router, I did something similar.
I think this will give you some clues http://arthur.gonigberg.com/2013/06/29/angularjs-role-based-auth/
The key is that you need to create some form of authentication service where you can store the logged in state of the user, and since a service is invoked once (singleton) it is shared across your app (controllers, other services, etc). Then in the routechangestart event handling you can prevent routing to the target page and redirect to login if user is not authenticated.
I found the answer in this Github Repo
the idea is to have role based authentication as discussed in the Repo readme.
so the code for forbidding the unauthorised access to /profile would be something like the following
$stateProvider.state("profile", {
url: "/profile",
templateUrl: "app/profile/profile.html",
controller: "ProfileCtrl",
controllerAs: "user",
data: {
permissions: {
except: ['guest'],
redirectTo: 'sign_in'
}
}
});
given that you defined the guest role
definePermissions = function(Permission, Identity) {
Permission.defineRole('guest', function(stateParams) {
return !Identity.currentUser;
});
};

Use Angular routing in an Apache-hosted app

My app's frontend is done in Angular while the backend is in PHP. For this last reason, I am using Apache as app server.
I want to use Angular's routing feature, that is, $routeProvider.when(), with conditional params (aka named groups) such as /user/:id/, where :id would be a parameter passed to the controller specified in the route.
Obviously, Apache tries to handle the request e.g., /user/21 by looking for a resource called 21 inside of the user directory, and thus returns a 404 error, instead of letting Angular routing load the resource at /user and using the value 21 to do internal stuff (such as calling an API).
How would I have to setup Apache so that some requests are left to be handled by Angular?

Resources