Use Azure Mobile Client for Rest API - azure-mobile-services

I started up using the Azure Mobile App SDK to develop my Xamarin app. Started with TableControlle, but due to want to keep most business logic in API, ended up most services using REST concept. E.g. :
[MyAuthorize(ActivityEnum.None, UserRole.Admin)]
[HttpGet]
[Route("GetOrderByUser")]
public IHttpActionResult GetOrderByUser(int tenantID, string userID)
{
try
{
var Orders = db.Orders
.Where(x => x.TenantID == tenantID && x.DateEndShip == null && x.DateCancel == null)
.Project().To<OrderDto>()
.ToList();
foreach (var item in Orders)
{
item.CustomerName = db.Parties.FirstOrDefault(x => x.ID == item.CustomerID).Name;
item.Order_Lines = db.Order_Line.Where(x => x.OrderID == item.OrderID)
.Project()
.To<Order_LineDto>()
.ToList();
foreach (var line in item.Order_Lines)
{
line.ItemName = db.Items.FirstOrDefault(x => x.ID == line.ItemID).ItemID;
}
}
return Ok(Orders);
}
catch (Exception ex)
{
return ResponseMessage(Request.CreateResponse(HttpStatusCode.BadRequest, ex.Message));
}
}
So used the HTTPClient in Xamarin. But this tend to be unstable and defeats the purpose hosting on Azure Mobile App service, I guess. Also, the authorization becomes messy, since I need to pass the token within the URL here.
Can I actually use Azure Mobile App SDK to call this service?

The Azure Mobile Apps client SDK provides client access to an Azure Mobile Apps server SDK. You need to use the two in tandem. You cannot use one without using the other.
Since you are using Xamarin, check out the book at https://adrianhall.gitlab.io/develop-mobile-apps-with-csharp-and-azure/ - a lot of the concepts here are covered in the book.

Related

How do you identify the tenant using a JWT when integrating with Autofac?

