AngularJS Set SSL Headers - angularjs

I've started a new Yeoman AngularJS project, hosted in Apache. I am getting data from a WCF Restful service hosted in IIS with CORS enabled. I am able to get data with no problem. However, currently I am passing the user name and password each time on the url, and overriding the user validator on the WCF side, which is extremely bad and is not secure by any means. Don't worry this only a development environment. How do I set the header values with the user credentials prior to calling the SSL service? Basically how do I setup the web request in AngularJS prior to making the service call?

I ended up creating a custom header on my AngularJS app called "Authorization", setting the header value on the app, and then reading the header values on the WCF Service.
The way I was able to accomplish this is as follows:
First, I had to change the WCF service to allow me to get the Http Context. To do that I had to first enable ASP Net Compatibility on the web.config like so:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
I had to add a Global.asax to my WebService project and modify the BeginRequest event to allow my new custom header like so:
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Authorization");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, PUT, DELETE");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
I then allowed ASP Net Compatibility on the service class by adding mark up to the class like so:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
At this point I was able to get Http Context headers on the WCF Service. Below is how I retrieved the header value in the service code:
HttpContext.Current.Request.Headers["Authorization"]
At this point, the WCF service is able to consume my custom header. The last step is to set the header from the AngularJS service factory code like below:
app.factory('serviceFactory', ['$http', function ($http) {
var urlBase = 'https://domainName.com/MyService.svc/';
var dataFactory = {};
var success = {};
serviceFactory.Login = function (username, password) {
return $http({
url: urlBase + "WebServiceLoginMethodName",
type: 'GET',
dataType: 'json',
headers: { 'Authorization': "Basic " + username + ":" + password }
});
};
This does not fire the User Validator on the web service, but this does let me put the username and password in the Http Headers, which I will encrypt and decrypt on the app and service as a next step.

Related

Activiti REST returns 401 after GET request

When i tried to send a GET request to Activiti REST URL, using POSTMAN and configuring an authorization parameter (kermit:kermit) it works like a charm.
But when i tried to do the same thing, only with Angular $http service, it returns the following error:
XMLHttpRequest cannot load http://localhost:8080/activiti-rest/service/repository/deployments. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not allowed access. The response had HTTP status code 401.
Here is my controller:
(function() {
'use strict';
angular
.module('doktorat-app-test')
.controller('TestController', TestController);
TestController.$inject = ['$http', '$base64'];
function TestController($http, $base64) {
var tcr = this;
$http.defaults.headers.common['Authorization'] = 'Basic ' + $base64.encode('kermit:kermit');
tcr.text = 'ssdsds';
$http.get('http://localhost:8080/activiti-rest/service/repository/deployments')
.then(function(response){
tcr.text = response.data;
});
}
})();
Has anyone encountered on similar error?
Spent more then 2 days trying to resolve this issue, but without any success.
P.S. I am using NodeJS http-server to run my Angular App, which runs on port 8081.
Since you are trying to access rest api which is on http://localhost:8081/ From http://localhost:8080/, browser will check if your server implement CORS using preflight request. You can get detail about CORS on below url:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Normally application hosted in one server will not be allowed to access the resources hosted in other sever.This restriction is implemented by all most all browser now a days.
In order to make it work, your rest api server has to tell that some other servers will also be allowed to call. For this , you need to implement CORS filer in your rest api server.
Since you didn't specify which langauge you are using in REST, i am providing an open source CORS filter library for JAVA:
http://software.dzhuvinov.com/cors-filter.html
which solves your problem.
To allow CORS for a specific domain you can use a middleware as below:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:8081");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, X-Requested-With");
next();
});

Accessing Django server from AngularJs App: Easy authentication solution?

