Azure AD B2C - Recover your Account differs from Reset Password - azure-active-directory

I am using Azure AD B2C (and MSAL), and have sign up / sign in, edit profile and password reset policies enabled and working.
However, I have noticed an anomaly if you are going through the Edit Profile workflow and select Recover Account, the flow returned is not the same as the Reset Password policy linked to the login flow.
When the user enters identity info and the captcha, it returns the error 'your organisation has not set up a password reset policy', even though I have as it works if you choose it on sign in.
This is how I set password reset
AuthenticationResult authResult = await ADB2CClient.AcquireTokenAsync(Scopes, GetUserByPolicy(accounts, EditProfilePolicy), UIBehavior.NoPrompt, string.Empty, null, AuthorityEditProfile, App.UiParent);
This is how I set Edit Profile
authenticationResult = await ADB2CClient.AcquireTokenAsync(Scopes, firstAccount, UIBehavior.SelectAccount, string.Empty, null, AuthorityResetPassword, App.UiParent);
However, as mentioned the Recover your Account option on Edit Profile clearly triggers a different flow and I'm unclear how to account for that in Policies?

I guess you are passing different policy names when you are getting authenticationResult. For example, In case of password reset policy, you are passing "AuthorityEditProfile" to get the authentciationResult and in case of edit profile, you are passing "AuthorityResetPassword".
Could you change it and try it again.
For edit profile:
AuthenticationResult authResult = await ADB2CClient.AcquireTokenAsync(Scopes, GetUserByPolicy(accounts, EditProfilePolicy), UIBehavior.NoPrompt, string.Empty, null, AuthorityEditProfile, App.UiParent);
For password reset:
authenticationResult = await ADB2CClient.AcquireTokenAsync(Scopes, firstAccount, UIBehavior.SelectAccount, string.Empty, null, AuthorityResetPassword, App.UiParent);

Related

Connect to Exchange with AD User (Single Sign On)

At the moment I have a Login-Form with Username (logonParamters.Username) and Password (logonParameters.Password) fields.
The code below is working fine but it presupposes that I have a Password to connect to Exchange. But we want to use Single Sign On and if we do so we don't have a Password right? But EWS wants an Username, Password and Domain. So how do I connect to the Exchange using SSO?
var domain = logonParameters.UserName.Split('\\').First();
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain))
{
// validate the credentials
var username = logonParameters.UserName.Split('\\').Last();
bool isValid = pc.ValidateCredentials(username, logonParameters.Password);
if (!isValid)
{
//throw exception
}
using (UserPrincipal up = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, username))
{
//Connect to ExchangeWebService with those AD Credentials.
}
}
In the EWS Managed API (or WSDL proxy) you can use the current security context (eg logged on user creds) like
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2016);
service.UseDefaultCredentials = true;
which means getting it to run in a impersonation context and relying on kerberos to do the auth if possible.

Not able to login after create the user in AD using Java