I'm trying to build a multi-tenant ASP.NET Core 2.1 WebApi.
I would like to chose tenant from the jwt token and not from the url or port.
So When user Request the token, I put it's tenant_id into the token.
But when I try to resolve the TenantId in the Autofac Multitenant strategy (ITenantIdentificationStrategy) like this:
public bool TryIdentifyTenant(out object tenantId)
{
_logger.LogInformation("***********************************TryIdentify");
tenantId = null;
try
{
var context = _httpContextAccessor()?.HttpContext;
if(context != null && context.Request != null)
{
var id = context.User.FindFirst("tenantId")?.Value;
if (id != null)
{
tenantId = id;
}
}
}
catch(Exception)
{
// Happens at app startup in IIS 7.0
}
return tenantId != null;
}
I see that the context.User is not jet populated and that's because the Jwt authentication didn't happen jet.
How to do it?
The short version of this is you don't get to do this for free. This is generally why it's best to use something you can trust but doesn't require additional support to use (like the host name in the request).
If you can only trust the token, then I have seen solutions that roughly do this (in pseudocode-that-looks-like-C#):
if(context.Items["tenant"] == null && context.User == null)
{
// no tenant has been identified before and
// token validation hasn't happened so manually
// get the tenant from the token knowing you are
// potentially getting an untrusted value.
context.Items["tenant"] = ManuallyLookAtToken();
}
else if(context.Items["tenant_trusted"] == null && context.User != null)
{
// a "trusted" tenant ID hasn't been read from the user
// principal so let's update.
context.Items["tenant"] = GetTenantFrom(context.User);
context.Items["tenant_trusted"] = true;
}
return context.Items["tenant"];
The risk in doing something like this is that you open yourself up to an attack where someone sends in a malformed token that only lives long enough to get past the initial part of your request pipeline. The token won't pass validation so the regular security should take care of it, but before that runs the tenant value isn't officially validated. If you have pipeline logic, that, for example... auto-provisions new tenants on first request or something like that?... then you may be in trouble. Someone could randomly generate millions of tenant names and kill your database. In cases like that you can sometimes fall back to other things like the host name.
Alternatively, you can actually manually invoke the token validation logic in that ManuallyLookAtToken() method and ensure it's valid before proceeding. It's sort of painful, but not impossible. That would mean technically you would run that twice during any given request, and it's sort of expensive, so consider the perf if you go that route and balance that with security implications.

In identity server 3 how to relate user to client

I am using Identity Server 3. I have couple applications ie. Client configured and have few users configured. How do i establish the relationship between User and a Client and also view all applications that the selected User has access to.
Update 1
I am sorry if question was confusing. On IdSvr3 home page, there is a link to revoke application permissions. I am guessing in order to revoke the permission you have to first establish the relationship between user and application.
and i wanted to know how to establish that permission when i add new user?
There's no direct way to limit one or multiple users to a certain client. This is where you should think about implementing your own custom validation. Fortunately, the IdentityServer provides an extensibility point for this kind of requirement.
ICustomRequestValidator
You should implement this interface to further validate users to see if they belong to certain clients and filter them out. You can look into the user details by looking at ValidatedAuthorizeRequest.Subject. This custom validator will start after validating optional parameters such as nonce, prompt, arc_values ( AuthenticationContextReference ), login_hint, and etc. The endpoint is AuthorizeEndPointController and the default implementation of the interface for the tailored job is AuthorizeRequestValidator and its RunValidationAsync. You should take a look at the controller and the class.
Implementation tip
By the time the custom request validation begins, a Client reference will be presented in ValidatedAuthorizeRequest. So all you need to do would be matching the client id or some other identifiers you think you need to verify the client. Probably, you might want to add a Claim key-value pair to your client which you want to allow a few users.
Maybe something like this.
new InMemoryUser{Subject = "870805", Username = "damon", Password = "damon",
Claims = new Claim[]
{
new Claim(Constants.ClaimTypes.Name, "Damon Jeong"),
new Claim(Constants.ClaimTypes.Email, "dmjeong#email.com"),
new Claim(Constants.ClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean)
}
}
Assume you have above user, then add the subject id to the claim of a client like below.
new Client
{
ClientName = "WPF WebView Client Sample",
ClientId = "wpf.webview.client",
Flow = Flows.Implicit,
.
.
.
// Add claim for limiting this client to certain users.
// Since a claim only accepts type and value as string,
// You can add a list of subject id by comma separated values
// eg ( new Claim("BelongsToThisUser", "870805, 870806, 870807") )
Claims = new List<Claim>
{
new Claim("BelongsToThisUser", "870805")
}
},
And then just implement the ICustomRequestValidator and try to match the Claim value with the given user in its ValidateAuthorizeRequestAsync.
public class UserRequestLimitor : ICustomRequestValidator
{
public Task<AuthorizeRequestValidationResult> ValidateAuthorizeRequestAsync(ValidatedAuthorizeRequest request)
{
var clientClaim = request.Client.claims.Where(x => x.Type == "BelongsToThisUser").FirstOrDefault();
// Check is this client has "BelongsToThisUser" claim.
if(clientClaim != null)
{
var subClaim = request.Subject.Claims.Where(x => x.Type == "sub").FirstOrDefault() ?? new Claim(string.Empty, string.Empty);
if(clientClaim.Value == userClaim.Value)
{
return Task.FromResult<AuthorizeRequestValidationResult>(new AuthorizeRequestValidationResult
{
IsError = false
});
}
else
{
return Task.FromResult<AuthorizeRequestValidationResult>(new AuthorizeRequestValidationResult
{
ErrorDescription = "This client doesn't have an authorization to request a token for this user.",
IsError = true
});
}
}
// This client has no access controls over users.
else
{
return Task.FromResult<AuthorizeRequestValidationResult>(new AuthorizeRequestValidationResult
{
IsError = false
});
}
}
public Task<TokenRequestValidationResult> ValidateTokenRequestAsync(ValidatedTokenRequest request)
{
// your implementation
}
}
Time to DI
You need to inject your own dependency when you configure up your IdentityServer. The authorization server uses IdentityServerServiceFactory for registering dependencies.
var factory = new IdentityServerServiceFactory();
factory.Register(new Registration<ICustomRequestValidator>(resolver => new UserRequestLimitor()));
Then Autofac; the IoC container in IdentityServer will do the rest of the DI jobs for you.

google anaylitics visitor counter fail to return using API

I have written following code in a handler to get visitor counter in asp.net website
using Google.Analytics;
using Google.GData.Analytics; //v2.2.0.0
public class Visitor : IHttpHandler {
public void ProcessRequest (HttpContext context) {
AccountQuery feedQuery = new AccountQuery();
AnalyticsService service = new AnalyticsService("kiranaAnalytic");
service.setUserCredentials("myemailid#gmail.com", "mypassword");
DataQuery pageViewQuery = new DataQuery("https://www.google.com/analytics/feeds/data");//https://www.google.com/analytics/feeds/data
pageViewQuery.Ids = "ga:xxxx";
pageViewQuery.Metrics = "ga:visitors";
pageViewQuery.GAStartDate = "2014-05-01";//DateTime.Now.AddMonths(-1).ToString("yyyy-MM-dd");
pageViewQuery.GAEndDate = DateTime.Now.ToString("yyyy-MM-dd");
DataEntry pvEntry = service.Query(pageViewQuery).Entries[0] as DataEntry;
context.Response.ContentType = "text/plain";
context.Response.Write(pvEntry.Metrics[0].Value);
}
public bool IsReusable {
get {
return false;
}
}
}
It was working fine till yeaterday. But I am suddenly started getting following error.
"Google.GData.Client.GDataRequestException: Execution of authentication request returned"
Has anyone have idea about it or did google made some changes ?
This means there is something wrong with your authentication. You appear to be using Login and password which is called client login.
Client login which was discontinued / shutdown on April 20 2015 and I suspect turned off on Tuesday for Google Analytics. You can no longer use client login with Google Analytics API, you need to switch to Oauth2 or a service account. I recommend using the Google .net client library.
tutorial: Google Analytics API C# Oauth2
Google shutdown the old account-password authentication. You need to move your code to use Oauth.

How to get Facebook Friend List in ASP.NET?

I'm building an App with ASP.NET MVC 5 and Identity.
So far the login is working correctly.
Here the auth:
var fb = new FacebookAuthenticationOptions();
fb.Scope.Add("email");
fb.Scope.Add("friends_about_me");
fb.Scope.Add("friends_photos");
fb.AppId = "";
fb.AppSecret = "";
fb.Provider = new FacebookAuthenticationProvider() {
OnAuthenticated = async FbContext => {
FbContext.Identity.AddClaim(
new System.Security.Claims.Claim("FacebookAccessToken", FbContext.AccessToken));
}
};
fb.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
app.UseFacebookAuthentication(fb);
I'm trying to get the friends list. I've been looking for a few examples but none is working with this version of MVC 5.
My question is. How can I fetch all the friends with this version?
I don't want to use Javascript API, I want all the code in c# and then send to the view.
I think I just need to rewrite the login and store the access token in the session, and then simply call var client = new FacebookClient(TOKEN);
So how can I rewrite the login?
You've already got everything you need. The OnAuthenticated callback you've set adds a claim containing the access token for Facebook. You just need to pull the claim for the user:
var identity = (ClaimsIdentity)User.Identity;
var facebookClaim = identity.Claims.FirstOrDefault(c => c.Type == "FacebookAccessToken");
if (facebookClaim != null)
{
// access facebook API with `facebookClaim.Value`
}
And if it exists, then you can use the Facebook API to pull in their friends by making standard HTTP calls via something like HttpClient.

Possible to force the C# Facebook SDK to use HTTP instead of HTTPS?

I need to do some connectivity simulations to see that my code handles various connectivity errors to Facebook. I want to be able to simulate 500s, timeouts etc.
The easiest way to do that is to use Fiddler, but it seems to not be working with HTTPS (I get 403s when I try).
Is ther a way to force the SDK to work with HTTP instead of HTTPS for debugging purposes?
Facebook C# SDK supports your scenario for mocking the entire HttpWebRequest and HttpWebResponse. In fact we actually use that internally in our unit tests so that every single line of the code in Facebook C# SDK actually gets executed and the result is always the same. https://github.com/facebook-csharp-sdk/facebook-csharp-sdk/blob/v5/Source/Facebook.Tests/TestExtensions.cs For now you will need to check these tests in v5 branch as we haven't yet migrated those tests to v6.
For v5, you will need to override the protected CreateHttpWebRequest method in FacebookClient.
Here is an example for v5 when there is no internet connection. There are three hidden classes HttpWebRequestWrapper, HttpWebResponseWrapper and WebExceptionWrapper that you will need to make use of.
public static void NoInternetConnection(this Mock<Facebook.FacebookClient> facebookClient, out Mock<HttpWebRequestWrapper> mockRequest, out Mock<WebExceptionWrapper> mockWebException)
{
mockRequest = new Mock<HttpWebRequestWrapper>();
mockWebException = new Mock<WebExceptionWrapper>();
var mockAsyncResult = new Mock<IAsyncResult>();
var request = mockRequest.Object;
var webException = mockWebException.Object;
var asyncResult = mockAsyncResult.Object;
mockRequest.SetupProperty(r => r.Method);
mockRequest.SetupProperty(r => r.ContentType);
mockRequest.SetupProperty(r => r.ContentLength);
mockAsyncResult
.Setup(ar => ar.AsyncWaitHandle)
.Returns((ManualResetEvent)null);
mockWebException
.Setup(e => e.GetResponse())
.Returns<HttpWebResponseWrapper>(null);
mockRequest
.Setup(r => r.GetResponse())
.Throws(webException);
mockRequest
.Setup(r => r.EndGetResponse(It.IsAny<IAsyncResult>()))
.Throws(webException);
AsyncCallback callback = null;
mockRequest
.Setup(r => r.BeginGetResponse(It.IsAny<AsyncCallback>(), It.IsAny<object>()))
.Callback<AsyncCallback, object>((c, s) =>
{
callback = c;
})
.Returns(() =>
{
callback(asyncResult);
return asyncResult;
});
var mockRequestCopy = mockRequest;
var mockWebExceptionCopy = mockWebException;
facebookClient.Protected()
.Setup<HttpWebRequestWrapper>("CreateHttpWebRequest", ItExpr.IsAny<Uri>())
.Callback<Uri>(uri =>
{
mockRequestCopy.Setup(r => r.RequestUri).Returns(uri);
mockWebExceptionCopy.Setup(e => e.Message).Returns(string.Format("The remote name could not be resolved: '{0}'", uri.Host));
})
.Returns(request);
}
You can then write your tests as below.
[Fact]
public void SyncWhenThereIsNotInternetConnectionAndFiddlerIsNotOpen_ThrowsWebExceptionWrapper()
{
var mockFb = new Mock<FacebookClient> { CallBase = true };
Mock<HttpWebRequestWrapper> mockRequest;
Mock<WebExceptionWrapper> mockWebException;
mockFb.NoInternetConnection(out mockRequest, out mockWebException);
Exception exception = null;
try
{
var fb = mockFb.Object;
fb.Get(_parameters);
}
catch (Exception ex)
{
exception = ex;
}
mockFb.VerifyCreateHttpWebRequest(Times.Once());
mockRequest.VerifyGetResponse();
mockWebException.VerifyGetReponse();
Assert.IsAssignableFrom<WebExceptionWrapper>(exception);
}
In v6 we have made mocking the HttpWebRequest and HttpWebResponse much easier.
Create your custom HttpWebRequest and HttpWebResponse by inheriting HttpWebRequestWrapper and HttpWebReponseWrapper.
Then change the default http web request factory for Facebook C# SDK. Here is the sample of the default factory.
FacebookClient.SetDefaultHttpWebRequestFactory(uri => new HttpWebRequestWrapper((HttpWebRequest)WebRequest.Create(uri)));
If you want to change the HttpWebRequestFactor per FacebookClient instance then use the following code.
var fb = new FacebookClient();
fb.HttpWebRequestFactory = uri=> new MyHttpWebRequestWrapper(uri);
Note: HttpWebRequestWrapper, HttpWebResponseWrapper, WebExceptionWrapper, FacebookClient.SetDefaultHttpWebRequestFactory and FacebookClient.HttpWebRequestFactory has the attribute [EditorBrowsable(EditorBrowsableState.Never)] so you might not see it in the intellisense.
Things like no internet connection that you mention should actually be a part of facebook c# sdk tests and not your app unit tests. The sdk should guarantee that when there is not internet conenction it always throws WebExceptionWrapper and your app unit tests should actually be handling the WebExceptionWrapper exception and not mocking the entire httpwebrequest and httpwebresponse.
I'd suggest you introduce another level of abstraction to your code and code to that abstraction rather than the implementation. Eg.
public interface IFacebookClient {
IEnumerable<Friend> GetFriends();
}
public class HttpsClient : IFacebookClient {
public IEnumerable<Friend> GetFriends() {
// Make a call out to the Facebook API, as per usual
};
}
In your consuming code you'd do something like;
public class ConsumingCode {
private IFacebookClient _client;
public ConsumingCode(IFacebookClient client) {
_client = client;
foreach (Friend friend in _client.GetFriends()) {
// Do something with each Friend
}
}
}
If you're using an IoC container this can all get wired up for you automatically. MVVM frameworks like Caliburn.Micro tend to support this as well.
Then when it comes to unit testing (or manual testing) you can change the implementation of your interface;
public class Http403Client : IFacebookClient {
public IEnumerable<Friend> GetFriends() {
throw new HttpException(403, "Forbidden");
}
}
Obviously this is just a mock up example but I think it demonstrates the concept that you want to implement.