Skype for web sdk signin issue with on prem use case - skype-for-business

I am trying your samples and some very simple code for signing in. Status changes to Signing In. But it stays there and doesn't go to Signed In.
Following is my code :
var config = {
apiKey: 'a42fcebd-5b43-4b89-a065-74450fb91255', // SDK
apiKeyCC: '9c967f6b-a846-4df2-b43d-5167e47d81e1' // SDK+UI
};
var client;
$(function () {
'use strict';
Skype.initialize({ apiKey: config.apiKey }, function (api) {
client = new api.application();
// whenever client.state changes, display its value
client.signInManager.state.changed(function (state) {
$('p').text("Status : "+state);
});
}, function (err) {
console.log(err);
alert('Cannot load the SDK.');
});
$('#LogIn').click(function () {
// start signing in
client.signInManager.signIn({
username: $('#username').val(),
password: $('#password').val()
}).then(function () {
//log in worked!
$('p').text("Status : "+"Logged In");
}, function (error) {
//Something went wrong.
$('p').text("Status : "+error);
});
});
I installed Skype for Business desktop client and used same username and password and could sign in successfully. But with the above code, I am unable to sign in. Its staying at "signing In". I am not getting errors also. I also used your samples as per this article : https://msdn.microsoft.com/en-us/skype/websdk/docs/downloadrunsamples
But I saw the same issue. The spinning wheel is forever spinning. It looks like it is looking at the same status as my code and staying at signing in.
Please let me know what wrong I might be doing. Just starting with this SDK. Any suggestions for debugging also can help.

Related

OneDrive FilePicker works with a personal account, but not with business account

I have an Angular web app that opens a OneDrive FilePicker and uses a Google Firebase cloud function to transfer the files the user picks to Google storage. It works fine if I use a personal OneDrive account, but if it is a business account I get a CORS error and the files are not transferred. My client-side code looks like this:
oneDriveOptions = {
clientId: '#####',
action: 'download',
multiSelect: true,
advanced: {
redirectUri: `${Utils.getBaseURL()}/one-drive-redirect`,
},
success: (files: any[]) => {
this.zone.run(() => {
this.oneDriveCallback(files);
});
},
cancel: () => {
this.zone.run(() => {
this.dbService.indeterminateProgress = false;
});
},
error: () => {
this.zone.run((error) => {
this.dbService.indeterminateProgress = false;
console.error('OneDrive file picker error:', error);
});
},
};
async oneDriveClicked() {
OneDrive.open(this.oneDriveOptions);
this.dialogRef.close();
}
async oneDriveCallback(files: any) {
try {
this.dbService.indeterminateProgress = true;
const cloudServiceFiles = this.convertOneDriveFiles(files.value);
await this.dbService.addFromCloudService(this.data.dbData, files.accessToken, cloudServiceFiles, this.data.insertIdx, 'oneDrive');
this.dbService.indeterminateProgress = false;
} catch (error) {
console.error(error.message);
this.dbService.indeterminateProgress = false;
}
}
And on the client side:
const getOneDriveFile = async (cloudServiceFile: CloudServiceFile) => {
const fileStream = oneDriveApi.items.download({
accessToken: cloudServiceAuthToken,
itemId: cloudServiceFile.id,
// drive:, default: 'me'. If it's set to be either 'user'/'drive'/'group'/'site', driveId has to be set to.
// driveId: The id of the drive that was shared to us. Must be set if params.drive is set.
});
return fileStream;
};
The output I get in the console:
Any suggestion why this code works fine for a personal account but gives CORS error from a business account?
This means you didn't register your app in Microsoft system so that they didn't let you to use the one drive .
follow this steps then check your app again
Setting up
To get started you need to register your application and receive an app ID from the Azure App registrations page.
To get started you need to register your application and receive an app ID from the Azure App registrations page.
Log in to the Azure App registrations page using your Microsoft account, or a work or school account.
Click Add an app and enter a name for your app.
After your application is created, configure it to support the JavaScript picker:
Click Generate New Password to create an Application secret. While this value is not necessary for the picker, it must have been created.
Click Add Platform and then select Web.
Enter one or more URLs where the picker will be hosted on your website. Each page that hosts the picker needs to have a redirect URL provided.
Click the Save button to save your changes.
Copy the Application Id for your application and use it in the JavaScript options object you provided to open or save a file.

Web app that runs in Microsoft Teams (personal tab) doesn't always work on Desktop version

I have a Web app built in Vuejs and has SSO authentification using microsoftTeams.authentication.getAuthToken when running in Teams, or microsoftAuthLib when running in the browser.
Inside the company's network or when connected to the VPN everything works absolutely fine.
We recently opened it outside of the VPN and we created a public certificate for it. So when I disconnect the VPN, it works:
In any browser (outside of Teams).
Teams browser version.
Teams on Android/iPhone.
But it doesn't work on Teams Windows Desktop version, it fails with the following error:
Refused to display
'https://login.microsoftonline.com/.../oauth2/authorize?...' in a
frame because it set 'X-Frame-Options' to 'deny'.
Anybody has an idea what could be the issue? And why would it work on the company's VPN but not outside?And only on specific cases? I am lost, any help would be appreciated.
Thank you
*** EDIT / ADDED SSO REDIRECT CODE ***
import * as microsoftTeams from "#microsoft/teams-js";
import * as microsoftAuthLib from "msal";
import settings from './settings.js';
var msalConfig = {
auth: {
clientId: settings.sso.id,
authority: settings.sso.authority
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true
}
};
var requestObj = {
scopes: settings.sso.scopes
};
var myMSALObj = new microsoftAuthLib.UserAgentApplication(msalConfig);
myMSALObj.handleRedirectCallback(authRedirectCallBack);
function authRedirectCallBack(error, response) {
if (error) {
console.log(error);
} else {
console.log("token type is:" + response.tokenType);
}
}
function loginRedirect(requestObj) {
let account = myMSALObj.getAccount();
if (!account) {
myMSALObj.loginRedirect(requestObj);
return false;
} else {
return true;
}
}
function acquireMsalToken() {
return new Promise(function (resolve) {
resolve(myMSALObj.acquireTokenSilent(requestObj).then(token => {
return token.accessToken;
}).catch(error => {
acquireMsalTokenRedirect(error);
}));
})
}
function acquireTeamsToken() {
return new Promise((resolve, reject) => {
microsoftTeams.authentication.getAuthToken({
successCallback: (result) => {
resolve(result);
},
failureCallback: (error) => {
reject(error);
}
});
});
}
function acquireMsalTokenRedirect(error) {
if (error.errorCode === "consent_required" ||
error.errorCode === "interaction_required" ||
error.errorCode === "login_required") {
myMSALObj.acquireTokenRedirect(requestObj);
}
}
var msal = {
autoSignIn: function () {
return loginRedirect(requestObj);
},
acquireToken: async function () {
if (settings.sso.inTeams) {
microsoftTeams.initialize();
microsoftTeams.enterFullscreen();
return acquireTeamsToken();
} else {
let signedIn = msal.autoSignIn();
if (signedIn) {
return acquireMsalToken();
}
}
}
}
export default msal
This error means that you are trying to redirect your tab's iframe to the AAD login flow which in turn is unable to silently generate an auth token for you and is attempting to show an interactive flow (e.g. sign in or consent):
Refused to display
'https://login.microsoftonline.com/.../oauth2/authorize?...' in a
frame because it set 'X-Frame-Options' to 'deny'.
To avoid this issue you need to try and acquire a token silently and if that fails use the microsoftTeams.authentication.authenticate API to open a popup window and conduct the AAD login flow there.
Replacing the acquireTeamsToken() function with the following resolved the issue.
function acquireTeamsToken() {
return new Promise((resolve, reject) => {
microsoftTeams.initialize(() => {
microsoftTeams.authentication.authenticate({
url: window.location.origin + "/ms-teams/auth-start",
width: 600,
height: 535,
successCallback: (result) => {
resolve(result);
},
failureCallback: (error) => {
reject(error);
}
});
});
});
}
I found this documentation very helpful on how to create the Authentication pop up and how to create a Callback window with the Token in it.
You might also want to cache the token and only create a popup when it expires.
This might be because you're using the auth popup option instead of the redirect option in whichever auth library you're using (hopefully MSAL 2.0). Teams is a little different because it's actually launching a popup for you when necessary, so although it sounds a bit strange, you actually want to use the redirect option, inside the popup that is launched. What might help is to look at the new SSO Sample app in the Teams PnP samples.
Go to: %APPDATA%\Microsoft\Teams
Open the file hooks.json (if it's not there, create it)
Add the following to it: {"enableSso": false, "enableSsoMac": false}
That's it, now Teams desktop has the same authentication workflow as the browser version. Have a nice day.

The sms code has expired. Please re-send the verification code to try again

Whenever I tried to login with phone number using react-native-firebase sdk, I recieve OTP code through sms and when I submit the recieved code, an error is there saying:"The sms code has expired. Please re-send the verification code to try again." And here point to be noted that an entry for respective phone number is writing in Users section of firebase even there is an error.
I am using following:
NodeJS: v8.11.1,
NPM: v5.6.0,
react-native: "^0.59.9",
react-native-firebase: "^5.5.3"
Some links I have already tried are:
1. https://github.com/invertase/react-native-firebase-
docs/blob/master/docs/auth/phone-auth.md
2. https://stackoverflow.com/questions/46522726/firebase-phone-
authentication-error-the-sms-code-has-expired
3. https://www.bountysource.com/issues/45308170-firebase-phone-
number-auth-integration
4. https://medium.com/#chrisbianca/getting-started-with-firebase-
authentication-on-react-native-a1ed3d2d6d91
5. https://invertase.io/oss/react-native-firebase/v6/auth/phone-
auth
In MobileRegistration.js:
navigateToOtpScreen() {
console.log("Phone number: ", "+91" + this.state.phoneNumber)
firebase.auth().signInWithPhoneNumber("+91" +
this.state.phoneNumber)
.then(confirmResult => {
this.setState({ confirmResult, message: 'Code has been sent!'})
this.props.navigation.navigate('EnterOtp', { 'confirmResult':
confirmResult})
})
.catch(error => {
alert(error.message);
this.setState({ message: `Sign In With Phone Number Error:
${error.message}` })
});
};
In EnterOtp.js:
componentDidMount() {
this.unsubscribe = firebase.auth().onAuthStateChanged((user) => {
alert(JSON.stringify(user));
if (user) {
this.setState({
user: user.toJSON()
});
} else {
// User has been signed out, reset the state
this.setState({
user: null,
message: '',
otp: '',
otp1: '',
otp2: '',
otp3: '',
otp4: '',
otp5: '',
otp6: ''
});
}
});
}
componentWillUnmount() {
if (this.unsubscribe) this.unsubscribe();
}
verifyOTP = async () => {
const {
confirmResult,
} = this.props.navigation.state.params;
let otp = this.state.otp + "" + this.state.otp1 + "" + this.state.otp2 + "" + this.state.otp3 + "" + this.state.otp4 + "" + this.state.otp5 + "" + this.state.otp6
if (confirmResult && otp.length) {
alert(otp);
confirmResult.confirm(otp).then((user) => {
AsyncStorage.setItem('accessToken', confirmResult._verificationId);
this.props.navigation.navigate('SetupCoverVideo');
this.setState({
message: 'Code Confirmed!'
});
})
.catch(error => {
alert(error.message) && this.setState({
message: `Code Confirm Error: ${error.message}`
})
});
}
}
Expected Result: Code should be verified and an entry should be in Users section of firebase and navigate to SetupCoverVideo.
Actual Result: Facing an error saying: "The sms code has expired. Please re-send the verification code to try again." And here point to be noted that an entry for respective phone number is writing in Users section of firebase even there is an error.
I am wondering for the solution. Anyone please assist me.
Apparently, some recent versions of Android are smart enough to receive the SMS verification code and use it to authenticate the user. This authentication happens in the background while the user still receives the verification code in an SMS. When the user tries to enter the verification code, he/she gets a message that the verification code expired, because Android has already used it (in the background) and has already logged in the user! To double-check that, check the Firebase Console. You should find that this new user has been added to the list of users.
To avoid receiving the verification code expiry message, we need to set up a listener for "authentication changes." As soon as Android logs in the user in the background, this listener should navigate the user away from the login screen, in which he/she was supposed to enter the verification code. The following demonstrates how this can be implemented. I would add the following code to the login screen.
Example code for use with functional components:
useEffect( () => {
firebase.auth().onAuthStateChanged( (user) => {
if (user) {
// Obviously, you can add more statements here,
// e.g. call an action creator if you use Redux.
// navigate the user away from the login screens:
props.navigation.navigate("PermissionsScreen");
}
else
{
// reset state if you need to
dispatch({ type: "reset_user" });
}
});
}, []);
Example code for use with class components:
// I did NOT test this version, because I use functional components.
componentDidMount() {
firebase.auth().onAuthStateChanged( (user) => {
if (user) {
// Obviously, you can add more statements here,
// e.g. call an action creator if you use Redux.
// navigate the user away from the login screens:
props.navigation.navigate("PermissionsScreen");
}
else
{
// reset state if you need to
this.setState({
user: null,
messageText: '',
codeInput: '',
phoneNo: '',
confirmResult: null,
});
}
});
};
You need to check for background authentication using:
conponentDidMount() {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// alert(JSON.stringify(user))
// Obviously, you can add more statements here,
// e.g. call an action creator if you use Redux.
// navigate the user away from the login screens:
}
});
}
Then you need to log out your user once you are done with it (I faced this issue of old user session already present while new user was coming to authenticate)
So, at the time of logging out use:
if (firebase.auth().currentUser)
firebase.auth().currentUser.delete();
And you are all set!

