loginPopup does not redirect to redirectUri in the original tab but opens redirectUri on Popup in D365 - dynamics-crm

I'm using MSAL in a react based SPA and a PCF component which is imported into a canvas app and this canvas app is embedded into Dynamic365 Field service CRM.
I have created a Azure AAD app registration and added these redirectUri in Single Page Application
localhost:3001
*.crm.dynamics.com/main.aspx //main.aspx because i referenced this Issue #190 earlier.
So when i open my app in localhost:3001, it work fine. It popup a login window ask for login and when close it gives a access token in response. but in second condition pop up is not redirecting back to it's main page but opens in the popup itself.
I have used this inside PCF component which i am using in D365 Field service.
import { PublicClientApplication } from "#azure/msal-browser";
const msalConfig = {
auth: {
clientId: 'client_id',
authority: 'https://login.microsoftonline.com/tanent_id',
redirectUri: '*.crm.dynamics.com/main.aspx',
}
};
const msalInstance = new PublicClientApplication(msalConfig);
var loginRequest = {
responseMode:"query",
scopes: ["openid", "offline_access", "https://storage.azure.com/user_impersonation"],
};
msalInstance.loginPopup(loginRequest)
.then(response => {
console.log(response)
})
.catch(err => {
console.log(err)
});
Reproduction Steps
Create a PCF component with above Code Snippets.
Add this PCF component inside a canvas app.
Embed new created canvas app inside a D365 Field Service CRM.
When you open your PCF component inside the D365 Field Service CRM which runs on this *.crm.dynamics.com/main.aspx, It will open a login Popup. we have to login from that popup.
This popup does not close but open the redirect URL inside the popup only.
and I have added redirect URI inside App registration like this
I have already used every variant like *.crm.dynamics.com/main.aspx and *.crm.dynamics.com/ and *.crm.dynamics.com.
Expected Behavior
A login popup pops up and after the user logs in the pop up closes itself and the loginPopup promise resolves (or rejects).
Actual Behavior
A login popup pops up and after the user logs in the pop up redirects back to my site in the pop up.

Related

Cypress - Microsoft authentication in Newly opened window

We have witnessed a scenario, where it is required to get the user authenticated by Microsoft and then request a callback url.
Login url
We have successfully mitigated the new login prompt window and trying to open Authentication url(got via new window object).
But it is now being visited as the url is continuously redirecting through multiple domains.
We have tried to use origin manually via this process, but when it will redirect to another (unknown)URL, the test will lead to a blank page.
Is it possible to visit an unknown URL and complete the authentication.
cy.origin('https://login.microsoftonline.com/', () => {
/// get email field and try to type
})

Problem with Sign-in to Nativescript app with google provider

I try to use google provider to log in to my angular nativescript app. My web app works properly, for mobile added SHA-1 to firebase console.
I have two problems:
After try to log in with google provider firebaseWebApi.auth().onAuthStateChanged not fired (login function returns User properly).
When Sign-in with google provider is not possible I try to simply log in with firebaseWebApi.auth().signInWithEmailAndPassword(), but I have an error message: "Logging in the user failed. com.google.firebase.auth.FirebaseAuthRecentLoginRequiredException: This operation is sensitive and requires recent authentication. Log in again before retrying this request."
It's weird because without trying to log in with google provider, signInWithEmailAndPassword works properly.
public async startLoginGoogle(): Promise<firebase.auth.UserCredential> {
const user = await firebase.login({
type: firebase.LoginType.GOOGLE
});
// user with getIdTokenResult() is available here
return user.getIdTokenResult();
}
firebaseWebApi.auth().onAuthStateChanged((user: firebase.User) => {
// nothing
subject.next(user);
});
Any idea?

Azure Bot - Directline token generation from html page hiding secret

I was trying to do some work around with azure bot service using Direct Line Channel from html page.
Script within html page is as follows:
index.html
var directLine = new window.WebChat.createDirectLine({ secret: 'SECRET' });
directLine.postActivity({
from: { id: 'myUserId', name: 'myUserName' }, // required (from.name is optional)
type: 'message',
text: 'hi'
}).subscribe(
id => console.log("Posted activity, assigned ID ", id),
error => console.log("Error posting activity", error)
);
directLine.activity$
.filter(activity => activity.type === 'message')
.subscribe(
message => console.log("received message ", message)
);
I found API "https://directline.botframework.com/v3/directline/tokens/generate" where secret can be exchanged with token but SECRET has to be added in Authorization header.
Is there a way to hide SECRET in html page without using MVC architecture? Or any other method to interact without exposing SECRET key.
No, there is no way to hide the secret. If it's in the web page, then it is accessible to anyone who inspects the source.
You don't necessarily have to opt for an MVC setup, however. All you need to do is create a service with APIs you can then access.
If you look over the latter half of this solution I previously provided, I demonstrate a simple setup that I run locally for development purposes. From the page hosting the Web Chat instance, I make a call to my custom /directline/token endpoint. The service, appended to my bot's index.js file gets a token and returns it back for use in Web Chat.
In production, I put the "token server" in its own file, and deploy it with the web app. It runs in the background on the server remaining inaccessible (as a file) but accessible via the APIs. Just lock down the API resources and you should be good to go.

Sending a message from parent page to AWS Lex Bot

