I have this code from Azure Services Mobile App, API custom controller. The result always the same "1:1". I test with all identity providers, google, facebook, twitter, and Microsoft Account, except AD. I think the problem is the call to GetIdentityAsync. Can anyone help me? Thanks
[HttpGet]
public async Task<string> GetIdentityInfo()
{
var user = (MobileAppUser)this.User;
string str = "";
string Provider = "YES", UserId = "NO";
try
{
if (user != null)
{
Provider = "1"; UserId = "1";
var microsoftCredentials = await user.GetIdentityAsync<MicrosoftAccountCredentials>();
if (microsoftCredentials != null && microsoftCredentials.Claims != null)
{
Provider = "MICROSOFT";
UserId = microsoftCredentials.UserId;
}
Provider = "2"; UserId = "2";
var googleCredentials = await user.GetIdentityAsync<GoogleCredentials>();
if (googleCredentials != null && googleCredentials.Claims != null)
{
Provider = "GOOGLE";
UserId = googleCredentials.UserId;
}
Provider = "3"; UserId = "3";
var facebookCredentials = await user.GetIdentityAsync<FacebookCredentials>();
if (facebookCredentials != null && facebookCredentials.Claims != null)
{
Provider = "FACEBOOK";
UserId = facebookCredentials.UserId;
}
Provider = "4"; UserId = "4";
var twitterCredentials = await user.GetIdentityAsync<TwitterCredentials>();
if (twitterCredentials != null && twitterCredentials.Claims != null)
{
Provider = "TWITTER";
UserId = twitterCredentials.UserId;
}
}
else
{
Provider = "NONE"; UserId = "NULL";
}
}
catch (Exception ex)
{
str = "ERROR";
}
finally
{
str = Provider + ":" + UserId;
}
return str;
}
We receive support from Microsoft Support Engineer Adrian Fernandez Garcia, and send an example that worked OK. The unique difference was that EMA_RuntimeUrl must be created manually in mobile app in azure portal in Application Properties, and assigned to Gateway address.
Actually this value is created automatically and don't have to create it manually.
This gave us the error URIFormat NULL value.
All is working OK now.
Thanks to Microsoft for the support.
Related
I want to retrieve metrics related to Blob metric namespace from Azure Storage Account. I need to read the BlobCount value.
Initially I have tried like this:
var usedCapacityResults = await metricsClient.QueryResourceAsync(resourceId, new[] { "BlobCount1" },
new MetricsQueryOptions
{
MetricNamespace = "Blob",
Aggregations =
{
MetricAggregationType.Average
},
Granularity = TimeSpan.FromMinutes(5),
TimeRange = new QueryTimeRange(TimeSpan.FromMinutes(10))
});
if (usedCapacityResults.GetRawResponse().Status == StatusCodes.Status200OK)
{
var usedCapacityMetric = usedCapacityResults.Value.Metrics.FirstOrDefault(m => m.Name == "BlobCount" && m.Error == null);
var metricValue = usedCapacityMetric?.TimeSeries.FirstOrDefault();
if (metricValue != null && !metricValue.Values.IsNullOrEmpty())
{
var average = metricValue.Values[0].Average;
if (average != null) blobCount = (decimal)average;
}
}
But nothing gets returned.
Then I have tried to get the supported metric namespace, using this call:
GET https://management.azure.com/{resourceUri}/providers/microsoft.insights/metricNamespaces?api-version=2017-12-01-preview
and the only valid metric seems to be Microsoft.Storage/storageAccounts, that does not have the blob count metric.
Any idea how to read from code the BlobCount value?
There will be also the option to retrieve the list of containers and iterate though it to count the blobs, but this is something I want to avoid.
The working solution, with help from MS support:
This is the solution that was provided to me by MS Support team:
private async Task<decimal> GetStorageAccountBlobCount(MetricsQueryClient metricsClient, string resourceId)
{
var blobCount = (decimal)0.0;
try
{
resourceId = $"{resourceId}/blobServices/default";
var blobCountResult = await metricsClient.QueryResourceAsync(resourceId, new[] { "BlobCount" },
new MetricsQueryOptions
{
MetricNamespace = "Microsoft.Storage/storageAccounts/blobServices",
Aggregations =
{
MetricAggregationType.Average
},
Granularity = TimeSpan.FromHours(1),
TimeRange = new QueryTimeRange(TimeSpan.FromMinutes(60))
});
if (blobCountResult.GetRawResponse().Status == StatusCodes.Status200OK)
{
var blobCountMetric = blobCountResult.Value.Metrics.FirstOrDefault(m => m.Name == "BlobCount" && m.Error == null);
var metricValue = blobCountMetric?.TimeSeries.FirstOrDefault();
if (metricValue != null && !metricValue.Values.IsNullOrEmpty())
{
var average = metricValue.Values[0].Average;
if (average != null) blobCount = (decimal)average;
}
}
}
catch (Exception ex)
{
_logger.LogError($"Error on calculate blob count for {resourceId}", ex);
}
return blobCount;
}
I am currently using an Umbraco library to extend the Authentication possibilities and enable back office authentication with Active Directory.
https://github.com/umbraco/UmbracoIdentityExtensions
After installing the library and following the blog post below, I was able to display an external login button, authenticate with Active Directory and add a user and external login to the Umbraco database.
https://www.jdibble.co.uk/blog/securing-umbraco-backoffice-with-azure-active-directory/
This then sends you back to the /umbraco login page in a continuous loop. As described by this blog post https://our.umbraco.org/forum/developers/extending-umbraco/75256-login-uisng-azure-ad-redirects-allways-to-login-page
Has anyone faced this issue and solved it? Or have any useful suggestions?
The code being used...
public static void ConfigureBackOfficeAzureActiveDirectoryAuth(this IAppBuilder app,
string tenant, string clientId, string postLoginRedirectUri, Guid issuerId,
string caption = "Active Directory", string style = "btn-microsoft", string icon = "fa-windows")
{
var authority = string.Format(
CultureInfo.InvariantCulture,
"https://login.microsoftonline.com/{0}",
tenant);
var adOptions = new OpenIdConnectAuthenticationOptions
{
SignInAsAuthenticationType = Constants.Security.BackOfficeExternalAuthenticationType,
ClientId = clientId,
Authority = authority,
RedirectUri = postLoginRedirectUri,
AuthenticationMode = AuthenticationMode.Passive,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async context =>
{
if (System.Diagnostics.Debugger.IsAttached)
System.Diagnostics.Debugger.Break();
var userService = ApplicationContext.Current.Services.UserService;
var stuff = (List<Claim>)context.JwtSecurityToken.Claims;
var email = stuff.FirstOrDefault(x => x.Type == "unique_name").Value;
var issuer = stuff.FirstOrDefault(x => x.Type == "iss").Value;
var providerKey = stuff.FirstOrDefault(x => x.Type == "sub").Value;
var name = stuff.FirstOrDefault(x => x.Type == "name").Value;
var userManager = context.OwinContext.GetUserManager<BackOfficeUserManager>();
var user = userService.GetByEmail(email);
if (user == null)
{
var writerUserType = userService.GetUserTypeByName("writer");
user = userService.CreateUserWithIdentity(email, email, writerUserType);
}
var identity = await userManager.FindByEmailAsync(email);
if (identity.Logins.All(x => x.ProviderKey != providerKey))
{
identity.Logins.Add(new IdentityUserLogin(issuer, providerKey, user.Id));
identity.Name = name;
var result = userManager.Update(identity);
}
},
}
};
adOptions.ForUmbracoBackOffice(style, icon);
adOptions.Caption = caption;
//Need to set the auth type as the issuer path
adOptions.AuthenticationType = string.Format(
CultureInfo.InvariantCulture,
"https://sts.windows.net/{0}/",
issuerId);
adOptions.SetExternalSignInAutoLinkOptions(new ExternalSignInAutoLinkOptions(autoLinkExternalAccount: true));
app.UseOpenIdConnectAuthentication(adOptions);
}
I have an ASP.NET Web Api that makes use of ASP.NET Identity v2.2.1 to manage users. I am able to add/edit users without issue. However, I have a second project that cannot make use of the API but needs to be able to change a Users password directly via the database.
I am trying to figure out how to hash the password entered by the user without going through the API. I need to make sure that I am using the same hashing algorithm that ASP.NET Identity is using. I came across some code in this SO article but I am not sure if it is the same hashing algorithm used by v2.2.1.
using using System.Security.Cryptography;
public static string HashPassword(string password)
{
private const int PBKDF2IterCount = 1000; // default for Rfc2898DeriveBytes
private const int PBKDF2SubkeyLength = 256 / 8; // 256 bits
private const int SaltSize = 128 / 8; // 128 bits
if (password == null)
{
throw new ArgumentNullException("password");
}
// Produce a version 0 (see comment above) text hash.
byte[] salt;
byte[] subkey;
using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount))
{
salt = deriveBytes.Salt;
subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
var outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];
Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength);
return Convert.ToBase64String(outputBytes);
}
I would like to avoid having to add ASP.NET Identity as a dependency to this project hence why I would like to hash the password manually.
I would recommend you to use SimpleCrypto
This is how I've used that in a project I believe this will help you. One can add this DLL from nuget
[HttpPost]
public ActionResult Register(RegisterViewModel model)
{
try
{
if (ModelState.IsValid)
{
{
var crypto = new SimpleCrypto.PBKDF2();
var encrypPass = crypto.Compute(model.Password);
var newUser = db.Users.Create();
newUser.Email = model.Email;
newUser.Password = encrypPass;
newUser.PasswordSalt = crypto.Salt;
// newUser.Name = model.UserName;
newUser.Username = model.UserName;
//newUser.AddedBy = model.;
db.Users.Add(newUser);
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "");
}
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
eve.Entry.Entity.GetType().Name, eve.Entry.State);
foreach (var ve in eve.ValidationErrors)
{
Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
ve.PropertyName, ve.ErrorMessage);
}
}
throw;
}
return View();
}
Your valid check at login will be like this
private bool IsValid(string email, string password)
{
var crypto = new SimpleCrypto.PBKDF2();
bool isValid = false;
{
var user = db.Users.FirstOrDefault(u => u.Email == email);
if (user != null)
{
if (user.Password == crypto.Compute(password, user.PasswordSalt))
{
isValid = true;
}
}
}
return isValid;
}
everyone.
Right now I'm using nice nuGet package to monitor my azure web app. The code could look something like this
var certificate = BuildCertificate(StoreName.My, StoreLocation.LocalMachine, " certificate thumbprint");
string subscriptionId = "subscriptionId";
string webspace = "westuswebspace";
string website = "websitename";
using (var client = new MetricsClient(new CertificateCloudCredentials(subscriptionId, certificate)))
{
var metricDefs = client.MetricDefinitions.List(ResourceIdBuilder.BuildWebSiteResourceId(webspace, website), null, null);
var end = DateTime.UtcNow;
var start = end.AddHours(-12);
var timeGrain = TimeSpan.FromHours(1);
var metricVals = client.MetricValues.List(ResourceIdBuilder.BuildWebSiteResourceId(webspace, website),
metricDefs.MetricDefinitionCollection.Value.Select(md => md.DisplayName).ToList(), "",
timeGrain, start, end);
foreach (var metric in metricVals.MetricValueSetCollection.Value)
{
Console.WriteLine("Metric Name: {0}", metric.DisplayName);
Console.WriteLine("Metric Namespace: {0}", metric.Namespace);
foreach (var val in metric.MetricValues)
{
Console.WriteLine("Value: {0}", val.Average.HasValue ? val.Average.Value : 0);
}
Console.WriteLine("//////////////////////");
}
}
certificate retrieval logic
private static X509Certificate2 BuildCertificate(StoreName storeName, StoreLocation storeLocation, string thumbprint)
{
var store = new X509Store(storeName, storeLocation);
store.Open(OpenFlags.ReadOnly);
try
{
var builder = new StringBuilder(thumbprint.Length);
foreach (char c in thumbprint.Where(char.IsLetterOrDigit))
{
builder.Append(c);
}
string cleanThumbprint = builder.ToString();
X509Certificate2Collection list = store.Certificates.Find(X509FindType.FindByThumbprint, cleanThumbprint, false);
X509Certificate2 cert;
if (list == null || list.Count != 1)
{
cert = null;
}
else
{
cert = list[0];
}
return cert;
}
finally
{
store.Close();
}
}
so, everything works perfectly fine, when I'm working with prod, but I can't figure out, how I can monitor my staging environment.
Please, help me with that. I would highly appreciate any help.
I have a plugin registered in Post operation that needs to update multiple fields in CRM using data from an XML file. Currently I am using the following code:
if (node["node1"] != null)
{
var sId = sElement.GetElementsByTagName("pId")[0].InnerText;
Guid sGUID = new Guid(sId);
sEntity["Attrib1"] = sGUID;
service.Update(sEntity);
}
if (node["node2"] != null)
{
var sMax = sElement.GetElementsByTagName("pMax")[0].InnerText;
sEntity["Attrib2"] = sMax;
service.Update(sEntity);
}
if (node["node3"] != null)
{
var sMin = sElement.GetElementsByTagName("pMin")[0].InnerText;
sEntity["Attrib3"] = sMin;
service.Update(sEntity);
}
So I am calling the service.Update each time I need to update and in the above case 3 times.
Is there a better way to accomplish what I am trying to do and call the service.Update only one time?
You can just do a single update in the end (eventually you can add a check in case none of the fields changed, to avoid a useless update):
if (node["node1"] != null)
{
var sId = sElement.GetElementsByTagName("pId")[0].InnerText;
Guid sGUID = new Guid(sId);
sEntity["Attrib1"] = sGUID;
}
if (node["node2"] != null)
{
var sMax = sElement.GetElementsByTagName("pMax")[0].InnerText;
sEntity["Attrib2"] = sMax;
}
if (node["node3"] != null)
{
var sMin = sElement.GetElementsByTagName("pMin")[0].InnerText;
sEntity["Attrib3"] = sMin;
}
service.Update(sEntity);