SharePoint Custom Webservice - web-services

I have a Custom SharePoint webservice for performing certain actions. User credentials are passed via Soap Header. The credentials reach the webservice without any problem.
Issue:
The following code returns "Unauthorized Error" if I did not make the webservice call with user credentials.
WebService Method
[WebMethod(Description = "Test Credentials")]
[SoapDocumentMethod(Binding = "SPService")]
[SoapHeader("Authen")]
public string[] TestCredentials(string siteURL)
{
string[] credentials = new string[3];
using (SPSite site = new SPSite(siteURL))
{
using (SPWeb spW = site.OpenWeb())
{
credentials[0] = Authen.CallingUserName;
credentials[1] = Authen.CallingUserPwd;
credentials[2] = siteURL;
}
}
return credentials;
}
Client Code
SPService.SPService spS = new SPService.SPService();//Webservice class
SPService.UserAuth ua = new SPService.UserAuth(); //Soap Header class
ua.CallingUserName = UserName; // User name
ua.CallingUserPwd = Password; // Password for the Username
spS.UserAuthValue = ua; // assigning the credential to the SoapHeader.
//System.Net.NetworkCredential nc = new NetworkCredential(UName, pwd, Domain);
//spS.Credentials = new NetworkCredential(UName, pwd, Domain);
string[] str = new string[3];
str = spS.TestCredentials(txt_URL.Text,"Shared Documents");
When the Network credential is commented out I get the The request failed with HTTP status 401: Unauthorized. error. If the credential is used then the webservice returns the expected value.
Requirement of the Custom WebService is to use WS-Security to pass the Login credentials and use the same to login into the SharePoint site.
Some help would be useful. Kindly let me know if you need more detail regarding this.

The SPSite constructor will require authentication to intialise correctly as it is accessing Sharepoint. You can instantiate it using credentials you have constructed before hand in a similar manner to what is described here

Related

Aws Cognito: Secret hash with Java SDK (not Android) and ADMIN_NO_SRP_AUTH flow

i try to register a user in my amazon cognito user pool with username and password from my java backend but i always get the error:
Unable to verify secret hash for client
in the documentation i don't found any information how to pass the clientSecret in the register request and i don't like to create an (backend) app without a clientSecret.
My code looks like this
identityProvider = AWSCognitoIdentityProviderClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(awsCreds)).withRegion(Regions.EU_CENTRAL_1).build();
Map<String, String> authParameters = new HashMap<>();
authParameters.put("USERNAME", "username");
authParameters.put("PASSWORD", "password");
authParameters.put("SECRET_HASH", "secret copy and paste from the aws console"); // i read in a forum post, that this should work
AdminInitiateAuthRequest authRequest = new AdminInitiateAuthRequest();
authRequest.withAuthFlow(AuthFlowType.ADMIN_NO_SRP_AUTH);
authRequest.setAuthParameters(authParameters);
authRequest.setClientId("clientId");
authRequest.setUserPoolId("userPoolId");
AdminInitiateAuthResult authResponse = identityProvider.adminInitiateAuth(authRequest);
Thanks
Marcel
To register users you should use the SignUp API. The secret hash can be calculated as follows in Java:
public String calculateSecretHash(String userPoolclientId, String userPoolclientSecret, String userName) {
if (userPoolclientSecret == null) {
return null;
}
SecretKeySpec signingKey = new SecretKeySpec(
userPoolclientSecret.getBytes(StandardCharsets.UTF_8),
HMAC_SHA256_ALGORITHM);
try {
Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
mac.init(signingKey);
mac.update(userName.getBytes(StandardCharsets.UTF_8));
byte[] rawHmac = mac.doFinal(userPoolclientId.getBytes(StandardCharsets.UTF_8));
return Encoding.encodeBase64(rawHmac);
} catch (Exception e) {
throw new RuntimeException("Error while calculating ");
}
}
Can you please elaborate your use case of creating users from your backend instead of directly calling Amazon Cognito from your clients?
Edit: We have updated our documentation to include a section about how to compute the secret hash.
The following code works perfectly:
AdminInitiateAuthRequest adminInitiateAuthRequest = new AdminInitiateAuthRequest().withAuthFlow(AuthFlowType.ADMIN_NO_SRP_AUTH).withClientId("<ID of your client application>").withUserPoolId("<your user pool ID>")
.addAuthParametersEntry("USERNAME", "<your user>").addAuthParametersEntry("PASSWORD", "<your password for the user>");
AdminInitiateAuthResult adminInitiateAuth = identityProvider.adminInitiateAuth(adminInitiateAuthRequest);
System.out.println(adminInitiateAuth.getAuthenticationResult().getIdToken());

How to create Gmail Delegation with Service Account?

