I have a nodejs application that successfully authenticates using LDAP locally using passport-ldapauth.
However, in another environment it is not working. I have written a .net app that can successfully query LDAP. The different is that it uses NTLM.
I am not familiar with NTLM and how this affects my nodejs project.
LDAP_URL = ldap://<ldap_server_ip address>
LDAP_BIND_DN = ldapadmin
LDAP_BIND_CREDENTIALS = password123
LDAP_SEARCH_BASE = DC=mydomain,DC=com
LDAP_SEARCH_FILTER = (sAMAccountName={{username}})
Am I talking apples and oranges here? I get invalid credentials even though they work in my .net app.
nodesjs code:
super(
(
request: Request,
callback
) => {
const options = {
server: {
url: getEnvValue('LDAP_URL'),
bindDN: getEnvValue('LDAP_BIND_DN'),
bindCredentials: getEnvValue('LDAP_BIND_CREDENTIALS'),
searchBase: getEnvValue('LDAP_SEARCH_BASE'),
searchFilter: getEnvValue('LDAP_SEARCH_FILTER'),
},
passReqToCallback: true,
};
callback(null, options);
}
);
Any thoughts would greatly appreciated.
Gina
After many many hours, the answer was simpler than expected:
LDAP_BIND_DN = mydomain\ldapadmin
Gina
Related
There are two Active Directory (LDAP Servers). Following are the users which belongs to their servers respectively.
Server user password
1- abc.pk user_abc#abc.pk ********
2- xyz.com.pk user_xyz#xyz.com.pk ********
I am authenticating the user in NodeJS with library (ActiveDirectory). Below is my code where I am authenticating user_xyz#xyz.com.pk from its respective server.
const ActiveDirectory = require('activedirectory');
var ad = new ActiveDirectory({
"url": "ldap://xyz.com.pk",
"baseDN": "DC=xyz,DC=com,DC=pk"
});
ad.authenticate(username, password, function(err, auth) {
console.log('auth function called with username: '+username);
if (err) {
console.log('auth function called and with following err '+JSON.stringify(err));
return;
}
if (auth) {
console.log('Authenticated from Active directory!');
});
it works fine. Same works fine if I authenticate user_abc#abc.pk from server 1 by updating the url and baseDN.
var ad = new ActiveDirectory({
"url": "ldap://abc.pk",
"baseDN": "DC=abc,DC=pk"
});
Server abc.pk has Trust Relations with Server xyz.com.pk. Means I have to authenticate the user user_abc#abc.pk from the Server xyz.com.pk . using the following configurations.
var ad = new ActiveDirectory({
"url": "ldap://xyz.com.pk",
"baseDN": "DC=xyz,DC=com,DC=pk"
});
but now facing the error of invalid credentials. This is the exact error I am facing {"lde_message":"80090308: LdapErr: DSID-0C090453, comment: AcceptSecurityContext error, data 52e, v3839\u0000","lde_dn":null}
If I authenticate the user_abc#abc.pk from xyz.com.pk Server with Active Directory Explorer it works fine.
Active Directory Explorer image
It would be a great help if someone could give me a solution.
Thanks
I solved the problem by checking the following 2 things:
1.-The configuration must be separated in the baseDN part:
var config = {
url: 'ldap://aaa.bbb.ccc.ddd',
baseDN: 'DC=aaa,DC=bbb,DC=ccc,DC=ddd'
};
2.-It seems the problem is not from code https://community.arubanetworks.com/community-home/digestviewer/viewthread?MID=40296#:~:text=%22AcceptSecurityContext%20error%2C%20data%2052e%22,instead%20of%20just%20the%20username.
According to the post, sometimes the domain name server may be required for authentication. It would be necessary to verify if it works with "username" or "username#aaa.bbb.ccc.ddd" or "aaa.bbb.ccc.ddd\username" depending on how the user is registered.
I hope my experience can be of use. Cheers
I'm struggling to solve an issue that I got on trying to login via Single Sign On from Microsoft Azure using Cypress. It is possible to do it without using the Client_Secret? How can I do it?
I've been spending more than a week trying to solve this situation...
I'm a junior on this, so if you could help-me I would be very grateful.
Thanks a lot,
Yes, you can. Navigate to your AD App in the portal -> Authentication -> set Allow public client flows to Yes like below.
Then in the blog, in step Cypress utility for mimicking react-adal, it uses the client credential flow, there is a comment post by #Bryce Kolton under the blog, he uses the ROPC flow, in this flow, you could use it without Client_Secret via a public client App as you changed above(Allow public client flows), just refer to it.
/* eslint-disable no-underscore-dangle */
import { AuthenticationContext } from ‘react-adal’;
import { azTenantId, azClientId } from ‘../../server/config/environment’;
// Need to get data points from server’s environment, not src
const adalConfig = {
tenant: azTenantId,
clientId: azClientId,
cacheLocation: ‘localStorage’,
replyUrl: ‘/’,
endpoints: {
api: ”,
},
};
const authContext = new AuthenticationContext(adalConfig);
export default async function doLogin() {
// getCachedToken also does an expiration check so we know for sure the tokens are usable
if (
!authContext.getCachedToken(adalConfig.endpoints.api)
|| !authContext.getCachedToken(adalConfig.clientId)
) {
const response = await cy.request({
method: ‘POST’,
url:
‘https://login.microsoftonline.com/mercedesme.onmicrosoft.com/oauth2/token’,
// qs: { ‘api-version’: ‘1.0’ }, // uncomment if your consuming resource expects the ‘aud’ to have a prefix of ‘sn:’
headers: {
‘cache-control’: ‘no-cache’,
‘content-type’:
‘multipart/form-data; boundary=—-WebKitFormBoundary7MA4YWxkTrZu0gW’,
},
form: true,
body: {
grant_type: ‘password’,
response_type: ‘code’,
client_id: ‘[[yourappsclientid]]’,
username: ‘[[yourtestuzseremail]]’,
password: ‘[[yourtestuserpassword]]!’,
scope: ‘openid’,
resource: ‘[[some-resource-id]]’,
},
});
// Store the token and data in the location where adal expects it
authContext._saveItem(authContext.CONSTANTS.STORAGE.IDTOKEN, response.body.access_token);
authContext._saveItem(
authContext.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + adalConfig.endpoints.api,
response.body.access_token,
);
authContext._saveItem(
authContext.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + adalConfig.clientId,
response.body.access_token,
);
authContext._saveItem(
authContext.CONSTANTS.STORAGE.EXPIRATION_KEY + adalConfig.endpoints.api,
response.body.expires_on,
);
authContext._saveItem(
authContext.CONSTANTS.STORAGE.EXPIRATION_KEY + adalConfig.clientId,
response.body.expires_on,
);
authContext._saveItem(
authContext.CONSTANTS.STORAGE.TOKEN_KEYS,
[adalConfig.clientId].join(authContext.CONSTANTS.RESOURCE_DELIMETER)
+ authContext.CONSTANTS.RESOURCE_DELIMETER,
);
}
}
To use the ROPC flow successfully, make sure your scenario meets the requirements below, e.g. your user account is not MAF-enabled.
I'm trying to connect to & use Skype for Business API (UCWA) following this procedure, using a Node.js test script.
I've registered a test app in Azure AD and checked all permissions concerning Skype for Business Online.
I'm doing this (simplified):
var adal = require('adal-node');
var https = require('https');
var clientId = 'a5cbbd......cc4a1'; // = app ID
var clientSecret = 'IOSDk1......LJ6vE=' // test key from Azure AD
var context = new adal.AuthenticationContext('https://login.windows.net');
// 'Autodiscover' step
// (callRestAPI() makes an HTTPS request using https.request() and returns results as JSON)
callRestAPI('webdir.online.lync.com', 443, '/autodiscover/autodiscoverservice.svc/root', 'GET', null /* no specific headers */, function(err, res) {
if (err) { console.log(err); return err; }
// extract discovered domain (I get something like https://webdir1e.online.lync.com)
let regex = new RegExp('^(https?://[^/]*)', 'g');
let sfbDiscoveredDomain = regex.exec(response._links.user.href);
sfbDiscoveredDomain = sfbDiscoveredDomain[1];
// 'Acquire token' step
context.acquireTokenWithClientCredentials(sfbDiscoveredDomain, clientId, clientSecret, function(err, res) {
if (err) { console.log(err); return err; }
regex = new RegExp('^https?://([^/]*)', 'g');
let sfbHost = regex.exec(res.resource);
sfbHost = sfbHost[1]; // here I get something like 'webdir1e.online.lync.com'
// 'Resending an autodiscovery request with the bearer token' step
callRestApi(sfbHost, 443, '/autodiscover/autodiscoverservice.svc/root/oauth/user', 'GET', {'Authorization': 'Bearer '+res.accessToken}, function(err, res) {
if (err) { console.log(err); return err; }
console.log(res);
});
});
});
The last step (resending an autodiscovery request) always fails with error HTTP 403/Forbidden.
There is an additional interesting response header:
'x-ms-diagnostics': '28070;source="AM41E00EDG01.infra.lync.com";reason="Service does not allow a cross domain request from this origin."'
...but I still don't understand why this error occurs.
I've played with additional headers seen here and there in various code samples (X-Ms-Origin and Host), with no luck.
This issue (Service does not allow a cross domain request from this origin.) is mostly caused by the "Cross-Origin Resource Sharing (CORS)" and that the address which is requesting the access isn´t "whitelisted".
An Skype for Business Administrator can configure that via (more info's here) when the server is on premises (see StackOverflow question here):
$x = New-CsWebOrigin -Url "https://apps.contoso.com"
Set-CsWebServiceConfiguration -Identity "{YOUR_IDENTITY}" -CrossDomainAuthorizationList #{Add=$x}
However as your Skype for Business isn´t on premises (its online) I assume there is nothing you can do as this section is mostly controlled by the cloud admins from Microsoft.
However as UCWA is supported with Skype for Business online I assume there is something wrong on your side. Did you checked if the application is correctly registered as explained here? If yes a fiddler trace might be useful to see what caused that issue.
I am trying to develop a node application that would be able to access my Outlook.com mails.
I am trying to do it in a way it doens't require me to enter my credentials, the application will know them (user name and password). I am not too worried about storing them in the config of my application.
I am using simple-oauth2 but I keep getting an error. The following is the code that is trying to retrieve the Oauth token:
const credentials = {
client: {
id: this.appId,
secret: this.appSecret,
},
auth: {
tokenHost: "https://login.microsoftonline.com",
authorizePath: "common/oauth2/v2.0/authorize",
tokenPath: "common/oauth2/v2.0/token",
},
};
const oathClient = oauth2.create(credentials);
const tokenConfig = {
username: "zzz#outlook.com",
password: "xxxxx",
scope: "Mail.Read",
};
const result = await oathClient.ownerPassword.getToken(tokenConfig);
const token = oathClient.accessToken.create(result);
However when calling get token I get the following response:
"error": "invalid_grant",
"error_description": "AADSTS70000: The grant is not supported by this API version\r\nTrace ID: 91935472-5d7b-4210-9a56-341fbda12a00\r\nCorrelation ID: 6b075f4e-b649-493e-a87b-c74f0e427b47\r\nTimestamp: 2017-08-19 14:00:33Z",
"error_codes": [ 70000],
I have aded the application in apps.dev.microsoft.com
Added a platform (Web API) for it.
Added the "Mail.Read" permission on Microsoft Grah
And I am using the apikey and secret I generated there.
Googling looks like all the examples I find are to connect is using a client certificate. Is it possible to use the API using the API credentials?
If the only way is using certificates, is there a way I can use simple-oauth2 for that?
Ok, looks like I was using the wrong method.
Trying to access using the ClientCredentials module on simple-ouath2 and its workign now:
const tokenConfig = {
scope: "https://graph.microsoft.com/.default",
};
const result = await oathClient.clientCredentials.getToken(tokenConfig);
Using auth0, I'm following this tutorial about connecting a multi-tenant saas to Azure AD:
https://auth0.com/docs/tutorials/building-multi-tenant-saas-applications-with-azure-active-directory
But, since my case is a bit different, I need it to pass some parameters when the user logs in. For the other connections, I'm able to set options.authParams.state = "..." and this state is sent to my callbackURL.
But, using Azure AD connection, my state variable is not correct. It's empty when I receive the callback.
I'm including the new Azure AD button according to the tutorial:
lock.once('signup ready', function () {
var link = $('<div class="a0-zocial a0-icon a0-waad" href="#">'
+ '<span>Azure AD</span></div>');
link.on('click', function () {
lock.getClient().login({
connection: 'seedtec-onmicrosoft-com'
});
});
var iconList = $(this.$container).find('.a0-iconlist');
iconList.append(link);
});
And sending my state through options:
var options = {
container: 'root'
, callbackURL: 'http://.../LoginCallback.ashx'
, responseType: 'code'
, dict: 'pt'
, socialBigButtons: false
, authParams: {
state: state
, scope: 'openid profile'
, company_id: $scope.companyId
}
, mode: mode
, callbackOnLocationHash: true
};
lock.show(options);
Do you know what is wrong in that?
Thank you!
PS: I'm using angular libraries for auth0.
I actually found out the solution to this. It was quite simple, but it's not well documented by auth0.
When calling lock.getClient().login(...) I had to pass the authparams again like this:
lock.getClient().login({
connection: 'myconn-onmicrosoft-com'
, scope: 'openid profile'
, company_id: 'blah...'
, state: 'blah blah...'
});