Is OrganizationServiceProxy Connected? - dynamics-crm-2011

What is the best way to tell if an OrganizationServiceProxy has successfully connected to CRM?
I am using GetEnumerator() on AccountSet as this fails if not connected.
/* Tries to connect to CRM and return false if failure - credentials arguments */
public bool Connect(string username, string password, string uri)
{
try
{
var cred = new ClientCredentials();
cred.UserName.UserName = username;
cred.UserName.Password = password;
service = new OrganizationServiceProxy(new Uri(uri), null, cred, null);
service.EnableProxyTypes(); // Allow LINQ early bound queries
linq = new Context(service);
/* This is where I need help */
var e = linq.AccountSet.GetEnumerator(); // this fails if not connected
}
catch
{
return false;
}
return true;
}
Service and Linq are private fields.
Context is the serviceContextName in crmsvcutil.exe.
I am in the habit of using the name "linq" for the Context object.
There must be a better way.

The simplest way is to execute a WhoAmIRequest, this because when you connect to CRM you need to provide valid credentials.
If the credentials are correct the WhoAmIRequest will return the current user GUID, if are not correct the request will fail.
So your code can be:
public bool Connect(string username, string password, string uri)
{
try
{
var cred = new ClientCredentials();
cred.UserName.UserName = username;
cred.UserName.Password = password;
service = new OrganizationServiceProxy(new Uri(uri), null, cred, null);
WhoAmIRequest request = new WhoAmIRequest();
WhoAmIResponse response = (WhoAmIResponse)service.Execute(request);
Guid userId = response.UserId;
}
catch
{
return false;
}
return true;
}

Related

OrganizationServiceProxy: No authentication error when wrong password is setup

I'm creating Organization service proxy object using following way:
[ThreadStatic]
public static OrganizationServiceProxy OrgServiceProxy;
// ...
sLog.DebugFormat("Get AuthenticationProviderType...");
AuthenticationProviderType _crmAuthType = this.GetServerType(parameters.DiscoveryUri);
sLog.DebugFormat("Get AuthenticationProviderType - DONE!");
// ...
sLog.Info("Perform metadata download (ServiceConfigurationFactory.CreateConfiguration)...");
IServiceConfiguration<IOrganizationService> _crmServiceConfiguration = ServiceConfigurationFactory.CreateConfiguration<IOrganizationService>(parameters.OrgServiceUri);
sLog.Info("Perform metadata download (ServiceConfigurationFactory.CreateConfiguration) - DONE");
// ...
// enable proxy types
var behavior = new ProxyTypesBehavior() as IEndpointBehavior;
behavior.ApplyClientBehavior(_crmServiceConfiguration.CurrentServiceEndpoint, null);
// ...
public OrganizationServiceProxy GetServiceProxy(ICRMConnectionParameters parameters)
{
// ...
ClientCredentials clientCreds = new ClientCredentials();
clientCreds.Windows.ClientCredential.UserName = parameters.UserName;
clientCreds.Windows.ClientCredential.Password = parameters.Password;
clientCreds.Windows.ClientCredential.Domain = parameters.Domain;
sLog.DebugFormat("Setup client proxy...");
OrgServiceProxy = new OrganizationServiceProxy(_crmServiceConfiguration, clientCreds);
sLog.DebugFormat("Setup client proxy - DONE.");
return OrgServiceProxy;
}
Just note here that AuthenticationProviderType and IServiceConfiguration are statically cached. This code above is part of class named CRMConnection.
I have one more abstract class (ProxyUser) which contains following property:
private CRMConnection conn;
// ...
protected OrganizationServiceProxy OrgServiceProxy
{
get
{
//return orgService;
return this.Conn.GetServiceProxy();
}
}
protected CRMConnection Conn
{
get
{
conn = conn ?? new CRMConnection();
return conn;
}
}
In another class that inherits ProxyUser I have method with following code:
ColumnSet columnSet = new ColumnSet();
ConditionExpression condition1 = new ConditionExpression("new_id", ConditionOperator.NotNull);
FilterExpression filter = new FilterExpression(LogicalOperator.And);
filter.AddCondition(condition1);
QueryExpression query = new QueryExpression()
{
EntityName = new_brand.EntityLogicalName,
ColumnSet = columnSet,
Criteria = filter,
NoLock = true
};
EntityCollection res = OrgServiceProxy.RetrieveMultiple(query);
And now we come to the point :)
If I setup correct parameters - organization service url, discovery service url, username, password and domain, everything works as expected. BUT, in case when wrong password is set, in line below, service is simply unresponsive. It doesn't happen anything.
EntityCollection res = OrgServiceProxy.RetrieveMultiple(query);
Of course, I'm expecting authentication failed error. Any suggestions what I'm missing here?
Thanks in advance!
I solved this problem with adding line below in GetServiceProxy method - when ClientCredentials are created:
clientCreds.SupportInteractive = false;
I figured this out after I moved whole logic in console app. When wrong password is set and app is in debug mode, I'm getting windows login prompt. Then I found this answer.