We use to create email delegates through Google Email Settings API, but after the deprecation of OAuth 1.0 we were no longer able to authenticate properly. After doing some research I think we should create a service account, delegate domain-wide access for that service account, then authenticate using it. However I can't seem to get it to work, all I receive from Google is 401 unauthorized. Does someone know what I am doing wrong? Here is most of the code, I'm using .Net/c# and I'm using Google Apps for business.
ServiceAccountCredential credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer("serviceAccountEmail")
{
Scopes = new[] { "https://apps-apis.google.com/a/feeds/emailsettings/2.0/ " },
User = "admin email string"
}.FromCertificate({X509 certificate from service account p12 file}));
credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Wait(-1);
GoogleMailSettingsService service = new GoogleMailSettingsService("domain name", "appname");
service.SetAuthenticationToken(credential.Token.AccessToken);
service.CreateDelegate("delegator", "delegate");
For those who may need this answer in the future, I was able to provide a solution through the following. For reference I am running a web app using MVC framework, but the solution could be tweaked for a console or GUI standalone app as well.
Basically, I was able to authenticate the GoogleMailSettingsService.Service.RequestFactory with a GOAuth2RequestFactory object.
For instance:
GoogleMailSettingsService service = new GoogleMailSettingsService("domain", "applicationName");
service.RequestFactory = new GOAuth2RequestFactory("service", "AppName", new OAuth2Parameters() { AccessToken = AuthorizationCodeWebApp.AuthResult.Credential.Token.AccessToken });
Now for the AuthorizationCodeWebApp.AuthResult I implemented the following:
public async Task<ActionResult> DelegationMenu(CancellationToken cancellationToken)
{
var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(cancellationToken);
if (result.Credential == null)
return new RedirectResult(result.RedirectUri); //Will redirect to login page for Google Admin to authenticate.
Session["AuthResult"] = result;
return View();
}
public class AppFlowMetadata : FlowMetadata
{
private static readonly IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "ClientId",
ClientSecret = "ClientSecret"
},
Scopes = new[] { "https://apps-apis.google.com/a/feeds/emailsettings/2.0/" },
DataStore = new FileDataStore("C:\\OAuth2.0Tokens")
});
public override string GetUserId(Controller controller)
{
var user = controller.Session["user"];
if (user == null)
{
user = Guid.NewGuid();
controller.Session["user"] = user;
}
return user.ToString();
}
public override IAuthorizationCodeFlow Flow
{
get { return flow; }
}
}
A service account isn't required for this action. The Email Settings API, within the Admin SDK, allows a Super Admin to set a delegation for an account within the domain without the need to impersonate the user via a service account.
Check out this section of the Developers site for more information on this API. You can also test this on the OAuth Playground and add delegates right from there.

Unable to authenticate in accessing Dynamic CRM Online Web Service

I need to utilize Dynamic CRM Data Service Endpoint exposed to get data from one of the methods.
Service(microsoft) account has access to this service.
I've tried authenticating to Discovery Service and Organization Service using sample code provided here [https://msdn.microsoft.com/en-us/library/hh675404.aspx] and succeed. However am not able to use same authentication to access data Service as I could find anyway to relate Data Service with the other two. Doing basic authentication using Network Credentials does not work.
I have downloaded the CSDL exposed and added that as service reference to my project, which created an class of web service which extends from DataServiceContext. Am trying to retrieve data of one of the methods using LinQ queries. It returs following error:
"The response payload is a not a valid response payload. Please make sure that the top level element is a valid Atom or JSON element or belongs to 'http://schemas.microsoft.com/ado/2007/08/dataservices' namespace." On capturing using fiddle I realized that on hitting data service URL it is redirected to sign in page 'login.microsoftonline.com/'
Can anybody suggest a way to authenticate the user to access Data Serivce?
Adding code:
//<snippetAuthenticateWithNoHelp1>
IServiceManagement<IDiscoveryService> serviceManagement =
ServiceConfigurationFactory.CreateManagement<IDiscoveryService>(
new Uri(_discoveryServiceAddress));
AuthenticationProviderType endpointType = serviceManagement.AuthenticationType;
// Set the credentials.
AuthenticationCredentials authCredentials = GetCredentials(serviceManagement, endpointType);
String organizationUri = String.Empty;
// Get the discovery service proxy.
using (DiscoveryServiceProxy discoveryProxy =
GetProxy<IDiscoveryService, DiscoveryServiceProxy>(serviceManagement, authCredentials))
{
// Obtain organization information from the Discovery service.
if (discoveryProxy != null)
{
// Obtain information about the organizations that the system user belongs to.
OrganizationDetailCollection orgs = DiscoverOrganizations(discoveryProxy);
// Obtains the Web address (Uri) of the target organization.
organizationUri = FindOrganization(_organizationUniqueName,
orgs.ToArray()).Endpoints[EndpointType.OrganizationService];
}
}
//</snippetAuthenticateWithNoHelp1>
if (!String.IsNullOrWhiteSpace(organizationUri))
{
//<snippetAuthenticateWithNoHelp3>
IServiceManagement<IOrganizationService> orgServiceManagement =
ServiceConfigurationFactory.CreateManagement<IOrganizationService>(
new Uri(organizationUri));
// Set the credentials.
AuthenticationCredentials credentials = GetCredentials(orgServiceManagement, endpointType);
// Get the organization service proxy.
using (OrganizationServiceProxy organizationProxy =
GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, credentials))
{
// This statement is required to enable early-bound type support.
organizationProxy.EnableProxyTypes();
// Now make an SDK call with the organization service proxy.
// Display information about the logged on user.
Guid userid = ((WhoAmIResponse)organizationProxy.Execute(
new WhoAmIRequest())).UserId;
SystemUser systemUser = organizationProxy.Retrieve("systemuser", userid,
new ColumnSet(new string[] { "firstname", "lastname" })).ToEntity<SystemUser>();
Console.WriteLine("Logged on user is {0} {1}.",
systemUser.FirstName, systemUser.LastName);
Uri x = new Uri("https://<MyOrgainzationName>.crm.dynamics.com/XRMServices/2011/OrganizationData.svc/");
MyOrgainzationContext saContext = new MyOrgainzationContext(x);
NetworkCredential nc = new NetworkCredential();
nc.UserName = "*****#microsoft.com";
nc.Password = "********";
saContext.Credentials = nc;
var query_where3 = from c in saContext.new_productSet
select new
{
ProductStatus = c.new_ProductStatus,
LineofBusiness = c.new_LineofBusiness
};
var temp = saContext.Entities;
foreach (var c in query_where3)
{
System.Console.WriteLine("ProductStatus: " +
c.ProductStatus +
"\t\t\t" +
"LineofBusiness: " +
c.LineofBusiness);
}
}
//</snippetAuthenticateWithNoHelp3>
}
MyOrganizationContext is the context class created on adding CSDL file exposed at service endpoints
Have a look at the CRM Web Api Preview: https://msdn.microsoft.com/en-us/dynamics/crm/webapipreview.aspx. You can call this endpoint from outside xRM and you can authenticate with OAuth 2.0.

