Getting Incomplete User Details Info from OneLogin - onelogin

I am trying to get user detail info from onelogin after getting token successfully.
But getting some parameters null. I have used below code:
val config = OIDCConfiguration.Builder()
.clientId("XXXXXXX")
.issuer("XXXXXXXX")
.redirectUrl("XXXXXXX")
.scopes(listOf("openid", "profile", "email"))
.isDebug(true)
.build()
OneLoginOIDC.initialize(this.applicationContext,config)
val oidcClient = OneLoginOIDC.getClient()
Now using oidcClient?.signIn() to get token in onSuccess callback and after getting token when i tried to get user info object using oidcClient?.getUserInfo() I get userinfo object like: UserInfo(sub=123936207, email=hksharma#q3tech.com, preferredUsername=null, name=Harish Kr Sharma, updatedAt=null, givenName=null, familyName=null, groups=null)
Here, getting updatedAt, givenName, familyName, groups and preferredUsername parameters value null.
Also how to get some custom additional information added by backened team to onelogin portal

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.".

Can we add authorization scopes for external logins and save results to database in ServiceStack?

Can we customize the scope in GoogleAuthProvider to get more details like their phone number, address or calendar, profile picture?
Also can we view the details of the Identity and access token and parse and save those results in our database?
You can register additional Scopes in the GoogleAuthProvider.Scopes collection which by default is populated with:
this.Scopes = new[] {
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"
};
The OAuth Info from all ServiceStack's OAuth Providers are populated in the registered Auth Repository in the UserAuthDetails table where the Access Token is stored in AccessTokenSecret.
You can retrieve additional info about the user using the Access Token and overriding CreateAuthInfo in a custom GoogleAuthProvider and overriding the CreateAuthInfo() implementation which by default retrieves basic info about the user from the UserProfileUrl (https://www.googleapis.com/oauth2/v2/userinfo):
protected override Dictionary<string, string> CreateAuthInfo(string accessToken)
{
var url = this.UserProfileUrl.AddQueryParam("access_token", accessToken);
var json = url.GetJsonFromUrl();
var obj = JsonObject.Parse(json);
obj.MoveKey("id", "user_id");
obj.MoveKey("given_name", "first_name");
obj.MoveKey("family_name", "last_name");
obj.MoveKey("picture", AuthMetadataProvider.ProfileUrlKey, profileUrl => profileUrl.SanitizeOAuthUrl());
return obj;
}
The returned dictionary populates all well-known properties on UserAuthDetails in the overridable LoadUserAuthInfo() (which can alternatively be intercepted with the LoadUserAuthFilter on each AuthProvider). All other non-matching properties in the dictionary are saved in the Items Dictionary on the UserAuthDetails table.

SuiteScript2.0 calling a Suitelet From User Event Not Working

What Do I Want To Happen
I want to be able to call a Suitelet from a User Event passing in a record id.
What Currently Happens
Either a "INSUFFICIENT_PERMISSION" error is thrown or no error is thrown but the suitelet is not called.
The Details
Hey all, I'm trying to call a suitelet from a User Event. We have a record getting created with some data, upon creating that record in the user event I want to create a Customer and Sales Order. I also need the User Events of those records to fire off. I know a user event cannot trigger another user event so I have written a suitelet to call which will do the processing. I am trying to call the suitelet with the following code.
var scheme = 'https://';
var host = url.resolveDomain({
hostType: url.HostType.APPLICATION
});
var suitletURL = url.resolveScript({
scriptId : 'customscript_pws_sl_data',
deploymentId : 'customdeploy_pws_sl_data'
});
var parameters = {
dataid : scriptContext.newRecord.id,
};
log.debug("URL", scheme + host + suitletURL);
var response = https.post({
url : scheme + host + suitletURL + "&dataid=" + scriptContext.newRecord.id,
body : parameters
});
Using this code, no errors are thrown, but the Suitelet is also not triggered. I know this because as soon as my suitelet triggers I log "Running"
log.debug("Running");
var user = runtime.getCurrentUser();
var script = runtime.getCurrentScript();
// Get parameters
var params = context.request.parameters;
log.debug("Context", JSON.stringify(context.request));
log.debug("Params", JSON.stringify(params));
Now I am logging the URL that the User Event is using and if I copy and paste that into the browser, the suitelet runs. So I know the URL is correct.
WHAT HAVE I TRIED
I have tried adding the
returnExternalUrl: true
parameter of the https call. Using this DOES call the Suitelet however I can an error stating
"type":"error.SuiteScriptError","name":"INSUFFICIENT_PERMISSION","message":"Permission Violation: You need the 'Lists -> Items' permission to access this page. Please contact your account administrator.","stack":["createError(N/error)","getOrderLines(/SuiteScripts/PWS Additional Modules/Additional Modules/Ecommerce Data/pws_lib_ecommerce.js:972)","processData(/SuiteScripts/PWS Additional Modules/Additional Modules/Ecommerce Data/pws_lib_ecommerce.js:109)","onRequest(/SuiteScripts/PWS Additional Modules/Additional Modules/Ecommerce Data/pws_sl_ecommdata.js:40)"],"cause":{"type":"internal error","code":"INSUFFICIENT_PERMISSION","details":"Permission Violation: You need the 'Lists -> Items' permission to access this page. Please contact your account administrator.","userEvent":null,"stackTrace":["createError(N/error)","getOrderLines(/SuiteScripts/PWS Additional Modules/Additional Modules/Ecommerce Data/pws_lib_ecommerce.js:972)","processData(/SuiteScripts/PWS Additional Modules/Additional Modules/Ecommerce Data/pws_lib_ecommerce.js:109)","onRequest(/SuiteScripts/PWS Additional Modules/Additional Modules/Ecommerce Data/pws_sl_ecommdata.js:40)"],"notifyOff":false},"id":"","notifyOff":false,"userFacing":false}
The Suite Deployment is set to "Available Without Login : true" and "All Roles : true"
Update
I am getting You must login before accessing this page.
I am logged in and calling it from a UserEvent
Setting both the User Event and Suitelet to run in Administrator mode and using the "returnExternalUrl: true" setting solved this problem :)
var suitletURL = url.resolveScript({
scriptId : 'customscript_pws_sl_data',
deploymentId : 'customdeploy_pws_sl_data',
returnExternalUrl : true
});
I already running both script as administrator, I log the current user and i get this. It is not the administrator role
{
id: -4,
name: "-Sistema-",
email: "onlineformuser#5273359-sb1.com",
location: 0,
department: 0,
role: 31,
roleId: "online_form_user",
roleCenter: "CUSTOMER",
subsidiary:1
}