I have written code using JNDI for creating users using DirContext in AD.
After I create the user I am not able to login with those credentials. When I manually reset the password for that user in AD, I am able to login.
Here I have placed my code for your reference,
Hashtable<String, String> ldapenv = new Hashtable<>();
ldapenv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
ldapenv.put(Context.PROVIDER_URL, "ldap://10.95.144.139:389");
ldapenv.put(Context.SECURITY_AUTHENTICATION, "simple");
ldapenv.put(Context.SECURITY_PRINCIPAL, "CN=Administrator,CN=Users,dc=Merck,dc=local");
ldapenv.put(Context.SECURITY_CREDENTIALS, "Merck2017");
DirContext context = new InitialDirContext(ldapenv);
Attributes attributes = new BasicAttributes();
// Create the objectclass to add
Attribute objClasses = new BasicAttribute("objectClass");
objClasses.add("top");
objClasses.add("person");
objClasses.add("organizationalPerson");
objClasses.add("user");
// Assign the username, first name, and last name
String cnValue = new StringBuffer(user.getFirstName()).append(" ").append(user.getLastName()).toString();
Attribute cn = new BasicAttribute("cn", cnValue);
Attribute sAMAccountName = new BasicAttribute("sAMAccountName", user.getUserName());
Attribute principalName = new BasicAttribute("userPrincipalName", user.getUserName()
+ "#" + "merck.local");
Attribute givenName = new BasicAttribute("givenName", user.getFirstName());
Attribute sn = new BasicAttribute("sn", user.getLastName());
Attribute uid = new BasicAttribute("uid", user.getUserName());
// Add password
Attribute userPassword = new BasicAttribute("userPassword", user.getPassword());
Attribute pwdAge = new BasicAttribute("pwdLastSet","-1");
Attribute userAccountControl = new BasicAttribute("userAccountControl", "544");
// Add these to the container
attributes.put(objClasses);
attributes.put(sAMAccountName);
attributes.put(principalName);
attributes.put(cn);
attributes.put(sn);
attributes.put(givenName);
attributes.put(uid);
attributes.put(userPassword);
attributes.put(userAccountControl);
attributes.put(pwdAge);
// Create the entry
try {
context.createSubcontext(getUserDN(cnValue,"Merck-Users"), attributes);
System.out.println("success === ");
} catch (Exception e) {
System.out.println("Error --- "+e.getMessage());
}
Please help me resolve the following issues:
How do I set AD user password while creating the user using the above code?
How do I set userAccountControl to 66048 in the above code?
How do I create the user enabled while using the above code?
How do I disable the option "user must change the password in next login" while creating the user in the above code?
Thanks in advance.
I don't have all the answers, but this should get you started:
Passwords can only be set over a secure channel, like LDAPS (LDAP over SSL). Since you are connecting to port 389, that is not SSL and AD won't let you set the password. You must connect to the LDAPS port: 636. You may run into issues trusting the SSL certificate. I can't help much here since I'm not a Java developer, but there is an example here.
The answer to your second and third questions is the same: Accounts with no passwords are always disabled. Since you haven't set the password properly, the account will be disabled. Once you figure out how to set the password, you can also set userAccountControl to whatever you need.
You are disabling the "user must change password" option correctly: by setting pwdLastSet to -1. That's the right way to do it. But you may have to fix the other issues first.
Another important thing: I have created AD accounts in .NET, and I have found that I had to create the account first, then go back and set the password and set the userAccountControl attribute after. You may have to do the same.

Is user has active session on IDMsrv?

