i want to validate a set of credentials against the domain controller. e.g.:
Username: joel
Password: splotchy
Domain: STACKOVERFLOW
In .NET 3.5 and newer you can use PrincipalContext.ValidateCredentials(username, password).
Otherwise you're in trouble.
Following the code in the Microsoft Knowledge Base article How to validate user credentials on Microsoft operating systems, i get to the point where you call AcceptSecurityContext:
ss = AcceptSecurityContext(
#pAS._hcred, //[in]CredHandle structure
phContext, //[in,out]CtxtHandle structure
#InBuffDesc, //[in]SecBufferDesc structure
0, //[in]context requirement flags
SECURITY_NATIVE_DREP, //[in]target data representation
#pAS._hctxt, //[in,out]CtxtHandle strcture
#OutBuffDesc, //[in,out]SecBufferDesc structure
ContextAttributes, //[out]Context attribute flags
#Lifetime); //[out]Timestamp struture
except that the function fails with:
SEC_E_NO_AUTHENTICATING_AUTHORITY (0x80090311)
The function failed. No authority could be contacted for authentication. This could be due to the following conditions:
The domain name of the authenticating party is incorrect.
The domain is unavailable.
The trust relationship has failed.
This would be a useful error, except that i can validate the same credentials from .NET 3.5 using:
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domain))
{
valid = context.ValidateCredentials(username, password);
}
What could be happening that allows .NET to validate a set of credentials, while native code cannot?
Update: LogonUser also fails:
LogonUser("joel#stackoverflow.com", null, "splotchy",
LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_WINNT50, out token);
with
1311 - There are currently no logon servers available to service the logon request
Update Two: i've tried both the preferred Negotiate provider, as well as the Windows NT4 legacy "NTLM" provider
String package = "Negotiate"; //"NTLM"
QuerySecurityPackageInfo(package, [out] packageInfo);
...
AcquireCredentialsHandle(
null, //[in] principle
package, //[in] package
SECPKG_CRED_OUTBOUND, //[in] credential use
null, //[in] LogonID
pAuthIdentity, //[in] authData
null, //[in] GetKeyFn, not used and should be null
null, //[in] GetKeyArgument, not used and should be null
credHandle, //[out] CredHandle structure
expires); //[out] expiration TimeStamp structure
I presume that this is to solve the same problem as another question that you posted.
I kind of understand what you are trying to do now. Let me recap what you wrote on another post.
Username Password Domain Machine on domain? Validate as
======== ======== ================= ================== ==============
iboyd pass1 . No Local account
iboyd pass1 (empty) No Local account
iboyd pass1 stackoverflow.com No Domain account
iboyd pass1 . Yes Local account
iboyd pass1 (empty) Yes Domain account
iboyd pass1 stackoverflow.com Yes Domain account
You want to
Authenticate a user from a domain that your machine doesn't trust
Authenticate a user from a domain that your machine trusted
Authenticate a local user
You can achieve the first two cases by doing proper SSPI handshaking with the domain controller. The KB article that you are referring to in another question is doing loop back SSPI handshaking. It's not going to work in case number one because the client machine does not trust the domain that you are authenticating to. That should be why you are seeing SEC_E_NO_AUTHENTICATING_AUTHORITY.
To cut it short, if you want to do exactly the same thing as
PrincipalContext.ValidateCredentials(username, password);
you need to handle the local user differently from the domain user. For domain user, you need to call ldap_bind_s to bind to the domain controller using the given credentials. For local user, you need to use ADsOpenObject to bind to the WinnT://YourComputerName using the given credentials. This is what PrincipalContext.ValidateCredentials doing from what I read in the Reflector.
I don't see there is any equivalent one single native API doing the same thing for you.
Related
I am writing code to use docusign demo machine through Docusign.esign.dll . I have tried using Oauth process for connecting the docusign.
I have used the code similar to the code motioned in here.
https://github.com/docusign/docusign-csharp-client/blob/master/test/SdkTests/JwtAuthUnitTests.cs
But I have used my demo machine Integetor key and private key. But I am getting the below error. So do I need to change any setup in my demo machine? Or how do I get valid Integotor key.
I hope my PEM key is causing the issue. So let me know how to preparte that pEM KEy.
I just copied by Private key and created the PEM file using notepad application.
Please let me know do I miss any thing?
Error calling Login: {\r\n \"errorCode\": \"PARTNER_AUTHENTICATION_FAILED\",\r\n \"message\": \"The specified Integrator Key was not found or is disabled. An Integrator key was not specified.\"\r\n}"}
BY default, the API points to their live/production servers. After creating an instance of the ApiClient, set it to point at the demo server:
apiClient.RestClient.BaseUrl = new Uri("https://demo.docusign.net/restapi");
Edit: That was for legacy authentication. For OAuth, please check to make sure you're pointing to account-d.docusign.com (notice the -d).
I too found this to be the issue, in the response the bearer token is missing
<br/><br/>string host = "https://demo.docusign.net/restapi/v2";
// Note with or without v2 their supplied credentials work<br/>
string oauthBasePath = "account-d.docusign.com";<br/>
ApiClient apiClient = new ApiClient(host);<br/>
apiClient.ConfigureJwtAuthorizationFlow(integratorKey, userId, oauthBasePath, privateKeyFilename, expiresInHours);
When you use the credentials from the JwtAuthUnitTests - TestConfig all works
Steps followed should be:
Created demo machine
Created IK
Created Secret key
Created RSA pair key
Copy the private key in to notepad and save that file in location
Missing steps are:
Granting Consent either using User Consent or Admin Consent, check
Service Integration for details.
Configure Redirect URI in the Integrator Key, only needed for User
Consent via Authorization Code Grant
You can use Admin Consent only if you can claim email domain in DocuSign else you need to use User Consent. With User Consent, normally using Authorization Code Grant, you need to get consent with scopes of Impersonation Signature. Once you have user's consent, then you can get new AccessToken for that user using JWT.
Also you need to point to correct host for Demo and Prod,
account-d.docusign.com is required for Demo
account.docusign.com is required for Prod
Above host is used to get access token from DocuSign Account Server (/oauth/token), and you will use above host also for getting the baseUri from /oauth/userinfo endpoint. Other than these two call, I don't think you will use above host.
In response for /oauth/userinfo endpoint call, you will get base_uri and account_id like below
"account_id": "fe0b61a3-3b9b-cafe-b7be-4592af32aa9b"
"base_uri": "https://demo.docusign.net"
You will use above base_uri and account_id for any other API calls, like for creating envelope etc
<base_uri>/restapi/v2/accounts/<account_Id>/envelopes
I need to set up a two-step authentication chain with OpenAM. In the first step, the module requests a user certificate (which has to have been previously linked with an userID) and sends it to an external web service that will validate it and return the userID, which becomes the name of the Principal:
public Principal getPrincipal()
{
return new DataStorePrincipal(userID);
}
On the second step, the module asks the user to type in his userID and password. How do I make sure that the userID typed is the same as the one from step 1?
The modules are chained like this:
Certificate - REQUISITE
ID/Password - REQUIRED
The first module could save the 'userId' in the shared-state map, the 2nd module can read it from the shared-state map. You may look at existing auth-modules source as they provide support for 'shared-state'
You may also look at 'http://docs.forgerock.org/en/openam/10.1.0/admin-guide/index.html#configure-authn-chains'
I am integrating the login of a NodeJS app to the company's Active Directory using the Exchange Web Services endpoint. This way I can validate if the provided credentials (username and password) match with the Active Directory user's credentials.
So far I was able to successfully validate if a username/password pair is valid. What I couldn't find a solution for is getting the email address given a username.
I cannot query the Active Directory directly using LDAP since the NodeJS app will be hosted outside the company's network. An available option is to use the Exchange Web Services (2010) endpoint.
I am currently doing a ResolveNames operation http://msdn.microsoft.com/en-us/library/exchange/aa563518(v=exchg.150).aspx
The problem is that doing a Resolvenames with the username as the UnresolvedEntry value will return several Resolutions, for example if a username is john and there are also other johns in the directory, the Resolvenames query will return those as well.
I am looking for a way to get unambiguously the email address using EWS for a username (which corresponds to the valid credentials being used to query the EWS SOAP service).
Have never came across a direct method that gives email-address of logged in user, but you can do simple hack by creating a PostItem and then getting email-address by its PostItem.getFrom() method, something like :
PostItem postItem = new PostItem( service );
postItem.setBody( MessageBody.getMessageBodyFromText("Test for email-address " ) );
postItem.save();
postItem = PostItem.bind( service , postItem.getId() );
System.out.println( postItem.getFrom() );
postItem.delete( DeleteMode.HardDelete );
I have a JSF web application that uses cookies for automatic authentication without prompting for username & password. It uses a cookie with username and a random UUID, and uses a WebFilter for redirection.
When there are no cookies on the client side, the authentication is done through HttpServletRequest #login(String username, String password). Behind the scenes, this approach uses JAAS authentication, and uses a LDAP server behind.
My problem comes when my application recognizes the user through the cookies holding the userid and the UUID. In this situation,
the application doesn't know the password, so the method HttpServletRequest #login(String username, String password) cannot be used.
Should I ask the password to the LDAP server through JNDI? This doesn't seem to be possible at a first glance
Alternatively, I could store the password in my db. But this would mean duplication of information, and I don't like it.
I have seen around people simply setting the attribute "role" to the session, but this doesn't seem to be equivalent to a JAAS login. With "equivalent" I mean being able to use isUserInRole() and getUserPrincipal() methods.
So, the question is: how am I supposed to log in the user in this case? I hope that the question is clearer now.
EDIT
In order to let the code speak, I add a simplified version of the Managed Bean:
#ManagedBean
#SessionScoped
public class loginBean() {
private String username = null;
private String password = null;
private UUID uuid = null;
private boolean rememberMe = false;
public void doLogin() {
checkCookies(); // this method sets the property values after checking if
// username & uuid match the ones saved previously
if (username != null && uuid != null && rememberMe) {
// authenticate automatically. Here I don't know how to proceed, because
// I don't have the password, unless I have saved it in the application's db,
// duplicating it because it's already in LDAP server.
} else {
httpServletRequest.login(username, password); // this uses LDAP behind JAAS
createCookies(); // this method also saves username & uuid in the app's db
}
}
To do an actual container login in a custom way (in your case via an cookie and UUID instead of the password), you need to create your own login module.
The dedicated API in Java EE for this is JASPI/JASPIC (people can never quite agree on the name, complicating eg google queries).
A login module is in full control and does not have to authenticate with the ldap server (if your app can locally verify with 100% certainty that the cookie is valid). You probably do have to authorize the user (ask the ldap server for the roles/groups the user has).
As an alternative to JASPI/JASPIC you can also look at the proprietary login module mechanism that your server is using.
Using an LDAP entry for this case is equivalent to requesting that the directory server authenticate a connection using information provided by the application. In terms of LDAP, authenticate means that an existing LDAP session, that is, a connection to a directory server, has had its authentication state changed by a successful BIND request.
The web application should request appropriate information from the user to be authenticated and present this information to the directory server as a BIND request. The information required varies according to the authentication method used by the web application (LDAP client):
A simple BIND request requires a distinguished name and a password. This distinguished name and password should be transmitted to the directory server as a simple BIND request over a secure connection.
A SASL BIND request using a predefined SASL mechanism. The mechanisms vary per server and range from GSSAPI to PLAIN.
Upon receipt of the BIND request, the directory server will immediately change the authentication state of the connection to anonymous and process the BIND request. If the request can be successfully processed, the directory server responds to the LDAP with a BIND response including an integer result code of zero (0). This indicates that the distinguished name or username was able to successfully authenticate.
The web application should use some mechanism to maintain an authentication state and issue a BIND request to the directory server when the authentication state changes. This could be a session timeout, or some other mechanism. The method that is chosen should not be changeable by the user.
In summary, use the directory server to check authentication credentials and use the session framework to manage authentication state.
Edit:
Seems this was a controversial answer.
Using cookies does not handle the case of the browser having cookies disabled, and cookies are not necessary to maintain an authentication state when using sessions.
The session does not need the password, nor should it store any sensitive information like passwords in memory or sessions. The application should request the password when the authentication state expires (if ever) or the session expires (if ever).
Following the steps in this guide Using Azure ACS I have a working Azure ACS service configured & authenticating via Facebook, redirecting back to a website running on my development server.
On authentication success Azure ACS redirects back to my local development website and the IsAuthenticated flag is true, however I want to set the IsAuthenticated flag to true only if the email from the claim also exists in my local database, via a check/call to a custom MembershipProvider. If the email from the claim does not exist I want to redirect the client to a register page. Once registered and authenticated I would like to set the IsAuthenticated flag to true.
Currently once authenticated with Facebook and AzureACS, a user can request a secure page such as ViewAccountBalance.aspx, even though the account does not exist since out of the box IsAuthenticated flag to true. Interested to hear what others have done and what the best practice is.
You'll need to make a clear difference between authentication and authorization. Since the user logged in through Facebook it means he's authenticated (you know who he is and where he comes from).
Now, if you want to restrict parts of the application based on a specific condition you're actually talking about authorization. You might consider combining roles with a simple HttpModule. Example: your HttpModule could verify which page the user is browsing. If the user accesses a page that requires an active profile, you could use the following code:
public class RequiresProfileHttpModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AuthorizeRequest += new EventHandler(OnAuthorize);
}
private void OnAuthorize(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
if (app.Request.Url.ToString().Contains("bla") && !app.Context.User.IsInRole("UsersWithProfile"))
app.Response.Redirect("http://myapp/register.aspx");
}
}
The only thing you'll need to take care of is to update the principal to make sure it has the role UsersWithProfile if the user filled in his email address.
This is just one of many possible solutions. If you're using ASP.NET MVC you could achieve the same result with global ActionFilters. Or, you could also try to work with the IClaimsPrincipal (add a claim if the user has a profile).
Sandrino is correct. You can use role based authorization (or more generally, claim based authorization). By default, ACS simply returns the claims issued by the identity providers to your relying party. For Facebook, it will return an email claim. However, you can configure ACS to create additional rules. For example, you can map particular users to a role whose value is administrator. Then ACS will also return this role claim to your relying party. Then you can use Sandrino’s suggestion to use role based authorization. You can also refer to http://msdn.microsoft.com/en-us/library/windowsazure/gg185915.aspx for more information.