I'm trying to restrict my Lex Bot to only show results of a SQL Search that a certain User has access to. For example, if User A only has access to records that belong to User A, the Bot will not allow User A to search for records that belong to User B.
Right now, I've got my Bot set up on a website that I've hosted via AWS S3. The issue I'm facing right now is getting my user's login information from the parent page (the website I've set up in S3) and sending it to my Lex Bot (which I've embedded as an Iframe).
The login to the page is done via Google Login which saves an Access Token in my SQL Database. I'd like to know how I can send this access token to my Lex Bot so I can authenticate it via Lambda. (I've already got the Lambda portion done, just need to know how to get the message from the parent page. Ideally, this part happens before the User talks to the Bot, which means a postback message so the user cannot see this information)
Things I've tried:
- I've tried doing a separate lambda function to handle this part only but don't really know how to integrate it into the website.
- I've tried using event listeners but am not very sure if the message goes to the bot or just the IFrame.
Right now, I'm out of ideas and any help would be greatly appreciated.
I managed to finally do it by adding a Javascript function to post a message. It doesn't look very professional but it works.
function isBotMinimized() {
return $('.' + lexWebUi.options.containerClass)
.hasClass('lex-web-ui--minimize');
}
function sendMessage() {
return Promise.resolve()
.then(function () {
return !isBotMinimized() ||
lexWebUi.sendMessageToIframe({ event: 'toggleMinimizeUi' });
})
.then(function () {
return lexWebUi.sendMessageToIframe({ event: 'postText', message: "Welcome"});
})
.then(function () { console.log('message succesfully sent'); })
.catch(function (error) { console.error('error sending message ', error); });
}

How can I create a login page in Xamarin.Forms?

How can I create a login page using Xamarin.Forms?
I'm debugging on Android device and
on the page I try to query the given username and password from an MSSQL database in MSSQL
and if the login be successful, the page will navigate to a new page, else will show authentication failed.
How can I do this in Xamarin.Forms?
(Xamarin LoginFlow Example linked at bottom of answer)
You would have multiple Xamarin.Forms pages and use a NavigationPage to push or pop them from the (lifecycle) stack.
Ref: https://developer.xamarin.com/api/type/Xamarin.Forms.NavigationPage/
Think of each Page a complete self-contained mini application. So the Login page might handle the getting the UserID/Password interactively from the user, performing a authorization check via a server via a Rest api that performs your SQL query. If login is successful it pushes a new Forms-based page on the NavigationPage stack. i.e.
SplashScreen -> LoginPage -> MainPagePage
LoginFlow Xamarin example
This sample demonstrates how to manipulate the navigation stack in order to only display the main page of the application once the user has successfully logged in.
For more information about the sample see Hierarchical Navigation.
What you need is the following functionalities:
Web APIs (Web Service for Login - Hosted on internet or local network - Connected with your MSSql Server)
A Login Screen in Xamarin.Forms Application (You can design it on your own or use the above mentioned demo)
On Login Screen's 'Login' button click, you need to call the Login Web Service from Xamarin.Forms application.
This requires networking (Internet Permission on Android Project, through Manifest.xml). You can use Microsoft.Net.Http for Web Service Calls.
(Look at this example http://www.c-sharpcorner.com/UploadFile/nirmal.hota/consuming-restful-web-service-in-xamarin-forms-project-using/ )
If your server responses with JSON and you need to parse JSON then you can use Json.Net (Newtonsoft.Json).
Note: What I am trying to tell you is that you need to use Web Services that are connected to the database and hosted on a server. From Xamarin.Forms application, you have to call this web-service with appropriate parameters. This requires networking, so you can use Microsoft.Net.Http (or there are other plugins also available). To get response from the Web Service, if it is in Json then you can use Newtonsoft.Json to parse Json.
There is a full example of an app with login page: xamarin-forms-samples/LoginDemo/ provided by Xamarin.
So lets say you have a LoginController on asp.net web api (if you don't know how to create an asp.net web api project etc. this is not the place to learn it:) )
[RoutePrefix("v1/login")]
public class LoginController : ApiController
{
[Route("")]
[HttpPost] //I'm using post!!!!!! you may use get etc.
public IHttpActionResult Login(UserLoginData request)
{
var userData = CheckFromDb(request);
return Json(userData);
}
}
It checks your request from db (UserLoginData is a simple class lets say holds username and password), than if user exists you return another class (lets say it is UserData hat holds name,surname, birthday etc.). If it can not find login it may return null. It's up to you.
So it will be available on your host machine like
localhost:34252/v1/login
(34252 your port-may change for you)
So you have to call it from the device (xamarin.forms) code like this
public string Post(string url, UserLoginData userLoginData)
{
//url is login url as defined above and userLoginData holds your
//user interface (textbox) data :)
using (var client = new HttpClient())
{
client.Timeout = new TimeSpan(0, 0, 30);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
StringContent content;
content = new StringContent(JsonConvert.SerializeObject(userLoginData), Encoding.UTF8, "application/json");
HttpResponseMessage response = client.PostAsync(url, content).Result;
if (!response.IsSuccessStatusCode)
{
throw new Exception("call failed");
}
//this is your response as json
var responseString = response.Content.ReadAsStringAsync().Result;
//you can convert it and check to a specific class if you need
var userData = JsonConvert.DeserializeObject<UserData>(responseString);
}
}
So UserLoginData and UserData classes both must exists on both sides. You can use Newtonsoft.Json library for json parsing (jsonconvert is it's method). Hope this helps you
And android device simulator networking is a bit tricky. You may not connect to localhost directy. It may take an address like 10.0.2.* for androidemulator or 10.71.34.* for xamarin simulator. Please check your network cards for ip addresses and findthe correct one via "cmd.exe" and "ipconfig /all" command.

Resources