Single Sign On With ACS through Multiple Applications - azure

Simple Single Sign-On question
I Have two MVC4 applications:
**1**- http://localhost/BikeShop
ACS Relying Party:
- Name: **BikeShop**
- Return Url: **http://localhost/BikeShop**
- Token Format: **SAML 2.0**
**2**- http://localhost/BikePartsShop
ACS Relying Party:
- Name: **BikePartsShop**
- Return Url: **http://localhost/BikePartsShop**
- Token Format: **SAML 2.0**
The Scenario I have
I access BikeShop and the ACS Login Page is presented and I choose my Identity.
I now can do stuff on BikeShop.
Then I access BikePartsShop and the ACS Login Page is presented and I can choose my Identity.
The Scenario I must have
I access BikeShop and the ACS Login Page is presented and I choose my Identity.
I now can do stuff on BikeShop.
Then I access BikePartsShop and the ACS authorizes the same Identity
used in the BikeShop without further user intervention.
Has anyone implemented this scenario?
Best Regards, and thank you!

You can use the ACS management service to configure multiple reply addresses for the same relying party. See this link for details on how to add an RP. From the linked code sample, register more addresses as follows:
RelyingParty relyingParty = new RelyingParty()
{
Name = "BikeShop",
AsymmetricTokenEncryptionRequired = false,
TokenType = "SAML_2_0",
TokenLifetime = 3600
};
svc.AddToRelyingParties(relyingParty);
RelyingPartyAddress realm = new RelyingPartyAddress()
{
Address = "http://localhost/",
EndpointType = "Realm"
};
RelyingPartyAddress replyAddress1 = new RelyingPartyAddress()
{
Address = "http://localhost/BikeShop",
EndpointType = "Reply"
};
RelyingPartyAddress replyAddress2 = new RelyingPartyAddress()
{
Address = "http://localhost/BikePartsShop",
EndpointType = "Reply"
};
svc.AddRelatedObject(relyingParty, "RelyingPartyAddresses", realmAddress);
svc.AddRelatedObject(relyingParty, "RelyingPartyAddresses", replyAddress1);
svc.AddRelatedObject(relyingParty, "RelyingPartyAddresses", replyAddress2);
svc.SaveChanges(SaveChangesOptions.Batch);

Try out this code to help you forward to a specific identity provider, if you can figure out how to remember which identity provider they last used. The last login should be stored so that you will automatically 302 back to your app.
public IdentityProvider GetIdentityProvider(string identityProviderName, string realm , string audienceUri )
{
// acs config parameters
string acsNamespace = ConfigurationManager.AppSettings["ida:Namespace"];
realm = realm ?? Uri.EscapeDataString(ConfigurationManager.AppSettings["ida:Realm"]);
audienceUri = audienceUri ?? ConfigurationManager.AppSettings["ida:AudienceUri"];
string returnPath = Uri.EscapeDataString("/home/index");
var newReplyTo =
Uri.EscapeDataString(audienceUri.Replace(new Uri(audienceUri).Authority,
HttpContext.Current.Request.Url.Authority));
// retrieve current identity providers
string idpDiscoveryUrl = string.Format("{0}v2/metadata/IdentityProviders.js?protocol=wsfederation&realm={1}&reply_to={2}&context=rm%3d0%26id%3dpassive%26ru%3d{3}&request_id=&version=1.0", acsNamespace, realm, newReplyTo, returnPath);
string response = null;
using (var client = new WebClient()) {
response = client.DownloadString(idpDiscoveryUrl);
}
List<IdentityProvider> identityProviders = JsonConvert.DeserializeObject<List<IdentityProvider>>(response);
// lookup provider for tenant
var identityProvider = identityProviders.Where(i => i.Name == identityProviderName).FirstOrDefault() ?? new IdentityProvider();
return identityProvider;
}

Related

Azure B2C Graph API issue