I've been looking everywhere but can't seem to find an answer that has been helpful.
I have written an angular app that is trying to pull data from a django RESTful backend that was written by my company. I have a username and password, but I'm not sure how to write the get request to provide the authentication credentials to the backend. I'm also confused about what exactly I'm supposed to provide in the header.
Eventually, we will be communicating using nginx.
What I want
I'm looking for a fix to write in the angular app itself. I'm trying to write the angular app as separate as possible from the django backend. I have already enabled cross origin resource sharing.
This will be a band aid fix just to display data from the backend. It does not need to be permanent by any means.
So far I have tried:
app.factory('mySamples', ['$http', function($http) {
return $http.get('website/api/foo', {
headers: {'username':"foo", 'password': 'bar'}
}).success(function(data) {
return data;
}).error(function(err) {
return err;
});
};
app.factory('mySamples', ['$http', function($http) {
return $http({method: 'GET', url: 'website/api/samples/', headers: {
'user': 'foo', 'auth':'bar'}
});
};
The second factory I wrote returns METHOD: OPTIONS in the networks inspector under returned header. Does anybody have a quick fix just to get data from my api?
EDIT: My django backend doesn't support basic authentication, only session based. How would I edit my get request?
You first need to know what kind of Authentication and Authorization is implemented on the server side i.e. What headers the server looks for authentication/authorization credentials in and what format is expected by the server, then send the credentials under that header key. For example if the sever checks for Authentication credentials in the Authorization header in format username::password then you need to add the headers like
headers: {'Authorization': 'johndoe::password'}
(1) If you are using basic authentication, you can add a basic authentication like so:
app.factory('mySamples', ['$http', function($http) {
var credentials = btoa(username + ':' + authtoken);
var authorization = {
'Authorization': 'Basic ' + credentials
};
return $http({method: 'GET', url: 'website/api/samples/', headers: authorization });
};
If all of your $http calls use this same auth, you can use $http.defaults.headers.common.Authorization
(2) I’m pretty sure nginx does not provide session handling—you’ll have to do that in django.
(3) I don’t typically use sessions with REST since REST is usually done stateless.
OP asked how to enable CORS. Enabling CORS is usually done on the server-side. You can do it in nginx by adding:
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
To the appropriate location block. You can also do this on the django side with middleware pacakges like django-cors-middleware (https://pypi.python.org/pypi/django-cors-middleware) or django-cors-headers (https://pypi.python.org/pypi/django-cors-headers).

Windows Authentication is not working with WebAPI when called through Angular

I have two Projects, one is MVC (using Angular) and other is WebAPI. Windows Authentication is working fine in MVC (thanks to this article)
However, when I am making AJAX calls from MVC site through Angular to WebAPI then I get following error:
HTTP Error 401.2 - Unauthorized You are not authorized to view this
page due to invalid authentication headers.
Most likely causes:
No authentication protocol (including anonymous)is selected in IIS.
Only integrated authentication is enabled, and a client browser was used that does not support integrated authentication.
Integrated authentication is enabled and the request was sent through a proxy that changed the authentication headers before they
reach the Web server.
The Web server is not configured for anonymous access and a required authorization header was not received.
The "configuration/system.webServer/authorization" configuration section may be explicitly denying the user access.
I read this post but it is talking about HttpClient (while I am using JQuery or Angular) to make calls.
PLEASE NOTE: If I hit the WebAPI URL through Browser then Authentication works fine. So it must be something to do with AJAX request.
This is my code in Global.asax
protected void Application_BeginRequest()
{
if (ValidateRequest())
{
//var origin = Request.Headers["Origin"];
Response.Headers.Remove("Access-Control-Allow-Origin");
Response.AddHeader("Access-Control-Allow-Origin", matchedOrigin);
Response.Headers.Remove("Access-Control-Allow-Headers");
Response.AddHeader("Access-Control-Allow-Headers", CustomConfig.HEADERS);
Response.Headers.Remove("Access-Control-Allow-Methods");
Response.AddHeader("Access-Control-Allow-Methods", CustomConfig.METHODS);
}
// This is to avoid "Method 405 Not allowed" error
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
Response.Flush();
Response.End(); //Send the Empty Response for Options (Preflight Request)
}
}
I have done enough research but couldn't find a solution. So couple of things.
How can I resolve my above issue
Secondly what's the best approach for using Windows Authentication based on my scenario (And Project setup).
If it works in the browser directly but not when JavaScript is involved it will be a CORS issue so check you have it all enabled, including handling pre-flight OPTIONS verb.
In your case you will also need to check you are passing credentials e.g.
[EnableCors(origins: "http://myclient.azurewebsites.net", headers: "*",
methods: "*", SupportsCredentials = true)]
Note with credentials I don't think you can have a wildcard origin - needs explicit list.
See this link: https://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api#credentials.
In your Angular $http request make sure you have the property withCredentials: true.
Or if you are making a JQuery ajax call then:
xhrFields: {
withCredentials: true
}
If you still have pre-flight problems try a custom message handler like this (change the origin(s)):
public class ExampleMessageHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (request.Headers.Contains("Origin") && request.Method.Method == "OPTIONS")
{
var response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Headers.Add("Access-Control-Allow-Origin", "http://localhost:8080/");
response.Headers.Add("Access-Control-Allow-Credentials", "true");
response.Headers.Add("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization");
response.Headers.Add("Access-Control-Allow-Methods", "DELETE, POST, PUT, OPTIONS, GET");
}
return base.SendAsync(request, cancellationToken);
}
}
Then:
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new ExampleMessageHandler());

Not able to get response from API through angular?

My code is as below
$scope.LoadSearchResults = function () {
$scope.hotels = '';
$scope.allData = '';
var mydata = '';
$http({
url: 'myurl',
Authorization : 'code',
method: 'POST',
header: { 'Content-type': 'text/json' }
})
.success(function (mydata) {
$scope.hotels = JSON.parse(JSON.stringify(mydata.SearchResponse.Hotels.Hotel));
$scope.allData = JSON.parse(JSON.stringify(mydata.SearchResponse.Hotels.Hotel));
$scope.AllLocality($scope.allData);
})
.error(function (mydata) {
$scope.hotels = "Failed";
console.log(JSON.stringify(mydata));
});
}
and getting error is
"Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://example.com/some-page. (Reason: CORS header 'Access-Control-Allow-Origin' missing)."
How could I solve this problem?
this is not an Angular problem.
the reason is you are firing a cross origin request (e.g. your app sits on a domain and the request specified by url: 'myurl' is for a different domain) and HTTP does not allow it unless permissions are specifically added by the server receiving the request by adding a CORS header to the response.
to solve your problem you please check here one of the 4 options (I am sure you can find more depending on your specific setup):
make your app fire the request to the same domain, which is normally the preferred and most secure approach (e.g. the web app hosting the angular code is also responsible of responding to the xhr you are doing via $http)
if you have control on how the server creates the response, it should be fairly easy to add such headers (I cannot add an example here as it is entirely dependent on the web server or application gateway you are using)
if you don't have control over the server response (and most importantly its headers) you can add your own server in the middle that would act as a request proxy, thus making your JS app firing the request to your server (not incurring CORS problems) and the server itself making the proxy request to the 3rd party provider
if you just need GET requests (which doesn't seem the case from your snippet) you can use angular's $http JSONP if the server supports this type of requests.
Hi I have got it same issue but now i have resolved it by using below:
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Authorization");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
please pass header on controller after parent::__construct();

Authentication using Angularjs

I am fairly new to AngularJS
I have a resource that I use for user management which is part of a service following this article.
Once sending the login request to the server I am getting a response with a set-cookie as part of the header.
What is the best practice to add this cookie to every request I am sending to the server?
myApp.factory('UserService', ['$resource', function ($resource) {
var userRes = $resource('http://<MyDomain>/api/v1/user/:param',
{param: '#param'},
{
login: {
method: 'POST'
},
logout: {
method: 'DELETE'
}
});
var user;
return {
signIn: function () {
user = userRes.login({param: 'login'}, {"email": "SomeName#MyDomain.com", "password": "test1"});
userRes.get({param: '1'});
},
userRes.login has set-cookie header in on the response
userRes.get does not send the cookie that was just received.
Cheers
Since your API is in a different domain you can't use cookies in this case. We've tried and we failed to put it simple there is no way, not only it doesn't work with CORS but also it doesn't work if you embed an iframe. The iframe trick fails on safaris mostly but it is not reliable.
What we usually do is to return a JWT (Json Web Token) from the API and attach a header then to every API request as Authorization: Bearer JWT.
This JWT can be decoded using a public key from the front end (and it will contain the user profile) and validad with a private key in the backend.
JWT is simple and there are plenty of libraries for every language/technology.
Auth0 is an authentication broker that can validate with any identity provider or custom databases, and it returns JWTs using standars. It provides a clientID that can be used to decode the profile in the front end and a secret to validate the tokens in the backend as well as client side library to do this.
Disclaimer: I work for auth0.

Resources