How to verify IDM does it have an active session for the user signing in?
details - If user'A' has a active session on IDM from browser 'X', When the same user 'A' try to login using browser 'Y', expected behavior identify that user has active session and invalidate the browser'X' session.
Background-
IDM with aspnetIdentity
Client with Implicit grant
(30 sec identitytoken life, does kept renewing access token silently without going to login page, expected to hit some method on the IDM then I can verify user has access or not)!!
Brock has already mentioned about it, It should be at the time of login and logout
It make sense,why its not in Idm. but its definitely possible to provide this as an enhanced feature at least in the coming versions.
Profile Service, IsActive method is the one hit by authorize and
tokenvalidation end point.
so at the time of login persist session, then when the above code hits do the check as per business requirement.
as long as the session is active ( cookie life time) the silent authentication will be passed with the application logic. so this can be controlled by cookie lifetime as well.
public override async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await userManager.FindByIdAsync(sub);
//Check existing sessions
if (context.Caller.Equals("AccessTokenValidation", StringComparison.OrdinalIgnoreCase))
{
if (user != null)
context.IsActive = !appuser.VerifyRenewToken(sub, context.Client.ClientId);
else
context.IsActive = false;
}
else
context.IsActive = user != null;
}
signin
public async Task<IActionResult> Login(LoginInputModel model)
{
if (ModelState.IsValid)
{
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberLogin, false);
if (result.Succeeded)
{
//Update security stamp to invalidate existing sessions
//TODO: This didn't invalidate the existing cookie from another client
//var test= _userManager.UpdateSecurityStampAsync(_userManager.FindByEmailAsync(model.Email).Result).Result;
appUser.PersistSession(new UserSession
{
CreatedOn = DateTimeOffset.Now,
DeviceUniqueId = GetDeviceId(),
UserId = _userManager.FindByNameAsync(model.Email).Result.Id,
SId = httpContext.HttpContext.Session.Id,
ClientId= httpContext.HttpContext.Request.QueryString.Value.GetClientIdFromQuery(),
ExpiresOn = DateTimeOffset.Now.AddMinutes(appSettings.SessionTimeOut)
});
_logger.LogInformation(1, "User logged in.");
return RedirectToLocal(model.ReturnUrl);
}
This method has a few drawback when IIS gets restarted and if user has not signed out properly.
there may be a better options this is not the best fit.!
Update:
refer here duplicate/similar question
idmsrv endpoints are missing security change check
Issue raised
Should be like this #tibold

Two factor authentication using identity server 4

How to implement a two factor authentication using Identity Server 4? The token end point returns a token with a username and password / client credentials.
Can we customize those end points?
Both the methods as per the sample does not allow to customize the end point:
> var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.client", "secret");
> var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("brockallen#gmail.com",
> "Pass123$", "api1");
Is it possible to achieve 2 factor authentication using either asp.net identity Or EF Core implementation?
This shouldn't be a problem at all. When a user is redirected to the Identity Server for login in, if 2FA is enabled then he/she would have to enter the authenticator's code before the Identity Server returns the response back. I have created a repository and blog post series that explain in detail the related concepts. In the AccountController of the IdentityServer you have to check if 2FA is enabled and ask the user to proceed by providing an authenticator code before returning the response.
var signInResult = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, true,
lockoutOnFailure: false);
if (signInResult.RequiresTwoFactor)
{
result.Status = Status.Success;
result.Message = "Enter the code generated by your authenticator app";
result.Data = new {requires2FA = true};
return result;
}
You will also need a TwoFactorAuthenticationController that supports all the 2FA tasks (enable/disable 2FA, sign in with authenticator code/recovery tokens, reset authenticator, etc...)

Email verification through silverlight

I've built a Silverlight website where users can create an account and login. Right now, users just create an account through a form and can directly login. I want to incorporate a email verification feature, where the user will receive an email with a verification URL and only then can he login. I also wish to incorporate a forgot password feature that sends an email to the users registered email address to recover password.
How can I do this in silverlight. I'm using Windows SQL Azure as the back-end database. Will I have to create a separate Application for creating user accounts and recovering passwords?
Hope this helps you out on part A of your problem.
I noticed the post might throw you off a bit, so I decided to write a method that will do this for you in the quickest amount of time.
public bool Send(string fromEmail, string toEmail, string subject, string body)
{
try
{
MailMessage message = new MailMessage();
message.From = new MailAddress(fromEmail);
message.To.Add(new MailAddress(toEmail));
message.Subject = subject;
message.Body = body;
message.IsBodyHtml = false;
SmtpClient smtp = new SmtpClient();
smtp.EnableSsl = true;
smtp.Send(message);
return true;
}
catch (Exception ex)
{
return false;
}
}
Essentially, once they create their account you would want to call this filling out all variables. Make sure in your body of text you have a link that sends them to a page where they can submit "activate" their account.
This will essentially be a bit value in the database that is set to false by default and won't be set to true until they click on the "submit" or "activate" button from the link that would be in the body of text.
For password recovery you would do the same. Except instead of sending them to a page to activate their account you'd send them to a page where they could just re-create their password. Since the database doesn't care if the password is old or new you could just send them to a page where they create a new password. You wouldn't even need to create a temp password for them (Unless you wanted to for experience and for a extra caution).
Happy Coding! ;)

Resources