How to create a user with email as login using Graph API in Azure B2C - azure-ad-graph-api

I am implementing Azure B2C in my ASP MVC application.
My sign up policy has email account chosen so If a user sign up, his account is created and he can log in using his email (I mean private email like xxx#gmail).
If I look at old azure portal -> users section, for this particular user there is no meaningfull data, just objectId. Where the email he provided is stored? (alternate mail field is empty).
And here starts my real question.
I would like also add users via Graph API. I am doing this via GraphConsoleAppV3 sample application. However I cannot set the mail field, the only thing I can do is add the email (custom email like #gmail) to the 'OtherEmails' collection.
But adding the user this way, I cannot log in to my application using private email. I can login using UPN name but I do not want to. Users will not know the UPN, only they real emails.
I can see in the Internet samples with something like 'SignInNames' but iin PowerShell.
I would like to set the user via Graph API and indicate that it has email as login type - not UPN. Hot to achieve it?

I have found that there is other sample project to create users in B2C (via posts with json). It seems that to sync B2C with AD and entire graph will take a while and all the nomenclature needs to unified

Not sure I understand the question, and this is from ages ago, but this may help someone in the future.
If you want to create a user in B2C through the Microsoft Graph API in C#, with an email as their sign-in, you can do the following:
NOTE: This is assuming you already setup the Microsoft Graph API in your C# application. If you have not done that yet, you can follow this.
First Create the user and the Identities.
public async Task CreateUser(string username, string givenName, string email, string password)
{
var identities = CreateIdentities(username, email, new List<ObjectIdentity>());
var user = new User
{
AccountEnabled = true,
DisplayName = username,
GivenName = givenName,
Identities = identities,
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = false,
Password = password
}
};
var response = await userRepository.CreateUserRequest(user);
}
When creating the Identities make sure the email and username are not the exact same values.
private List<ObjectIdentity> CreateIdentities(string username, string email, List<ObjectIdentity> identities)
{
if (email != null) identities = AddIdentity(identities, "emailAddress", email);
if (username != null && (!username.Equals(email) || email == null)) identities = AddIdentity(identities, "userName", username);
return identities;
}
/// <summary>
/// Adds an Identity to the ObjectIdentity list
/// </summary>
/// <param name="identities">List of identities</param>
/// <param name="signInType">Type of sign-in, which is mostly just emailAddress or userName</param>
/// <param name="issuerAssignedId">The value of the sign-in name or email, for example t.chermin#please.nl</param>
/// <returns>List of ObjectIdentity</returns>
private List<ObjectIdentity> AddIdentity(List<ObjectIdentity> identities, string signInType, string issuerAssignedId)
{
var identity = new ObjectIdentity
{
SignInType = signInType,
Issuer = issuer,
IssuerAssignedId = issuerAssignedId
};
identities.Add(identity);
return identities;
}
Finally, we can add the user to our AADB2C environment:
public async Task<User> CreateUserRequest(User user)
{
try
{
return await graphClient.Users
.Request()
.AddAsync(user);
}
catch (Exception ex)
{
}
return null;
}

Related

How to get Firebase UID knowing email user?

I am building a Flutter app where the administrator profile can create users to access their company. The code works right, unless the new user was previously created for another company. In this case an error of type ERROR_EMAIL_ALREADY_IN_USE appears from FIREBASE AUTH. What I want to do is simply retrieve the assigned UID from FIREBASE AUTH, which is necessary to assign the user within my database to an additional company.
It's my code...
_register(LoginBloc bloc, BuildContext context) async{
final usuarioBloc = Provider.usuarioBloc(context);
if (!formKey.currentState.validate() ) return;
final info = await usuarioProvider.crearUsuarioFirebase(bloc.email, bloc.password, true);
if (info['ok']) {
final keyUserId = info['localId'];
usuarioProvider.crearUsuarioRaiz(keyUserId, _prefs.idEmpresa, bloc.email);
usuario.idUsuario = info['localId'];
usuario.correo = bloc.email;
usuarioBloc.crearUsuarioEmpresa(usuario, usuario.idUsuario, usuario.idEmpresa); //to create user in the Company
print('******* User was Created *************');
} else { //info['ok'] is false
switch (info['mensaje'].code) {
case 'ERROR_EMAIL_ALREADY_IN_USE':
usuario.correo = bloc.email;
// usuario.idUsuario = ????????
// Here I would like to retrieve the UID to assign it to their additional Company
usuarioBloc.crearUsuarioEmpresa(usuario, usuario.idUsuario, usuario.idEmpresa); //to create user in the Company
print('*** User already in use, the user can use his/her usual password ***');
break;
default:
print(info['mensaje'].message); //If it was a different error
}
}
}
In Provider, I have...
Future <Map<String, dynamic>> crearUsuarioFirebase(String email, String password, [bool desdeAdmin = false]) async {
try {
AuthResult result = await _firebaseAuth.createUserWithEmailAndPassword(email: email, password: password);
FirebaseUser user = result.user;
return {'ok' : true, 'localId':user.uid, 'email' : user.email};
} catch (e) {
print(e);
return {'ok': false, 'mensaje': e};
}
}
How can I programmatically obtain the UID knowing its user email?
There is no way to look up a user's UID from their email address using the Firebase Authentication client-side APIs. Since this lookup is considered a trusted operations, it is only available in the Admin SDK for Firebase Authentication.
The two most common solutions are:
Create a custom server-side API in a trusted environment (such as Cloud Functions) that performs the lookup, and then call that API from your client-side application. You will have to make sure that only authorized users can perform this lookup.
Store the information about each user into a database (like the Realtime Database that you tagged your question with) when their account is created, or whenever they sign in. Then you can look up the UID from the email in the database. Here too, you will have to ensure that the data is only available in ways that fit with your application's data privacy requirements.
Note that if you just need to know whether an email address is in use (and not the specific UID that uses it), you can call the fetchSignInMethodsForEmail method.

email_verified = false in ID token from Google

I use Google ID tokens to sign in users to my webservice. As part of validating the token it receives from Google, the webservice checks that email_verified = true in the token's payload.
Some of my users signed up for a Google-account with their non-Gmail, non-Google Apps email address. They did click the link in the email that Google sent them after sign-up, to verify their email address.
When those users try to login to my webservice, I get email_verified = false in the token's payload.
What does this mean and can/ should I ignore this in validating the token?
There are a couple of different ways in which you can validate the integrity of the ID token on the server side:
"Manually" - constantly download Google's public keys, verify signature and then each and every field, including the iss one; the main advantage (albeit a small one in my opinion) I see here is that you can minimize the number of requests sent to Google.
"Automatically" - do a GET on Google's endpoint to verify this token
https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}
Using a Google API Client Library - like the official one.
Here's how this could look:
private const string GoogleApiTokenInfoUrl = "https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}";
public ProviderUserDetails GetUserDetails(string providerToken)
{
var httpClient = new MonitoredHttpClient();
var requestUri = new Uri(string.Format(GoogleApiTokenInfoUrl, providerToken));
HttpResponseMessage httpResponseMessage;
try
{
httpResponseMessage = httpClient.GetAsync(requestUri).Result;
}
catch (Exception ex)
{
return null;
}
if (httpResponseMessage.StatusCode != HttpStatusCode.OK)
{
return null;
}
var response = httpResponseMessage.Content.ReadAsStringAsync().Result;
var googleApiTokenInfo = JsonConvert.DeserializeObject<GoogleApiTokenInfo>(response);
if (!SupportedClientsIds.Contains(googleApiTokenInfo.aud))
{
Log.WarnFormat("Google API Token Info aud field ({0}) not containing the required client id", googleApiTokenInfo.aud);
return null;
}
return new ProviderUserDetails
{
Email = googleApiTokenInfo.email,
FirstName = googleApiTokenInfo.given_name,
LastName = googleApiTokenInfo.family_name,
Locale = googleApiTokenInfo.locale,
Name = googleApiTokenInfo.name,
ProviderUserId = googleApiTokenInfo.sub
};
}