Google plus API shutdown, How it will affect Google auth2 login for web sites?

I am confused with shutdown notification mails from Google one of the recent mail mentioned as
projects directly requesting the “plus.me” scope are affected. This scope may have been listed in some emails, even if not directly
requested by your project. We apologize for any confusion caused.
I am using following JS code for login, may I know will it affect anyway due to Google plus api shutdown?
<script async defer src="https://apis.google.com/js/api.js" onload="this.onload=function(){};HandleGoogleApiLibrary()" onreadystatechange="if (this.readyState === 'complete') this.onload()"></script>
<script type="text/javascript">
//google login starts
function HandleGoogleApiLibrary() {
// Load "client" & "auth2" libraries
gapi.load('client:auth2', {
callback: function() {
// Initialize client library
// clientId & scope is provided => automatically initializes auth2 library
gapi.client.init({
apiKey: 'API KEY HERE',
clientId: 'XXXXXXXXXXXXXXXXX.apps.googleusercontent.com',
scope: 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email'
}).then(
// On success
function(success) {
// After library is successfully loaded then enable the login button
//CODE AFTER SUCCESS
},
// On error
function(error) {
alert('Error : Failed to Load Library');
}
);
},
onerror: function() {
// Failed to load libraries
}
});
}
// Click on login button
$("#login-button").on('click', function() {
// API call for Google login
gapi.auth2.getAuthInstance().signIn().then(
// On success
function(success) {
// API call to get user information
gapi.client.request({ path: 'https://www.googleapis.com/plus/v1/people/me' }).then(
// On success
function(success) {
console.log(success);
var user_info = JSON.parse(success.body);
//VALIDATION
},
// On error
function(error) {
alert('Error : Failed to login');
}
);
},
// On error
function(error) {
$("#login-button").removeAttr('disabled');
alert('Error : Login Failed');
}
);
});
There is good news and bad news.
The good news is that you're not using any of the plus scopes.
The bad news is that you're using the plus API, which is also being shut down, and which was mentioned in a previous email that should have been sent to you.
Specifically, this chunk of code:
gapi.client.request({ path: 'https://www.googleapis.com/plus/v1/people/me' }).then(
calls the "plus.people.me" API.
Fortunately, you should be able to switch to a different API, such as the "userinfo" API, by changing endpoints to
https://www.googleapis.com/oauth2/v2/userinfo
You may also wish to look into the more modern People API, which works very similarly, and is slightly more complicated, but can provide other profile fields.

Ember simple-auth mixins deprected

I am an experienced (55+ years) programmer but a total noob in ember and js. I'm trying to get a simple authentication page working using the ember-cli addons ember-cli-simple-auth, ember-cli-simple-auth-oauth2 and cut-and-paste from the simplelabs tutorial.
I get the following in the console:
DEPRECATION: The LoginControllerMixin is deprecated. Use the session's authenticate method directly instead.
and:
DEPRECATION: The AuthenticationControllerMixin is deprecated. Use the session's authenticate method directly instead.
The solution may be trivial, but I have been chasing it for hours and get deep into javascript before reaching a dead-end. The code that is causing these errors is:
import LoginControllerMixin from 'simple-auth/mixins/login-controller-mixin';
export default Ember.Controller.extend(LoginControllerMixin, {
authenticator: 'simple-auth-authenticator:oauth2-password-grant'
});
which invokes the ApplicationControllerMixin somewhere in the bower code.
Before I "re-invent the wheel" by translating some old html/ruby/pascal code into js, can anyone help me "Use the session's authenticate method directly instead."?
Thanks.
I feel you're pain. I spent weeks trying to sort this out. A big part of the problem is that so much has changed in the past couple of years and there are a lot of code examples out there that are outdated or don't work together. It's really difficult to put the various pieces together coherently, and figure out what one does NOT need to do.
That said, please keep in mind that i'm a n00b as well. What i've done seems to work ok but i've no idea whether there's a much better way.
Also, what you're trying to do may not be the same as what i've done. My app authenticates against google (and twitter, fb, etc.) using Simple-Auth-Torii and then exchanges the returned Authenication Code for an Authentication Token. That last part happens on the server. So, after the session authenticates, i then pass the auth code to the server and get back the auth code.
// routes/login.js
import Ember from "ember";
import ENV from "../config/environment";
export default Ember.Route.extend({
setupController: function(controller, model) {
controller.set("errorMessage", null);
},
actions: {
googleLogin: function() {
var _this = this;
// Using "session's authenticate method directly" right here
this.get("session").authenticate("simple-auth-authenticator:torii", "google-oauth2")
.then(function() {
// We're now authenticated. The session should now contain authorization
// code from provider. We now need to exchange that for an auth token.
var secureData = _this.get("session.content.secure");
// call server to initiate token exchange from provider
var exchangeData = {
authorizationCode: secureData.authorizationCode,
redirectUri : secureData.redirectUri,
provider : 'google'
};
// sends ajax request to server, which will in turn call provider
// with authentication code and receive auth token
_this.tokenService.fetch(exchangeData).then(function(response) {
if (response.success) {
_this.set("session.content.secure.access_token", response.data.token);
_this.set("session.content.secure.userData", response.data.user);
// take user somewhere ...
_this.transitionTo("data_sets");
}
else {
// set an error message, log the response to console, whatever, but
// we need to invalidate session because as far as simple-auth
// is concerned we're already authenticated. The following logs the user out.
_this.get("session").invalidate();
}
}, function(error) {
console.log("tokenService.fetch error", error);
_this.get("session").invalidate();
});
}, function(error) {
console.log("simple-auth-authenticator:torii error", error);
_this.get("session").invalidate();
});
},
twitterLogin: function() {
// etc.
}
}
});
Logging a user out also uses the session directly.
{{!templates/application.hbs}}
<ul class="nav navbar-nav navbar-right">
{{#if session.isAuthenticated}}
<li><button {{ action 'invalidateSession' }} class="btn btn-sm">Logout</button></li>
{{/if}}
...
</ul>
// routes/application.js
import Ember from "ember";
import ENV from "../config/environment";
import ApplicationRouteMixin from "simple-auth/mixins/application-route-mixin";
export default Ember.Route.extend(ApplicationRouteMixin, {
actions: {
// action is globally available because in application route
invalidateSession: function() {
// the most basic logout
this.get("session").invalidate();
return;
// If you need to invalidate also on the server do something like:
//
// var _this = this;
// return new Ember.RSVP.Promise(function(resolve, reject) {
// var params = {
// url : ENV.logoutEndpoint,
// type : "POST",
// dataType : "json"
// };
// Ember.$.ajax(params).then(function(response) {
// console.log('session invalidated!');
// console.dir(response);
// _this.get("session").invalidate();
// });
// });
}
}
});
I've met the same deprecation problem. I thinks this snippet for a lovely login controller will do, it's a bit more what you asked, but I hope it is still understandable. I use it with devise, it's almost the same except I use it this way: authenticate('simple-auth-authenticator:devise', credentials)
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
authenticate: function() {
// identification and password are the names of the input fields in the template
var credentials = this.getProperties('identification', 'password');
if (!credentials.identification || !credentials.password) {
return false;
}
this.get('session').authenticate('simple-auth-authenticator:oauth2-password-grant', credentials).then(function() {
// authentication was successful
}, function(errorMessage) {
// authentication failed
});
}
}
});