How do I get the roles for an authenticated logged in extranet user in sitecore 6.4? I'm trying to check the roles to restrict access.
The Sitecore.Context.User.Roles is coming back with default\Anonynous not extranet\WebsiteUser.
UPDATE: When checking the roles directly after login all appears fine. However it's when I check the roles from within a httphandler that the Sitecore.Context.User.Roles is lost and defaults to default\Anonynous.
Create extranet user code:
using (new SecurityStateSwitcher(SecurityState.Disabled))
{
var domainUsername = Context.Domain.GetFullName(user.Email);
Sitecore.Security.Accounts.User sitecoreUser = Sitecore.Security.Accounts.User.Create(domainUsername, user.Password);
Database dbCore = Factory.GetDatabase("core");
Item profileItem = dbCore.GetItem(CustomUserProfilePath);
List<Role> roles = Sitecore.Context.Domain.GetRoles().Where(role => role.Name == "extranet\WebsiteUser").ToList();
if (roles.Any())
{
sitecoreUser.Roles.Add(roles.First());
}
sitecoreUser.Profile.ProfileItemId = profileItem.ID.ToString();
sitecoreUser.Profile.FullName = string.Format("{0} {1}", user.FirstName, user.LastName);
sitecoreUser.Profile.Email = user.Email;
sitecoreUser.Profile.Comment = "Created by the register system";
sitecoreUser.Profile.Save();
}
I have now found a solution through using IIS7 url rewrites instead of routing the handler through the web.config. This keeps the Sitecore.Context so I can check the logged in users roles.
Related
I have a Azure Active Directory B2C tenant. I also have a small service that creates new users in the B2C tenant from a different system. This way I can synchornize both systems. When a user has been added to B2C and logs in the first time, I want the user to be forced to change the password. But whatever I do, the user can just log in and continue, without changing the password..
To add a user to B2C, I use the Microsoft Graph 1.14 package. I push the user information as JSON to the endpoint https://graph.windows.net/{tenantId}/users?api-version=1.6
The log in page is an Azure custom page in the user flow policies. There is also a change password policy, if needed.
This I tried:
When adding the user, I set the password profile. Adding the property "ForceChangePasswordNextLogin" and setting it to true, does not work.
Someone suggested to add the "ForceChangePasswordNextSignIn" property, but B2C doesn't know this property.
Tried to fix it in the policy; didn't work.
Used Google and StackOverflow; not much luck.
This is the user I post to Microsoft Graph:
var user = new GraphUserModel
{
City = "Amsterdam",
CustomField= "999999",
Department = "TestPassword",
DisplayName = "TestPassword",
OtherMails = new[] { "myemail#something.nl" },
PostalCode = "1234 AB",
StreetAddress = "Hoofdweg 6",
Surname = "TestPassword",
TelephoneNumber = "0123456789",
ChainCode = null,
MailNickname = "999999",
UserPrincipalName = "999999#{tenantNameHere}",
SignInNames = new List<SignInNames>
{
new SignInNames
{
Type = "userName",
Value = "999999"
}
},
AccountEnabled = true,
CreationType = "LocalAccount",
PasswordProfile = new PasswordProfile
{
Password = "SomeRandomPassword"
},
PasswordPolicies = "DisablePasswordExpiration"
};
The users are created correctly, but when they log in for the first time, I would like to see a page where they are forced to change the password.
With Sign-up/Sign-in policy I had to implement that manually by flagging users in DB if they have changed the password and then redirecting to password change if they have not changed the password.
I was also not able to find 'out of the box' solution. I found that forceChangePasswordNextLogin works only with Sign-in policy.
I'm building a web app that is essentially a store, but I want to put in an easy way for the admin of the site to add new products. However I want to restrict this part of the site so only the admin can access it. I have no use for other users at this moment.
How do I make it so that anybody with the admin username and password can access these pages and it will persist to know that they are logged in? I already have a system in place that accepts a user input and then continues to the admin pages if it's correct. But the problem is if someone decides to just go directly to the pages like Admin/AddProduct. I'd need my app to know that they're not allowed to access the AddProduct page yet and redirect them back to the login.
Here's how you go about it Joey
You could do this easily by creating a CreateRoles method in your startup class. This helps check if the roles are created, and creates the roles if they aren't; on application startup. Like so.
private async Task CreateRoles(IServiceProvider serviceProvider)
{
//initializing custom roles
var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var UserManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
string[] roleNames = { "Admin", "Store-Manager", "Member" };
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));
}
}
// find the user with the admin email
var _user = await UserManager.FindByEmailAsync("admin#email.com");
// check if the user exists
if(_user == null)
{
//Here you could create the super admin who will maintain the web app
var poweruser = new ApplicationUser
{
UserName = "Admin",
Email = "admin#email.com",
};
string adminPassword = "p#$$w0rd";
var createPowerUser = await UserManager.CreateAsync(poweruser, adminPassword);
if (createPowerUser.Succeeded)
{
//here we tie the new user to the role
await UserManager.AddToRoleAsync(poweruser, "Admin");
}
}
}
and then you could call the await CreateRoles(serviceProvider); method from the Configure method in the Startup class.
ensure you have IServiceProvider as a parameter in the Configure class.
Question 2: "How do I make it so that anybody with the admin username and password can access these pages "
You can do this easily, like so.
[Authorize(Roles="Admin")]
public class ManageController : Controller
{
//....
Return View();
}
You can also use role-based authorization in the action method like so. Assign multiple roles, if you will
[Authorize(Roles="Admin")]
public IActionResult Index()
{
/*
.....
*/
}
While this works fine, for a much better practice, you might want to read about using policy based role checks. You can find it on the ASP.NET core documentation here, or this article I wrote about it here
Once you add ASP.NET Identity to your project you can implement Role based Authorization in your application. Basically it allows you to setup [Authorize(Roles = "Administrator")] attribute for contollers which shall be available for admin users only.
I'm trying to deploy the validation logins for active directory groups. as shown below
// Control with groups restriction of the ad
[Authorize (Roles = "Financial, ADM")]
public class FinanceiroController: Controller
{
}
I'm using FormsAuthentication to login:
Principal User = autenticacao.Autenticar (login, password);
if (User! = null)
{
FormsAuthentication.SetAuthCookie (login, true);
}
the problem is that I can not access the same controller using a user q is the ADM group, someone help me?
I have an existing ASP.NET application that uses LDAP for authentication and ASP.NET membership for authentication and authorization.
So an LDAP user could choose to authenticate either using his LDAP credentials, or ASP.NET membership credentials. A non LDAP user can only authenticate using LDAP credentials.
I now want to create a Web API project that uses a similar approach for authentication and authorization.
Using VS 2013, I created a new Web API project that uses the Individual Accounts option for authentication.
I've modified the GrantResourceOwnerCredentials method in the Providers\ApplicationOAuthProvider.cs file.
Before
...
IdentityUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
...
After
...
IdentityUser user;
if (AuthenticateActiveDirectory(context.UserName, context.Password, "MyADDomain"))
{
user = await userManager.FindByNameAsync(context.UserName);
}
else
{
user = await userManager.FindAsync(context.UserName, context.Password);
}
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
...
And the AuthenticateActiveDirectory method is:
private bool AuthenticateActiveDirectory(string userName, string password, string domain)
{
bool validation;
try
{
var lcon = new LdapConnection(new LdapDirectoryIdentifier((string)null, false, false));
var nc = new NetworkCredential(userName, password, domain);
lcon.Credential = nc;
lcon.AuthType = AuthType.Negotiate;
lcon.Bind(nc);
validation = true;
}
catch (LdapException)
{
validation = false;
}
return validation;
}
This works, but is it the best way of doing it or is there a better way?
It's fine. Couple things come to mind:
If you have multiple domains in your forest (or ever will support that), username isn't unique across the forest - just the domain. Looks like you're keying on username today.
For your LdapConnection, I assume the null server name is just for show here? Rather than hardcoding one, you can use the S.DS.AD namespace to find a domain controller for you.
You'd probably want AuthType.Basic rather than Negotiate here. You'll want to make sure your connection is LDAP/S since the creds will be cleartext.
I have a method to retrieve a list of AD groups that a user belongs to. Here is the code:
public static List<GroupPrincipal> GetGroups(string userName)
{
List<GroupPrincipal> result = new List<GroupPrincipal>();
// establish domain context
PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);
UserPrincipal user = null;
// find your user
user = UserPrincipal.FindByIdentity(yourDomain, userName);
// if found - grab its groups
if (user != null)
{
PrincipalSearchResult<Principal> groups = user.GetGroups();
// iterate over all groups
foreach (Principal p in groups)
{
// make sure to add only group principals
if (p is GroupPrincipal)
{
result.Add((GroupPrincipal)p);
}
}
}
return result;
}
In both IE and Chrome, this can work fine, but in Firefox, it always gives me DirectoryServicesCOMException on the user = UserPrincipal.FindByIdentity(yourDomain, userName); I don't even have any idea what kind of exception that is. Can someone explain me what the error is and how to fix it? Thank you so much!
Change the call to look like this:
using (HostingEnvironment.Impersonate()){
user = UserPrincipal.FindByIdentity(yourDomain, userName);
}
You will need to make sure that your application pool has AD permissions. This will perform the underlying AD call using the credentials of the hosting environment (the web App Pool Identity) instead of the credentials of user, who may not have permissions to query the AD server.