Azure Mobile Services backend serviceUser does not return Facebook identities as expected

I'm struggling with a Xamarin Forms (iOS)/Azure Mobile Services/Facebook issue that I don't know how to resolve. What I'm trying to do is login to Facebook using AMS and then save that user's details to a service side database via a custom controller. I am running Azure Mobile Services on the backend.
What I have in place is the code below that successfully logs in a Facebook user.
var fbUser = await DependencyService.Get<IMobileClient>().LoginAsync(MobileServiceAuthenticationProvider.Facebook);
I then want to save fbUser to the database where I'm using ASP.NET Identity tables all configured. I want to use this user to gain access to the facebook user's profile information. I therefore have a backend service custom controller action that looks like this:
[Route("logintofacebook")]
[AuthorizeLevel(AuthorizationLevel.Anonymous)]
public async Task<IHttpActionResult> LoginToFacebook(MobileServiceUser msUser)
{
try
{
if (msUser != null)
{
var serviceUser = User as ServiceUser;
var identities = await serviceUser.GetIdentitiesAsync();
var result = new JObject();
var fb = identities.OfType<FacebookCredentials>().FirstOrDefault();
if (fb == null)
{
return NotFound();
}
var googleCredentials = identities.OfType<GoogleCredentials>().FirstOrDefault();
var azure = identities.OfType<MicrosoftAccountCredentials>().FirstOrDefault();
var accessToken = fb.AccessToken;
result.Add("facebook",
await GetProviderInfo("https://graph.facebook.com/me?access_token=" + accessToken));
var email = GetUserInfo(result);
var userTypeId = UTypes.Facebook;
When debugging on the backend side, the MobileServiceUser is a valid object and I can check the token and Facebook userid which are the same as were created on the client. However, the highlighted line returns zero identities. This means that fb variable end up being null.
The question is, why are no identities being returned from the serviceUser variable above?
Here's what the debugged AMS token looks like when debugged with jwt.io
{
"iss": "urn:microsoft:windows-azure:zumo",
"aud": "urn:microsoft:windows-azure:zumo",
"nbf": 1446872000,
"exp": 1449464000,
"urn:microsoft:credentials": "{\"accessToken\":\"CAAL2gwRM4RYBAKV9Wp0Evjp2aATnm5OIHHc15ujJfeevqCW6DoI36HOQCOYq96xUjZA6VXwovnkBOlY0SkC9nrdwr8jdbF3qJdtK4GAHVk9SGxKVYUZBJ4UwPqQmb5yka93GzL0Fl86m93LnqTffIPJ6vkMfpP0ZAroKzmcJxM1pJ7BAAAA\"}",
"uid": "Facebook:0000000000000000",
"ver": "2"
}
(I've replaced out the facebook section with zeros)
thanks
O

Spring Security and social SignUp with Rest

My application exposes a REST API for services and uses SpringSecurity to manage login at the private services.
With custom signup and login I don't have any kind of problem, but now I try to implement login/signup with Facebook or Twitter, and I don't know how to do this.
Has anyone had the same problem and solved it?
I tried to use a custom password "very long" for every Facebook and Twitter account but that didn't work.
UPDATE
I try your solution, but get an error. This is my code
public UserDetails loadUserByUsername(String mail) throws UsernameNotFoundException {
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
if (ConstantPWCabinet.SOCIAL_LOGIN_FACEBOOK.equalsIgnoreCase(attr.getRequest().getParameter(ConstantPWCabinet.LOGIN_TYPE))) {
User facebookInfo = dao.getFacebookInfo(new FacebookTemplate(attr.getRequest().getParameter(ConstantPWCabinet.FACEBOOK_TOKEN)));
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority(Role.ROLE_USER_FACEBOOK.toString()));
org.springframework.security.core.userdetails.User user = new org.springframework.security.core.userdetails.User(facebookInfo.getEmail(), null, authorities);
Authentication auth = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
return user;
}
logger.debug("Mail di accesso: " + mail);
User user = dao.getUserSelectedMail(mail);
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
String role = user.getRole().toString();
if (StringUtils.isEmpty(role))
authorities.add(new SimpleGrantedAuthority(Role.ROLE_USER.toString()));
else
authorities.add(new SimpleGrantedAuthority(role));
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), authorities);
}
But i get and "Bad credential" and no get login.
You have an AuthenticationFilter that listens to url j_spring_security_check
Filter creates an authentication object and sends to Authentication Provider.
AuthenticationProvider calls UserDetailsService to load user by username and authenticate the user.
Filter then checks the authentication object returned by the provider and sends request to success/failure handler.
When you do it through social medium, your user is authenticated by an external source, so you do not need to authenticate user at your end.
You can simple do
// Authenticate the user
UserDetails user = userDetailsService.loadUserByUsername(username);
Authentication auth = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
This will authenticate the user without password.

ServiceStack OAuth - registration instead login

In servicestack OAuth implementation I only saw possibility to automatically login with eg. facebook account.
But is there abbility to support registration process with facebook login. What I wanted is to let users login to facebook app, and then load their Name, Surname and email and prefill needed text boxes for real registration on my site (since I also have to have mobile phone verification etc.) I don't want user to be authorized and authenticated when he logs in with facebook. Only credentials login should be valid one for full site access.
Edit: I found a solution.
In FacebookProvider.cs
public override bool IsAuthorized(IAuthSession session, IOAuthTokens tokens, Auth request = null)
{
if (request != null)
{
if (!LoginMatchesSession(session, request.UserName)) return false;
}
return tokens != null && session.UserName!=null && !string.IsNullOrEmpty(tokens.AccessTokenSecret);
}
The catch was the && session.UserName!=null part. So we can check if user is logged in using credentials, this will be !=null and user can use all services. If not, this will be ==null and he can only get facebook info from session.
The SocialBootstrap API project shows an example of handling the callback after a successful Authentication by overriding the OnAuthenticated() hook of its custom user session:
I've pulled out, rewrote some and highlighted some of the important bits:
public class CustomUserSession : AuthUserSession
{
public override void OnAuthenticated(IServiceBase authService,
IAuthSession session,
IOAuthTokens tokens,
Dictionary<string, string> authInfo)
{
base.OnAuthenticated(authService, session, tokens, authInfo);
//Populate matching fields from this session into your own MyUserTable
var user = session.TranslateTo<MyUserTable>();
user.Id = int.Parse(session.UserAuthId);
user.GravatarImageUrl64 = CreateGravatarUrl(session.Email, 64);
foreach (var authToken in session.ProviderOAuthAccess)
{
if (authToken.Provider == FacebookAuthProvider.Name)
{
user.FacebookName = authToken.DisplayName;
user.FacebookFirstName = authToken.FirstName;
user.FacebookLastName = authToken.LastName;
user.FacebookEmail = authToken.Email;
}
else if (authToken.Provider == TwitterAuthProvider.Name)
{
user.TwitterName = authToken.DisplayName;
}
}
//Resolve the DbFactory from the IOC and persist the user info
using (var db = authService.TryResolve<IDbConnectionFactory>().Open())
{
//Update (if exists) or insert populated data into 'MyUserTable'
db.Save(user);
}
}
//Change `IsAuthorized` to only verify users authenticated with Credentials
public override bool IsAuthorized(string provider)
{
if (provider != AuthService.CredentialsProvider) return false;
return base.IsAuthorized(provider);
}
}
Basically this user-defined custom logic (which gets fired after every successful authentication) extracts data from the UserSession and stores it in a custom 'MyUserTable'.
We've also overridden the meaning of IsAuthorized to only accept users that have authenticated with CredentialsAuth.
You can use this data to complete the rest of the registration.
Other possible customizations
ServiceStack's built-in Auth persists the AuthData and populates the Session automatically for you. If you want to add extra validation assertions you can simply use your own custom [Authentication] attribute instead containing additional custom logic. Look at the implementation of the built-in AuthenticateAttribute as a guide.