What does GenerateCorrelationId() and ValidateCorrelationId() do?

I see this code within a custom owin handler to do Oauth2. For example here: https://github.com/RockstarLabs/OwinOAuthProviders/blob/master/Owin.Security.Providers/Reddit/RedditAuthenticationHandler.cs
Can someone explain to me in plain English what these two methods do in the context of oauth2? It seems to be related to CSRF but not sure how.
When a redirect to an "OAuth 2" partner occurs there must be someway of correlating the eventual redirect back to your own application with the original redirect that you sent.
The way the Microsoft.Owin AuthenticationHandler accomplishes this:
generates a nonce of random bytes and retains it in a browser cookie
(GenerateCorrelationId)
encrypts this nonce and other information and your job is to pass this in a state query string parameter to the partner (recall that the partner's job is to return this value right back to your application after authenticating the user)
validates the nonce by decrypting the state query string parameter and verifying it matches the value in the cookie stored (ValidateCorrelationId)
Here is the source:
protected void GenerateCorrelationId(AuthenticationProperties properties)
{
if (properties == null)
{
throw new ArgumentNullException("properties");
}
string correlationKey = Constants.CorrelationPrefix +
BaseOptions.AuthenticationType;
var nonceBytes = new byte[32];
Random.GetBytes(nonceBytes);
string correlationId = TextEncodings.Base64Url.Encode(nonceBytes);
var cookieOptions = new CookieOptions
{
HttpOnly = true,
Secure = Request.IsSecure
};
properties.Dictionary[correlationKey] = correlationId;
Response.Cookies.Append(correlationKey, correlationId, cookieOptions);
}
protected bool ValidateCorrelationId(AuthenticationProperties properties,
ILogger logger)
{
if (properties == null)
{
throw new ArgumentNullException("properties");
}
string correlationKey = Constants.CorrelationPrefix +
BaseOptions.AuthenticationType;
string correlationCookie = Request.Cookies[correlationKey];
if (string.IsNullOrWhiteSpace(correlationCookie))
{
logger.WriteWarning("{0} cookie not found.", correlationKey);
return false;
}
var cookieOptions = new CookieOptions
{
HttpOnly = true,
Secure = Request.IsSecure
};
Response.Cookies.Delete(correlationKey, cookieOptions);
string correlationExtra;
if (!properties.Dictionary.TryGetValue(
correlationKey,
out correlationExtra))
{
logger.WriteWarning("{0} state property not found.", correlationKey);
return false;
}
properties.Dictionary.Remove(correlationKey);
if (!string.Equals(correlationCookie, correlationExtra, StringComparison.Ordinal))
{
logger.WriteWarning("{0} correlation cookie and state property mismatch.",
correlationKey);
return false;
}
return true;
}

Access ServiceStack session from ConnectionFilter

I am using SQL Server and database triggers to keep a data-level audit of all changes to the system. This audit includes the userID / name of whomever initiated a change. Ideally I'd like to do something like this in my AppHost.Configure method:
SqlServerDialect.Provider.UseUnicode = true;
var dbFactory = new OrmLiteConnectionFactory(ConnectionString, SqlServerDialect.Provider)
{
ConnectionFilter = (db =>
{
IAuthSession session = this.Request.GetSession();
if (session != null && !session.UserName.IsNullOrEmpty())
{
System.Data.IDbCommand cmd = db.CreateCommand();
cmd.CommandText = "declare #ci varbinary(128); select #ci = CAST(#Username as varbinary(128)); set context_info #ci";
System.Data.IDbDataParameter param = cmd.CreateParameter();
param.ParameterName = "Username";
param.DbType = System.Data.DbType.String;
//param.Value = session.UserName;
param.Value = session.UserAuthId;
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
}
return new ProfiledDbConnection(db, Profiler.Current);
}),
AutoDisposeConnection = true
};
container.Register<IDbConnectionFactory>(dbFactory);
Of course, this doesn't work because this.Request doesn't exist. Is there any way to access the current session from the ConnectionFilter or ExecFilter on an OrmLite connection?
The other approach I had started, doing an override of the Db property of Service, doesn't work any more because I've abstracted some activities into their own interfaced implementations to allow for mocks during testing. Each of these is passed a function that is expected to return the a DB connection. Example:
// Transaction processor
container.Register<ITransactionProcessor>(new MockTransactionProcessor(() => dbFactory.OpenDbConnection()));
So, how can I ensure that any DML executed has the (admittedly database-specific) context information needed for my database audit triggers?
The earlier multi tenant ServiceStack example shows how you can use the Request Context to store per-request items, e.g. you can populate the Request Context from a Global Request filter:
GlobalRequestFilters.Add((req, res, dto) =>
{
var session = req.GetSession();
if (session != null)
RequestContext.Instance.Items.Add(
"UserName", session.UserName);
});
And access it within your Connection Filter:
ConnectionFilter = (db =>
{
var userName = RequestContext.Instance.Items["UserName"] as string;
if (!userName.IsNullOrEmpty()) {
//...
}
}),
Another approach is to use a factory pattern, similar to how ServiceStack creates OrmLite db connections in the first place. Since all user-associated calls are made via the ServiceRunner, I piggy-back off of the session that's managed by ServiceStack.
public class TransactionProcessorFactory : ITransactionProcessorFactory
{
public ITransactionProcessor CreateTransactionProcessor(IDbConnection Db)
{
return new TransactionProcessor(Db);
}
}
public abstract MyBaseService : Service
{
private IDbConnection db;
public override System.Data.IDbConnection Db
{
get
{
if (this.db != null) return db;
this.db = this.TryResolve<IDbConnectionFactory>().OpenDbConnection();
IAuthSession session = this.Request.GetSession();
if (session != null && !session.UserName.IsNullOrEmpty())
{
IDbCommand cmd = db.CreateCommand();
cmd.CommandText = "declare #ci varbinary(128); select #ci = CAST(#Username as varbinary(128)); set context_info #ci";
IDbDataParameter param = cmd.CreateParameter();
param.ParameterName = "Username";
param.DbType = DbType.String;
//param.Value = session.UserName;
param.Value = session.UserAuthId;
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
}
return db;
}
}
private ITransactionProcessor tp = null;
public virtual ITransactionProcessor TransactionProcessor
{
get
{
if (this.tp != null) return tp;
var factory = this.TryResolve<ITransactionProcessorFactory>();
this.tp = factory.CreateTransactionProcessor(this.Db);
return tp;
}
}
}
For the sake of potential future ServiceStack users, another approach would be to use OrmLite's Global Insert/Update filters combined with Mythz's approach above to inject the necessary SQL only when DML actions are made. It isn't 100%, since there may be stored procs or manual SQL, but that's potentially handled via an IDbConnection extension method to manually set desired auditing information.

Manual force-authentication of a user without issuing an authentication request

I have a ServiceStack application that coexists with mvc5 in a single web project. The only purpose of the mvc5 part is to host a single controller action that receives a callback from janrain for javascript initiated social login. I could receive this callback in a SS service request, too, but then I don't know how I would do a redirect to the returnUrl that is passed through all the way from the javascript context. Even if I was able to figure this out, my question would still be the same.
Inside of the controller action, once I verify the janrain provided token resolves to a user in my system, I need to manually tell ServiceStack "hey trust me - this person is authorized".
All my searches lead to some code along the lines of the following snippet:
var authService = AppHostBase.Resolve<AuthService>();
authService.RequestContext = System.Web.HttpContext.Current.ToRequestContext();
var AuthResponse = authService.Authenticate(new Auth
{
provider = "credentials",
UserName = user.user_id,
Password = user.password,
RememberMe = true
});
My first problem here is that I store hashed passwords (I support social login as well as manual login), so I don't know the user's password (and I shouldn't).
My second problem is that this code seems to only work for SS 3.X and not 4.X. I requires a ServiceStack.ServiceInterface.dll that is mysteriously missing from 4.X.
Is there a short and precise way to manually authenticate a user with SS on the server side?
Thanks
EDIT:
So far this is what I am doing: (This is not final code - I have commented out some things I don't know what to do with):
public class UsernameOnlyAuthorizationService : Service
{
public object Post(UsernameOnlyLoginRequest request)
{
var authProvider = new UsernameOnlyAuthProvider();
authProvider.Authenticate(this, GetSession(), new Authenticate()
{
UserName = request.username,
Password = "NotRelevant",
RememberMe = true
});
return HttpResult.Redirect(request.returnUrl);
}
}
public class UsernameOnlyAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
var authRepo = authService.TryResolve<IAuthRepository>().AsUserAuthRepository(authService.GetResolver());
ReferScienceDataContext db = authService.TryResolve<ReferScienceDataContext>();
var session = authService.GetSession();
IUserAuth userAuth;
var user = db.Users.FirstOrDefault(u => u.Username == userName);
if (user != null)
{
//AssertNotLocked(userAuth);
//session.PopulateWith(userAuth);
session.Id = user.Id.ToString();
session.UserName = user.Username;
session.FirstName = user.FirstName;
session.LastName = user.LastName;
session.IsAuthenticated = true;
session.UserAuthId = user.Id.ToString(CultureInfo.InvariantCulture);
session.ProviderOAuthAccess = authRepo.GetUserAuthDetails(session.UserAuthId)
.ConvertAll(x => (IAuthTokens)x);
return true;
}
return false;
}
}
And from within my Janrain success callback code I call it so:
HostContext.ResolveService<UsernameOnlyAuthorizationService>().Post(new UsernameOnlyLoginRequest() {username = user.Username, returnUrl= returnUrl});
This seems to work nicely, however, I can't get it to remember my session across browser closes. I am hardcoding RememberMe = true - why is this not working?
I would do this by creating an internal service, which you can call from your MVC5 controller action, where you only require to pass the username of the user you have authenticated.
public class JanrainSuccessService : Service
{
public void CreateSessionFor(string username)
{
var repository = TryResolve<IAuthRepository>().AsUserAuthRepository(GetResolver());
var user = repository.GetUserAuthByUserName(username);
var session = GetSession();
session.PopulateWith(user);
session.IsAuthenticated = true;
session.UserAuthId = user.Id.ToString(CultureInfo.InvariantCulture);
session.ProviderOAuthAccess = repository.GetUserAuthDetails(session.UserAuthId).ConvertAll(x => (IAuthTokens)x);
}
}
The code in this method, is effectively the same could that is used by the CredentialsAuthProvider, but has the advantage of not requiring the password of the user. (See the TryAuthenticate method here for original code)
In your MVC5 controller action method you would need to call:
HostContext.ResolveService<JanrainSuccessService>().CreateSessionFor(user.user_id);
This assumes that you have a valid repository of users configured to match username's against.
You should update your code to be:
public class UsernameOnlyAuthorizationService : Service
{
public object Post(UsernameOnlyLoginRequest request)
{
var authProvider = new UsernameOnlyAuthProvider();
authProvider.Authenticate(this, GetSession(), new Authenticate()
{
UserName = request.username,
Password = "NotRelevant",
RememberMe = true
});
// Remember the session
base.Request.AddSessionOptions(SessionOptions.Permanent);
return HttpResult.Redirect(request.returnUrl);
}
}
public class UsernameOnlyAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
var authRepo = authService.TryResolve<IAuthRepository>().AsUserAuthRepository(authService.GetResolver());
ReferScienceDataContext db = authService.TryResolve<ReferScienceDataContext>();
var session = authService.GetSession();
var user = db.Users.FirstOrDefault(u => u.Username == userName);
if (user == null)
return false;
session.Id = user.Id.ToString();
session.UserName = user.Username;
session.FirstName = user.FirstName;
session.LastName = user.LastName;
session.IsAuthenticated = true;
session.UserAuthId = user.Id.ToString(CultureInfo.InvariantCulture);
session.ProviderOAuthAccess = authRepo.GetUserAuthDetails(session.UserAuthId).ConvertAll(x => (IAuthTokens)x);
return true;
}
}