Authenticate with MS Crm Web Service

I'm looking for a way to authenticate a user (given a username and password) via the Microsoft CRM 4.0 Web Services API. Ideally, I'd like to filter down a list of projects based on which ones the logged in user has access to. i may be able to figure out the second part but I can't find a way to authenticate the user. The way all of the cals are currently made in the web service is via:
MyWebServices.CrmService svc = new MyWebServices.CrmService();
MyWebServices.CrmAuthenticationToken token = new MyWebServices.CrmAuthenticationToken();
token.OrganizationName = "MyCRM";
token.AuthenticationType = 0;
svc.CrmAuthenticationTokenValue = token;
svc.PreAuthenticate = true;
svc.Credentials = System.Net.CredentialCache.DefaultCredentials;
svc.Credentials = new NetworkCredential("hj", "mypass", "mydomain");
Then calls can be made via the service. I guess I could potentially try to authenticate to CRM via the user's username/password but it feels wrong somehow.
If you are in an on-premise environment, you should be able to use the following code to get a valid CRM service that can be used to retrieve your projects.
public static Microsoft.Crm.SdkTypeProxy.CrmService GetCrmService(string crmServerUrl, string organizationName, System.Net.NetworkCredential networkCredential)
{
// Setup the Authentication Token
CrmAuthenticationToken crmAuthenticationToken = new CrmAuthenticationToken
{
OrganizationName = organizationName,
AuthenticationType = 0
};
var crmServiceUriBuilder = new UriBuilder(crmServerUrl) { Path = "//MSCRMServices//2007//CrmService.asmx" };
// Instantiate a CrmService
var crmService = new Microsoft.Crm.SdkTypeProxy.CrmService
{
Url = crmServiceUriBuilder.ToString(),
UseDefaultCredentials = false,
Credentials = networkCredential,
CrmAuthenticationTokenValue = crmAuthenticationToken
};
return crmService;
}

How do I connect to a CRM IFD web service?

I have taken the code from the SDK and made just one modification to set the authentication type but when I try to connect I get an "Unauthorized" error.
My code is:
// Set up the CRM Service.
CrmAuthenticationToken token = new CrmAuthenticationToken();
token.AuthenticationType = 2;
token.OrganizationName = "TESTCRM";
CrmService service = new CrmService();
service.Url = "https://testcrm.ifdtestsystem.com/MSCrmServices/2007/CrmService.asmx";
service.CrmAuthenticationTokenValue = token;
//service.Credentials = System.Net.CredentialCache.DefaultCredentials;
service.Credentials = new NetworkCredential("Bill", "Password");
// Create an account entity and assign data to some attributes.
account newAccount = new account();
newAccount.name = "Greg Bike Store";
newAccount.accountnumber = "123456";
newAccount.address1_postalcode = "98052";
newAccount.address1_city = "Redmond";
// Call the Create method to create an account.
Guid accountId = service.Create(newAccount);
When using SPLA (IFD) you need to also populate the token with a crmticket.The ticket can be retrieved by quering the CrmDiscoveryService.
This document contains a reasonable sample how to use CrmDiscoveryService to obtain a ticket and set up CrmService.
Note that Credentials property for the service will no longer be required as all authentication information will be inside the ticket.
Hope this helps