Currently in my Xamairn.Android I have 2 activities Mainactivity and SignoutActivity.
In my Mainactivity I have a button where when user clicks the button it goes to SignoutActivity.
Here I have implemented the signout codes of Auth0.
Here are the codes-
In MainAcitivity-
this.Signout.Click += delegate
{
using (var intent = new Intent(this, typeof(SignOutActivity)))
{
this.StartActivity(intent);
}
};
SignOutAcitivity-
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
this.LogoutAsync();
Finish();
}
public async Task<BrowserResult> LogoutAsync()
{
var clientOptions = new Auth0.OidcClient.Auth0ClientOptions
{
Domain ="",
ClientId = "",
Scope = "openid email offline_access",
Browser = new PlatformWebView()
};
var logoutUrl = "Signout URl";
string redirectUri = "I have proper callback uri";
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("client_id", "random1234");
dictionary.Add("returnTo", clientOptions.RedirectUri);
string endSessionUrl = new RequestUrl(logoutUrl).Create(dictionary);
var logoutRequest = new LogoutRequest();
BrowserResult browserResult = null;
browserResult = await clientOptions.Browser.InvokeAsync(new BrowserOptions(endSessionUrl, redirectUri)
{
Timeout = TimeSpan.FromSeconds((double)logoutRequest.BrowserTimeout),
DisplayMode = logoutRequest.BrowserDisplayMode
});
return browserResult;
}
Platformview-
class PlatformWebView : IBrowser
{
public Task<BrowserResult> InvokeAsync(BrowserOptions options)
{
if (string.IsNullOrWhiteSpace(options.StartUrl))
{
throw new ArgumentException("Missing StartUrl", nameof(options));
}
if (string.IsNullOrWhiteSpace(options.EndUrl))
{
throw new ArgumentException("Missing EndUrl", nameof(options));
}
var tcs = new TaskCompletionSource<BrowserResult>();
void Callback(string response)
{
ActivityMediator.Instance.ActivityMessageReceived -= Callback;
// set result
if (response == "UserCancel")
{
tcs.SetResult(new BrowserResult { ResultType = BrowserResultType.UserCancel });
}
else
{
tcs.SetResult(new BrowserResult
{
Response = response,
ResultType = BrowserResultType.Success
});
}
}
ActivityMediator.Instance.ActivityMessageReceived += Callback;
var uri = Android.Net.Uri.Parse(options.StartUrl);
var intent = new Intent(Intent.ActionView, uri);
intent.AddFlags(ActivityFlags.NoHistory)
.AddFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(intent);
return tcs.Task;
}
}
}
Problem is browser never returns to app,Also I have put a debugger at return browserResult,this debugger also does not hit.Please help me.
Related
I can't use the Twilio SDK in Microsoft Dynamics 365 (Twilio library is not installed in Dynamics and can't include the dll in my plugin registration) so I've had to do a http post using the HttpClient. The call to Twilio happens successfully because Twilio is able to send me an verification email but the breakpoint after PostAsync never gets hit, nor does an exception get caught. I need to capture the output from the PostAsync. What am I doing wrong?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public class TwilioMessageInput
{
public string To { get; set; }
public string Channel { get; set; }
}
public class TwilioMessageOutput
{
public string Message { get; set; }
}
private void button1_Click(object sender, EventArgs e)
{
// https://www.twilio.com/docs/verify
// https://www.twilio.com/docs/verify/email
string url = "https://verify.twilio.com/v2/Services/VA********************************/Verifications/";
string authToken = "AC********************************:********************************"; //-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
string email = "***************#************.com";
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("To", email),
new KeyValuePair<string, string>("Channel", "email")
});
using (var client = new Rest(url))
{
var response = client.PostAsync<TwilioMessageOutput>(url, formContent, authToken).Result;
}
}
}
public class Rest : IDisposable
{
private readonly TimeSpan _timeout;
private HttpClient _httpClient;
private HttpClientHandler _httpClientHandler;
private readonly string _baseUrl;
private const string ClientUserAgent = "twillio-client-v1";
private const string MediaTypeJson = "application/json";
public Rest(string baseUrl, TimeSpan? timeout = null)
{
_baseUrl = NormalizeBaseUrl(baseUrl);
_timeout = timeout ?? TimeSpan.FromSeconds(90);
//_timeout = TimeSpan.FromSeconds(1);
}
private async Task<string> PostAsyncInternal(string url, FormUrlEncodedContent input, string authToken)
{
try
{
EnsureHttpClientCreated();
var byteArray = Encoding.ASCII.GetBytes(authToken);
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
using (var response = await _httpClient.PostAsync(url, input))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
catch (Exception ex)
{
throw ex;
}
}
public async Task<TResult> PostAsync<TResult>(string url, FormUrlEncodedContent input, string authToken) where TResult : class, new()
{
var strResponse = await PostAsyncInternal(url, input, authToken);
return JsonConvert.DeserializeObject<TResult>(strResponse, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
public void Dispose()
{
_httpClientHandler?.Dispose();
_httpClient?.Dispose();
}
private void CreateHttpClient()
{
_httpClientHandler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
};
_httpClient = new HttpClient(_httpClientHandler, false)
{
Timeout = _timeout
};
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(ClientUserAgent);
if (!string.IsNullOrWhiteSpace(_baseUrl))
{
_httpClient.BaseAddress = new Uri(_baseUrl);
}
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeJson));
}
private void EnsureHttpClientCreated()
{
if (_httpClient == null)
{
CreateHttpClient();
}
}
private static string ConvertToJsonString(object obj)
{
if (obj == null)
{
return string.Empty;
}
return JsonConvert.SerializeObject(obj, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
private static string NormalizeBaseUrl(string url)
{
return url.EndsWith("/") ? url : url + "/";
}
}
Twilio developer evangelist here.
I'm not a C# or Dynamics developer, so sorry if this doesn't help. When you make the request:
var response = client.PostAsync<TwilioMessageOutput>(url, formContent, authToken).Result;
it is an asynchronous request, but you do not seem to be waiting for the asynchronous response at all. Should that be?
var response = await client.PostAsync<TwilioMessageOutput>(url, formContent, authToken).Result;
Xamarin Forms App
I have two pages in my App: News and Announcements.
On these pages I want to display messages received from a rabbitmq Server.
I implemented a Service in Android that is executed after the login is completed. The communication between the Shared Code and the Android-Code is realized with Xamarin.MessagingCenter.
The Problem is that my rabbitmq Client currently doesn't receive any messages.
The Server is running on a VM and the App runs in an Emulator.
Code
Here is my Code
DataTransferTaskService in Android
[Service]
class DataTransferTaskService : Service
{
static User user = new User { Groups = new List<string>() { "Test","Test2" } };
CancellationTokenSource _cts;
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
// From shared code or in your PCL
_cts = new CancellationTokenSource();
PS();
return StartCommandResult.NotSticky;
}
void PS()
{
var factory = new ConnectionFactory() { HostName = "10.0.0.3", UserName = "test", Password = "test", Port = 5672 };
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
channel.ExchangeDeclare(exchange: "Kastner", type: ExchangeType.Direct);
var queueName = channel.QueueDeclare().QueueName;
foreach (string g in user.Groups)
{
channel.QueueBind(queue: queueName,
exchange: "Kastner",
routingKey: g);
}
var consumer = new EventingBasicConsumer(channel);
System.Diagnostics.Debug.WriteLine("vor event");
consumer.Received += (model, ea) =>
{
var body = ea.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
var obj = JObject.Parse(message);
News n;
Announcement a;
System.Diagnostics.Debug.WriteLine("vor if");
if (obj.Properties().Select(p => p.Name).FirstOrDefault() == "NewsId")
{
n = JsonConvert.DeserializeObject<News>(message);
MessagingCenter.Send<object, News>(this, "NewsMessage", n);
}
else
{
a = JsonConvert.DeserializeObject<Announcement>(message);
MessagingCenter.Send<object, Announcement>(this, "AnnouncementMessage", a);
}
};
channel.BasicConsume(queue: queueName,
autoAck: true,
consumer: consumer);
}
}
MainActivity.cs in Android
[Activity(Label = "DA_MessageBrokerApp", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
FFImageLoading.Forms.Platform.CachedImageRenderer.Init(enableFastRenderer: true);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
CrossMediaManager.Current.Init(this);
LoadApplication(new App());
WireUpDataTransferTask();
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
void WireUpDataTransferTask()
{
MessagingCenter.Subscribe<NewsViewModel>(this, "StartDataTransferMessage", (sender) =>
{
var intent = new Intent(this, typeof(DataTransferTaskService));
StartService(intent);
});
}
}
NewsViewModel in Shared Code
public class NewsViewModel : BaseViewModel
{
static User user = new User { Groups = new List<string>() { "Test","Test2" } };
private News _selectedItem;
public ObservableCollection<News> Items { get; }
public Command LoadItemsCommand { get; }
public Command AddItemCommand { get; }
public Command<News> ItemTapped { get; }
public NewsViewModel()
{
Title = "News";
Items = new ObservableCollection<News>();
MessagingCenter.Subscribe<object, News>(this, "NewsMessage", async (sender, arg) =>
{
await Task.Run(() =>DataStoreNews.AddItemAsync(arg));
await ExecuteLoadItemsCommand();
});
MessagingCenter.Send<NewsViewModel>(this, "StartDataTransferMessage");
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
ItemTapped = new Command<News>(OnItemSelected);
}
void AddNewItem(News news)
{
if (!Items.Contains(news))
Items.Add(news);
}
async Task ExecuteLoadItemsCommand()
{
IsBusy = true;
try
{
Items.Clear();
var items = await DataStoreNews.GetItemsAsync(true);
foreach (var item in items)
{
Items.Add(item);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
public void OnAppearing()
{
IsBusy = true;
SelectedItem = null;
}
public News SelectedItem
{
get => _selectedItem;
set
{
SetProperty(ref _selectedItem, value);
OnItemSelected(value);
}
}
async void OnItemSelected(News item)
{
if (item == null)
return;
// This will push the ItemDetailPage onto the navigation stack
await Shell.Current.GoToAsync($"{nameof(NewsDetailPage)}?{nameof(NewsDetailViewModel.NewsId)}={item.NewsId}");
}
}
BaseViewModel in Shared Code
public class BaseViewModel : INotifyPropertyChanged
{
public IDataStore<News> DataStoreNews => DependencyService.Get<IDataStore<News>>();
public IDataStore<Announcement> DataStoreMessage => DependencyService.Get<IDataStore<Announcement>>();
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set { SetProperty(ref isBusy, value); }
}
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName] string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Problem
In the PS() method in the Service Class is the Method where I execute the Code of the rabbitmq Client. But the event that the client receives a message is never raised. I already tried the connection with annother Test Console App and there I received messages. Did I do something wrong with the Service or why is this not working?
Edit: I removed the usings of connection and channel in the DataTransferTaskService class, because I found out that these caused some problems, but it is still not working.
I'm currently working on an OWIN OAuth implementation which uses JWT and supports token refreshing. I'm having intermittent problems with the token refresh process. The process works reliably on my development environment, but when published onto our Azure Service Fabric test environment, which is setup in a 3-node load-balanced configuration, the refresh token request often fails (not always!), and I get the infamous "invalid_grant" error.
I've found that the refresh token works successfully when being handled by the same service fabric node that issued it originally. However, it always fails when handled by a different node.
My understanding is that by using JWT, having a micro-service infrastructure deliver a load-balanced authentication server get's around the "machine-key" related issues that arise from using the OOTB access token format provided by OWIN.
Failed refresh tokens are making their way into the IAuthenticationTokenProvider.ReceiveAsync method, but the OAuthAuthorizationServerProvider.GrantRefreshToken method is never being hit, suggesting something in the OWIN middle-ware is not happy with the refresh token. Can anyone offer any insight into what the cause may be?
Now for the code, there's quite a bit - apologies for all the reading!
The authentication server is a service fabric stateless service, here's the ConfigureApp method:
protected override void ConfigureApp(IAppBuilder appBuilder)
{
appBuilder.UseCors(CorsOptions.AllowAll);
var oAuthAuthorizationServerOptions = InjectionContainer.GetInstance<OAuthAuthorizationServerOptions>();
appBuilder.UseOAuthAuthorizationServer(oAuthAuthorizationServerOptions);
appBuilder.UseJwtBearerAuthentication(InjectionContainer.GetInstance<JwtBearerAuthenticationOptions>());
appBuilder.UseWebApi(GetHttpConfiguration(InjectionContainer));
}
Here's the implementation of OAuthAuthorizationServerOptions:
public class AppOAuthOptions : OAuthAuthorizationServerOptions
{
public AppOAuthOptions(IAppJwtConfiguration configuration,
IAuthenticationTokenProvider authenticationTokenProvider,
IOAuthAuthorizationServerProvider authAuthorizationServerProvider)
{
AllowInsecureHttp = true;
TokenEndpointPath = "/token";
AccessTokenExpireTimeSpan = configuration.ExpirationMinutes;
AccessTokenFormat = new AppJwtWriterFormat(this, configuration);
Provider = authAuthorizationServerProvider;
RefreshTokenProvider = authenticationTokenProvider;
}
}
And here's the JwtBearerAuthenticationOptions implementation:
public class AppJwtOptions : JwtBearerAuthenticationOptions
{
public AppJwtOptions(IAppJwtConfiguration config)
{
AuthenticationMode = AuthenticationMode.Active;
AllowedAudiences = new[] {config.JwtAudience};
IssuerSecurityTokenProviders = new[]
{
new SymmetricKeyIssuerSecurityTokenProvider(
config.JwtIssuer,
Convert.ToBase64String(Encoding.UTF8.GetBytes(config.JwtKey)))
};
}
}
public class InMemoryJwtConfiguration : IAppJwtConfiguration
{
AppSettings _appSettings;
public InMemoryJwtConfiguration(AppSettings appSettings)
{
_appSettings = appSettings;
}
public int ExpirationMinutes
{
get { return 15; }
set { }
}
public string JwtAudience
{
get { return "CENSORED AUDIENCE"; }
set { }
}
public string JwtIssuer
{
get { return "CENSORED ISSUER"; }
set { }
}
public string JwtKey
{
get { return "CENSORED KEY :)"; }
set { }
}
public int RefreshTokenExpirationMinutes
{
get { return 60; }
set { }
}
public string TokenPath
{
get { return "/token"; }
set { }
}
}
And the ISecureData implementation:
public class AppJwtWriterFormat : ISecureDataFormat<AuthenticationTicket>
{
public AppJwtWriterFormat(
OAuthAuthorizationServerOptions options,
IAppJwtConfiguration configuration)
{
_options = options;
_configuration = configuration;
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
throw new ArgumentNullException(nameof(data));
var now = DateTime.UtcNow;
var expires = now.AddMinutes(_options.AccessTokenExpireTimeSpan.TotalMinutes);
var symmetricKey = Encoding.UTF8.GetBytes(_configuration.JwtKey);
var signingCredentials = new SigningCredentials(
new InMemorySymmetricSecurityKey(symmetricKey),
SignatureAlgorithm, DigestAlgorithm);
var token = new JwtSecurityToken(
_configuration.JwtIssuer,
_configuration.JwtAudience,
data.Identity.Claims,
now,
expires,
signingCredentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public AuthenticationTicket Unprotect(string protectedText)
{
throw new NotImplementedException();
}
}
This is the IAuthenticationTokenProvider implementation:
public class RefreshTokenProvider : IAuthenticationTokenProvider
{
private readonly IAppJwtConfiguration _configuration;
private readonly IContainer _container;
public RefreshTokenProvider(IAppJwtConfiguration configuration, IContainer container)
{
_configuration = configuration;
_container = container;
_telemetry = telemetry;
}
public void Create(AuthenticationTokenCreateContext context)
{
CreateAsync(context).Wait();
}
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
try
{
var refreshTokenId = Guid.NewGuid().ToString("n");
var now = DateTime.UtcNow;
using (var container = _container.GetNestedContainer())
{
var hashLogic = container.GetInstance<IHashLogic>();
var tokenStoreLogic = container.GetInstance<ITokenStoreLogic>();
var userName = context.Ticket.Identity.FindFirst(ClaimTypes.UserData).Value;
var userToken = new UserToken
{
Email = userName,
RefreshTokenIdHash = hashLogic.HashInput(refreshTokenId),
Subject = context.Ticket.Identity.Name,
RefreshTokenExpiresUtc =
now.AddMinutes(Convert.ToDouble(_configuration.RefreshTokenExpirationMinutes)),
AccessTokenExpirationDateTime =
now.AddMinutes(Convert.ToDouble(_configuration.ExpirationMinutes))
};
context.Ticket.Properties.IssuedUtc = now;
context.Ticket.Properties.ExpiresUtc = userToken.RefreshTokenExpiresUtc;
context.Ticket.Properties.AllowRefresh = true;
userToken.RefreshToken = context.SerializeTicket();
await tokenStoreLogic.CreateUserTokenAsync(userToken);
context.SetToken(refreshTokenId);
}
}
catch (Exception ex)
{
// exception logging removed for brevity
throw;
}
}
public void Receive(AuthenticationTokenReceiveContext context)
{
ReceiveAsync(context).Wait();
}
public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
try
{
using (var container = _container.GetNestedContainer())
{
var hashLogic = container.GetInstance<IHashLogic>();
var tokenStoreLogic = container.GetInstance<ITokenStoreLogic>();
var hashedTokenId = hashLogic.HashInput(context.Token);
var refreshToken = await tokenStoreLogic.FindRefreshTokenAsync(hashedTokenId);
if (refreshToken == null)
{
return;
}
context.DeserializeTicket(refreshToken.RefreshToken);
await tokenStoreLogic.DeleteRefreshTokenAsync(hashedTokenId);
}
}
catch (Exception ex)
{
// exception logging removed for brevity
throw;
}
}
}
And finally, this is the OAuthAuthorizationServerProvider implementation:
public class AppOAuthProvider : OAuthAuthorizationServerProvider
{
public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
{
if (context.ClientId != null)
{
context.Rejected();
return Task.FromResult(0);
}
// Change authentication ticket for refresh token requests
var newIdentity = new ClaimsIdentity(context.Ticket.Identity);
newIdentity.AddClaim(new Claim("newClaim", "refreshToken"));
var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties);
context.Validated(newTicket);
return Task.FromResult(0);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
using (var container = _container.GetNestedContainer())
{
var requestedAuthenticationType = context.Request.Query["type"];
var requiredAuthenticationType = (int)AuthenticationType.None;
if (string.IsNullOrEmpty(requestedAuthenticationType) || !int.TryParse(requestedAuthenticationType, out requiredAuthenticationType))
{
context.SetError("Authentication Type Missing", "Type parameter is required to check which type of user you are trying to authenticate with.");
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
return;
}
var authenticationWorker = GetInstance<IAuthenticationWorker>(container);
var result = await authenticationWorker.AuthenticateAsync(new AuthenticationRequestViewModel
{
UserName = context.UserName,
Password = context.Password,
IpAddress = context.Request.RemoteIpAddress ?? "",
UserAgent = context.Request.Headers.ContainsKey("User-Agent") ? context.Request.Headers["User-Agent"] : ""
});
if (result.SignInStatus != SignInStatus.Success)
{
context.SetError(result.SignInStatus.ToString(), result.Message);
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
return;
}
// After we have successfully logged in. Check the authentication type for the just authenticated user
var userAuthenticationType = (int)result.AuthenticatedUserViewModel.Type;
// Check if the auth types match
if (userAuthenticationType != requiredAuthenticationType)
{
context.SetError("Invalid Account", "InvalidAccountForPortal");
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
return;
}
var identity = SetClaimsIdentity(context, result.AuthenticatedUserViewModel);
context.Validated(identity);
}
}
public override async Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
{
using (var container = GetNestedContainer())
{
var email = context.Identity.FindFirst(ClaimTypes.UserData).Value;
var accessTokenHash = _hashLogic.HashInput(context.AccessToken);
var tokenStoreLogic = GetInstance<ITokenStoreLogic>(container);
await tokenStoreLogic.UpdateUserTokenAsync(email, accessTokenHash);
var authLogic = GetInstance<IAuthenticationLogic>(container);
var userDetail = await authLogic.GetDetailsAsync(email);
context.AdditionalResponseParameters.Add("user_id", email);
context.AdditionalResponseParameters.Add("user_name", userDetail.Name);
context.AdditionalResponseParameters.Add("user_known_as", userDetail.KnownAs);
context.AdditionalResponseParameters.Add("authentication_type", userDetail.Type);
}
await base.TokenEndpointResponse(context);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult(0);
}
private ClaimsIdentity SetClaimsIdentity(OAuthGrantResourceOwnerCredentialsContext context, AuthenticatedUserViewModel user)
{
var identity = new ClaimsIdentity(
new[]
{
new Claim(ClaimTypes.Name, context.UserName),
new Claim(ClaimTypes.SerialNumber, user.SerialNumber),
new Claim(ClaimTypes.UserData, user.Email.ToString(CultureInfo.InvariantCulture)),
new Claim(ClaimTypeUrls.AdminScope, user.Scope.ToString()),
new Claim(ClaimTypeUrls.DriverId, user.DriverId.ToString(CultureInfo.InvariantCulture)),
new Claim(ClaimTypeUrls.AdministratorId, user.AdministratorId.ToString(CultureInfo.InvariantCulture))
},
_authenticationType
);
//add roles
var roles = user.Roles;
foreach (var role in roles)
identity.AddClaim(new Claim(ClaimTypes.Role, role));
return identity;
}
}
We did custom authorization attribute and want this to be covered by unit test. Unfortunately I don't have any idea how to unit test such kind of staff. Could you advise please?
public override void OnAuthorization(HttpActionContext actionContext)
{
var ts = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(TokenService));
try
{
var token = GetHeader(actionContext.Request);
if (token == null)
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("Token not found")
};
return;
}
else
{
var tks = ts as TokenService;
var tkn = Task.Run(() => tks.FindToken(token)).Result;
if (tkn.ValidTill > DateTime.Now)
{
var us = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(UserService));
var uss = us as UserService;
var user = Task.Run(() => uss.FindByTokenValue(token)).Result;
if (user != null)
{
if (!_roles.Contains(user.RoleName))
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden)
{
Content = new StringContent("You role permission is not enough")
};
return;
}
var identity = new Identity { Name = user.Login, IsAuthenticated = true };
var principal = new GenericPrincipal(identity, new[] { user.RoleName });
actionContext.RequestContext.Principal = principal;
Thread.CurrentPrincipal = principal;
base.OnAuthorization(actionContext);
_roles = null;
}
else
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("User not found")
};
return;
}
}
else
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent($"Token valid till {tkn.ValidTill}")
};
return;
}
}
}
catch (Exception ex)
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent($"Authorization error: {ex.Message}")
};
return;
}
}
Test that should be passed:
- Token is exist.
- Token is valid for this DateTime.
- User role is valid.
P.S. Please don't ask me why we did this instead of using ASP.NET Identity, that's was not my solution, I prefer ASP.NET Identity.
Well there is nothing really special about this. So for example using Moq:
[Test]
public void OnAuthorization_ReturnsErrorWhenThereIsNoToken()
{
var resolver = new Mock<IDependencyResolver>();
resolver.Setup(x => x.GetService(It.IsAny<Type>())).Returns(
(Type t) =>
{
if (t == typeof(TokenService))
{
return new TokenService();
}
if (t == typeof(TokenService))
{
return new UserService();
}
return null;
});
var original = GlobalConfiguration.Configuration.DependencyResolver;
GlobalConfiguration.Configuration.DependencyResolver = resolver.Object;
var ctx = new HttpActionContext
{
ControllerContext =
new HttpControllerContext { Request = new HttpRequestMessage() }
};
var target = new Attrr();
target.OnAuthorization(ctx); // no token
Assert.AreEqual(HttpStatusCode.Unauthorized, ctx.Response.StatusCode);
Assert.AreEqual("Token not found", (ctx.Response.Content as StringContent).ReadAsStringAsync().Result);
// we need this to ensure the test state is restored after test
GlobalConfiguration.Configuration.DependencyResolver = original;
}
Obviously then you need to keep replicating behaviours (i'm hoping your TokenService and UserService are actually interface'd.
I'm getting following error while integrating facebook api over Windows 8.1 for store apps:-
Given URL is not permitted by application configuration......"
Screenshot showing error dialog:
Please help to resolve this issue.
private FacebookSession _session;
private FacebookClient _client;
private string _accessToken;
string appID = "749110128499368";
Dictionary<string, object> parameters = new Dictionary<string, object>{
{"response_type","token"},
{"display","touch"},
{"redirect_uri","https://www.facebook.com/connect/login_success.html"},
};
FacebookClient oauth;
string[] extended_permissions;
async void getToken()
{
try
{
FacebookSessionClient fbClient = new FacebookSessionClient(appID);
if (ApplicationData.Current.LocalSettings.Values.ContainsKey("fbaccesstoken"))
{
_accessToken = ApplicationData.Current.LocalSettings.Values["fbaccesstoken"].ToString();
}
else
{
_session = await fbClient.LoginAsync("user_about_me,read_stream");
_accessToken = _session.AccessToken;
ApplicationData.Current.LocalSettings.Values["fbaccesstoken"] = _accessToken;
}
_client = new FacebookClient(_accessToken);
}
catch (Exception e){
extended_permissions = new string[] { "user_friends", "email" };
oauth = new FacebookClient() { AppId = appID };
if (extended_permissions != null && extended_permissions.Length > 0)
{
var scope = new StringBuilder();
scope.Append(string.Join(",", extended_permissions));
parameters["scope"] = scope.ToString();
}
getLogin();
}
}
void getLogin()
{
oauth.Version = "2.2";
extended_permissions = new string[] { "user_friends", "email" };
oauth = new FacebookClient() { AppId = appID };
if (extended_permissions != null && extended_permissions.Length > 0)
{
var scope = new StringBuilder();
scope.Append(string.Join(",", extended_permissions));
parameters["scope"] = scope.ToString();
}
var loginUrl = oauth.GetLoginUrl(parameters);
fbBrowser.Navigate(loginUrl);
}
async private void fb_browser_Navigated(object sender, NavigationEventArgs e)
{
FacebookOAuthResult fb_result;
var fb = new FacebookClient();
string uri = e.Uri.AbsoluteUri;
Uri uri_fb = new Uri(uri);
if (fb.TryParseOAuthCallbackUrl(uri_fb, out fb_result))
{
if (fb_result.IsSuccess)
{
_accessToken = fb_result.AccessToken;
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,()=>
{
GetData(_accessToken);
});
}
else
{
var errordescription = fb_result.ErrorDescription;
var errorreason = fb_result.ErrorReason;
MessageDialog m = new MessageDialog(errordescription + "\n" + errorreason);
await m.ShowAsync();
}
}
}
async void GetData(string access_token)
{
string uriString = "https://graph.facebook.com/me?access_token=" + access_token;
HttpClient wClient = new HttpClient();
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,()=>
{
Task gettingData = wClient.GetStringAsync(uriString);
});
}