I am trying to run the sample at:
https://github.com/Azure-Samples/ms-identity-dotnetcore-b2c-account-management
And am receiving this error:
Enter command, then press ENTER: 7
Create a user with the custom attributes 'FavouriteSeason' (string) and 'LovesPets' (boolean)
Have you created the custom attributes 'FavouriteSeason' (string) and 'LovesPets' (boolean) in your tenant?
Code: Request_BadRequest
Message: One or more property values specified are invalid.
Inner error:
AdditionalData:
date: 2020-06-30T23:24:26
request-id: dad23cee-984b-439c-a943-9e1bc6be4c9b
ClientRequestId: dad23cee-984b-439c-a943-9e1bc6be4c9b
I have created the custom attributes and can clear see them in the tenant...it even returns their ids. I've setup the Graph access level appropriately (I believe).
Any ideas? Thank you!
In Code, you need to update Tenant id, client id, client secret and also give B2cExtensionAppClientId= “your application display name” in appsettings.json
You have to create two custom attributes in the B2C portal
I. FavouriteSeason (string)
II. LovesPets (boolean)
Use below code to create the user with the custom attribute
try
{
//Create user
var result = await graphClient.Users
.Request()
.AddAsync(new User
{
GivenName = "Casey",
Surname = "Jensen",
DisplayName = "Casey Jensen",
Identities = new List<ObjectIdentity>
{
new ObjectIdentity()
{
SignInType = "emailAddress",
Issuer ="AADCxPb2c.onmicrosoft.com",
IssuerAssignedId = "x#AADCxPb2c.onmicrosoft.com",
}
},
PasswordProfile = new PasswordProfile()
{
Password = b2c_ms_graph.Helpers.PasswordHelper.GenerateNewPassword(4, 8, 4)
},
PasswordPolicies = "DisablePasswordExpiration",
AdditionalData = extensionInstance
}) ;
Console.WriteLine(result);
string userId = result.Id;
Console.WriteLine(result.Id);
Console.WriteLine($"Created the new user. Now get the created user with object ID '{userId}'...");
Can find it on your registered App on Azure AD B2C:
Click on "API Permissions" on left panel.
Then Chose "APIs my organization uses".
You can find the value under name "b2c-extensions-app. Do not modify. Used by AADB2C for storing user data.".

User.identity.Name is null - configure name with azure authentication .net 4.7

I have an application that is in .net 4.7 and i am wanting to bring authentication over to use Azure AD from windows authentication.
I have this working but i want to use User.Identity.Name which is currently null
I have seen that i can configure this somehow within startup.cs in configuration using NameClaimTypeReceiver
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = false,
NameClaimTypeRetriever = OnNameClaimTypeRetriever
}
I cant see an example of writing this method anywhere OnNameClaimTypeRetriever
would you please be able to provide an example.
I am wanting to set it to OnPremisesSamAccountName which i can get via azure graph
NameClaimTypeRetriever is invoked from TokenValidationParameters.CreateClaimsIdentity(SecurityToken securityToken, string issuer) using those same parameters.
Example:
NameClaimTypeRetriever = (SecurityToken securityToken, string issuer) =>
{
var validUserNameTokens = new[] { "preferred_username", JwtRegisteredClaimNames.Email };
return validUserNameTokens.FirstOrDefault(token => (securityToken as JwtSecurityToken).Claims.Any(claim => token == claim.Type));
}
This checks for any claim which type is either 'preferred_username' or 'email'. If not present, returning null makes CreateClaimsIdentity() use ClaimsIdentity.DefaultNameClaimType instead.

ASP.Net MVC5: Using identity how to attach role with user after login

We protect action with authorize attribute with specific role name this way
[Authorize(Roles="members, admin")]
suppose users and roles are mapped in db table. so when user login then how could i attach role with logged in user using identity.
here i am posting url and sample which show how people do the same in mvc4 with custom form authentication. just see the code and i hope surely understand what i am trying to do with asp.net mvc 5 using identity.
https://www.codeproject.com/Articles/408306/Understanding-and-Implementing-ASP-NET-Custom-Form
see this above url for custom form authentication with asp.net mvc 4
protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
//let us extract the roles from our own custom cookie
string roles = DBHelper.GetUserRoles(username);
//Let us set the Pricipal with our user specific details
e.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles.Split(';'));
}
catch (Exception)
{
//somehting went wrong
}
}
}
}
i am working with asp.net mvc 5 & identity system. please help and guide me. thanks
You have to get logged in user id first
var UserName= await User.Identity.GetUserId()
then you can assign any role to that logged in user like
var _context = new ApplicationDbContext();
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(_context));
UserManager.AddToRole("UserName", "UserRole");