LocalDB operations within impersonation context

Using the following method I impersonate as local administrator user (with elevated privileges) and pass the function that has to be executed within the impersonation context.
/// <summary>
/// Attemps to impersonate a given windows user and to run a given function within the impersonation context.
/// </summary>
/// <param name="userInformation">The user name and password for impersonation.</param>
/// <param name="functionAsImpersonatedUser">The function to be executed within the impersonation context.</param>
/// <returns>True if the operation was successful, false and an error message otherwise.</returns>
public static BooleanResult ExecuteAsImpersonatedUser(UserInformation userInformation, Func<BooleanResult> functionAsImpersonatedUser)
{
BooleanResult retval = new BooleanResult();
IntPtr returnedToken = IntPtr.Zero;
try
{
//Note: the logon type 'batch' seems to return a token with elevated privileges
bool success = NativeMethods.LogonUser(userInformation.Name, userInformation.Domain ?? ".", userInformation.Password, (int)LogonType.Batch, (int)LogonProvider.Default, out returnedToken);
if (false == success)
{
int ret = Marshal.GetLastWin32Error();
throw new Win32Exception(ret);
}
using (WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(returnedToken))
{
retval = functionAsImpersonatedUser();
}
}
catch (OutOfMemoryException o)
{
string logMessage = String.Format(CultureInfo.InvariantCulture, ErrorMessages.ErrorImpersonatingUser, userInformation.Domain, userInformation.Name, o.Message);
retval.ProcessGeneralException(o, logMessage);
}
catch (SecurityException s)
{
string logMessage = String.Format(CultureInfo.InvariantCulture, ErrorMessages.ErrorImpersonatingUser, userInformation.Domain, userInformation.Name, s.Message);
retval.ProcessGeneralException(s, logMessage);
}
catch (UnauthorizedAccessException u)
{
string logMessage = String.Format(CultureInfo.InvariantCulture, ErrorMessages.ErrorImpersonatingUser, userInformation.Domain, userInformation.Name, u.Message);
retval.ProcessGeneralException(u, logMessage);
}
catch (Win32Exception w)
{
string logMessage = String.Format(CultureInfo.InvariantCulture, ErrorMessages.ErrorImpersonatingUser, userInformation.Domain, userInformation.Name, w.Message);
retval.ProcessGeneralException(w, logMessage);
}
finally
{
if (NativeMethods.CloseHandle(returnedToken))
LogUtility.Instance.Write(String.Format(CultureInfo.InvariantCulture, TranslationStrings.CloseUserHandleSuccess, userInformation.Domain, userInformation.Name), 4);
else
LogUtility.Instance.Write(String.Format(CultureInfo.InvariantCulture, ErrorMessages.ErrorCloseUserHandle, userInformation.Domain, userInformation.Name), 2);
}
return retval;
}
No problems with that so far. After replacing LogonType.Interactive by LogonType.Batch even seems to return a user token with elevated privileges.
The function within the impersonation context creates a localDB instance if required, starts it and then tries to set up the database using insallation scripts and SMO. The first thing that occurs to me is that the instance owner is not the impersonated local administrator, why is that: do I have a wrong understanding of how impersonation or localDB works?
As only to be expected using a connecting like "Data Source=(localdb).[instanceName];Initial Catalog=[databaseName];Integrated Security=true" doesn’t work. That consequently results in a ConnectionFailureException.
But I still don’t get it, why is my impersonated local administrator not the owner of the instance (even if I create the instance within the impersonated context) , and thus not able to access the database?
The solution might be obvious, but I’m stuck.
Best Regards,
Stephan
Silly me!
By setting the verb, user name and password properties in the process start info it is possible to install the localDB instance and specify a different owner...
public static ConsoleOutputResult CreateInstance(UserInformation user)
{
if (user == null)
throw new ArgumentNullException("user");
ConsoleOutputResult retval = new ConsoleOutputResult();
try
{
ProcessStartInfo startInfo = new ProcessStartInfo(Path.Combine(localDBPath, "SqlLocalDB.exe"), String.Format(CultureInfo.InvariantCulture, "create {0}", instanceName))
{
CreateNoWindow = true,
Domain = user.Domain,
ErrorDialog = false,
LoadUserProfile = true,
Password = user.Password.ConvertToSecureString(),
RedirectStandardError = true,
RedirectStandardOutput = true,
UserName = user.Name,
UseShellExecute = false,
Verb = "runas"
};
using (Process process = Process.Start(startInfo))
{
process.WaitForExit();
retval.Error = process.StandardError.ReadToEnd();
retval.Output = process.StandardOutput.ReadToEnd();
retval.Success = String.IsNullOrEmpty(retval.Error);
if (retval.Success)
LogUtility.Instance.Write(retval.Output, 4);
}
}
catch (Exception e)
{
string logMessage = String.Format(CultureInfo.InvariantCulture, ErrorMessages.ErrorCreateLocalDB, e.Message);
retval.ProcessGeneralException(e, logMessage);
throw new SmartAppWizardException(logMessage, e.InnerException);
}
return retval;
}

Resources