How to query the "Exposed Api" for all users calendars in a Tenant?

I want to be able to - from a crohn job on a 3rd. party server - query and modify all users in my the Tenants (organisation) calendars - but i just end up with a "Application ID URI" that i don't know what to do with.
No matter how i query the microsoft graph API i get "Invalid Audience" and the docs on the subject doesn't really seem to highlight how exactly to specify the correct "audience" or what a "resource" actually entails.
These are the steps i have taken in the Azure Active Directory portal:
I use the Client Credentials Grant flow so i can access with a Cron and not through a user. https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
1) Registered an application in the portal. So i get some ID's (anonymized here)
Application (client) ID
:
51ed7b6d-d33e-491e
Directory (tenant) ID
:
c181f4f3-912b-4acf-
Object ID
:
3f52a799-f2ab-4161-a81c
2) Created a secret so i can provide that together with the Application id to get a token.
3) Given "Api Application Permissions" to https://graph.microsoft.com/Calendars.ReadWrite.
4) "Exposed an Api" and called it's scope "readwrite calendars" so the Application ID URI with the scope end up being: api://51ed7b6d-d33e-491e-9d40-1/readwritecalendars
5) Authorized the API to the application with the Application (client) ID from step 1 so i don't need admin consent to query.
Problem is now i just end up with an "Application ID URI", okay how i do i exactly query my for the calendars then?
I am using https://github.com/TheNetworg/oauth2-azure here:
I am able to successfully get a token:
$provider = new \TheNetworg\OAuth2\Client\Provider\Azure([
'clientId' => env('OAUTH_APP_ID'),
'clientSecret' => env('OAUTH_APP_PASSWORD'),
'redirectUri' => 'http://www.google.dk'
]);
$provider->tenant = 'secret';
$token = $provider->getAccessToken('client_credentials', [
'resource' => 'https://graph.windows.net',
]);
$provider->urlAPI = "https://graph.microsoft.com/v1.0/";
$provider->resource = "https://graph.microsoft.com/";
return $token ;
Gives me:
{
"token_type": "Bearer",
"ext_expires_in": "3600",
"expires_on": "1562669834",
"not_before": "1562665934",
"resource": "https://graph.windows.net/",
"access_token": "longstringofnumbers",
"expires": 1562269224
}
There is no "Aud" or "Audience" field returned.
This i where i get confused, how exactly do i form a link, how do i say that i want to query all calendars with the token?
Looking at the outlook graph documentation it specifies i need to query like this (https://learn.microsoft.com/en-us/graph/api/user-list-calendars?view=graph-rest-1.0&tabs=http):
GET /me/calendars
This doesn't really make sense to me as "me" seems to imply a user, i am trying to query stuff in a tenant not tied to a specific user?
Anyway if i try to query like:
$provider->get('me/calendars',$token);
Or different combinations of this i just get:
Access token validation failure. Invalid audience.
To sum it all up: how do i actually query the API to list/modify calendars, what is the actual endpoint i have to hit? And where do i put the actual query?
Thanks in advance!
A result would be a JSON object instead of the error message. A successful return to the query. In this case a list of all users calendars, or a "successfully updated" after modifying a calendar.
In Azure AD you can specify "API Permissions" for an app registration. If you want to query all calendars with one access token you should use "Application permissions".
Point 4 is for other types of applications like Office Add-Ins.
For all request you can use the default Graph endpoint https://graph.microsoft.com/v1.0/. So if you wan't to query a user calendar you should use this:
GET https://graph.microsoft.com/v1.0/<UserId or UPN>/calendar
Got it working with:
$provider = new \TheNetworg\OAuth2\Client\Provider\Azure([
'clientId' => env('OAUTH_APP_ID'),
'clientSecret' => env('OAUTH_APP_PASSWORD'),
]);
$provider->tenant = env('AZURE_TENANT');
$provider->urlAPI = "https://graph.microsoft.com/v1.0/";
$provider->resource = "https://graph.microsoft.com/";
$token = $provider->getAccessToken('client_credentials', [
'resource' => 'https://graph.microsoft.com',
]);
$currentCalendarEvents = $provider->get('users/some#some.com/calendars/Calendar/events?$top=1000', $token);
The $provider->resource and urlapi has to be set before the request off course as written in the docs: https://github.com/TheNetworg/oauth2-azure#microsoft-graph

Azure Mobile Services - Custom Authentication Claims Issue

I've implemented custom authentication in my mobile services, but the claims that I add to my ClaimsIdentity object don't appear to be saved.
I create my ClaimsIdentity object, and then pass it to the CreateLoginResult method, as follows:
public IServiceTokenHandler Handler { get; set; }
...
ClaimsIdentity claimsIdentity = new ClaimsIdentity();
claimsIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "username"));
claimsIdentity.AddClaim(new Claim(ClaimTypes.GivenName, "FirstName"));
claimsIdentity.AddClaim(new Claim(ClaimTypes.Surname, "LastName"));
LoginResult login = new CustomLoginProvider(Handler).CreateLoginResult(claimsIdentity, "masterkey");
If I call another method with the returned authorization token and try to retrieve the GivenName or Surname claims, they aren't available.
var identity = (ClaimsIdentity)User.Identity;
// 'claim' will be null
Claim claim = identity.FindFirst(ClaimTypes.GivenName);
Is this expected behaviour or am I doing something wrong? I'm making an assumption that the Claims in the ClaimsIdentity object being sent to CreateLoginResult are being saved against that authenticated user.
The ClaimsIdentity passed into this method does not get used fully unless you act on it in an overload of CreateCredentials(). First you should create a child class of ProviderCredentials with the fields you want. CreateCredentials() will be called by CreateLoginResult(), and it will get the same ClaimsIdentity as a parameter.
The returned ProviderCredentials gets stored, and you can always retrieve it again in your server code with a call to ServiceUser.GetIdentitiesAsync().

Resources