aspnetcore.identity - in role, but getting denied access

Core 2.0, using AspnetCore.Identity. I created a few roles, including "Admin".
//initializing custom roles
var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var UserManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
string[] roleNames = { "Admin", "Training", "Operations", "Membership", "Individual" };
IdentityResult roleResult;
foreach (var roleName in roleNames)
{
var roleExist = await RoleManager.RoleExistsAsync(roleName);
// ensure that the role does not exist
if (!roleExist)
{
//create the roles and seed them to the database:
roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
}
}
I checked the SQL tables, and they're all there.:
Then I add myself to the Admin role (not the full method, but the relevant parts):
var UserManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var _eric = await UserManager.FindByEmailAsync("username#gmail.com");
await UserManager.AddToRoleAsync(_eric, "Admin");
I check the tables, and I'm in there (along with another guy I added to a different role):
I then travel over to my method and slap Authorize on it with two of the roles, one of which I'm in (Admin):
[Authorize(Roles ="Training, Admin")]
public ActionResult Index()
{
return View();
}
And then I get access denied. I'm missing something, but can't figure out what step I messed up. User is in there, I'm logged in, the data tables show me as having the role assigned, and the Authorize tag looks good.
Roles are claims and claims are loaded only on sign in. If you modify a claim (such as by adding a role), you must sign the user out and either automatically sign them back in or prompt the user to re-authenticate, to reload the claims.

deleting computer account from AD c#

I'm trying to delete a computer account from AD using this code:
string ldapBase = "ldap://x.y.z.com/";
string sFromWhere = ldapBase + "rootDSE";
DirectoryEntry root = new DirectoryEntry(sFromWhere, null, null, AuthenticationTypes.Secure);
string defaultNamingContext = root.Properties["defaultNamingContext"][0].ToString();
/* Retrieving the computer to remove */
sFromWhere = ldapBase + defaultNamingContext;
DirectoryEntry deBase = new DirectoryEntry(sFromWhere, null, null, AuthenticationTypes.Secure);
DirectorySearcher dsLookForDomain = new DirectorySearcher(deBase);
dsLookForDomain.Filter = "(&(cn=waprptest))"; // MACHSUPR is the computer to delete
dsLookForDomain.SearchScope = SearchScope.Subtree;
dsLookForDomain.PropertiesToLoad.Add("cn");
dsLookForDomain.PropertiesToLoad.Add("distinguishedName");
SearchResultCollection srcComputer = dsLookForDomain.FindAll();
// Deleting computer
foreach (SearchResult aComputer in srcComputer)
{
DirectoryEntry computerToDel = aComputer.GetDirectoryEntry();
computerToDel.DeleteTree();
computerToDel.CommitChanges();
}
I'm getting exception #
string defaultNamingContext = root.Properties["defaultNamingContext"][0].ToString();
as the rot.Properties count is 0
Please let me know what I'm doing wrong... I'm a newbie to AD
From my experience, to get the RootDSE folder, you must use this LDAP string:
LDAP://RootDSE
First of all, the LDAP must be in all capital letters, and RootDSE also has a capital R at its beginning. LDAP strings are case sensitive!
Also: if you're using .NET 3.5 or newer, you can use a PrincipalSearcher and a "query-by-example" principal to do your searching (much simpler than using DirectorySearcher!):
// create your domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// define a "query-by-example" principal - here, we search for a ComputerPrincipal
ComputerPrincipal qbeComputer = new ComputerPrincipal(ctx);
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeComputer);
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal"
ComputerPrincipal cp = found as ComputerPrincipal;
if (cp != null)
{
// do something with the computer account
}
}
}
If you haven't already - absolutely read the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 which shows nicely how to make the best use of the new features in System.DirectoryServices.AccountManagement. Or see the MSDN documentation on the System.DirectoryServices.AccountManagement namespace.

Resources