Google Apps Email Audit API with 2 Legged OAuth - google-api-client

I'm currently trying to use the GData .net API
Here is the documentation I'm using http://code.google.com/googleapps/domain/audit/docs/1.0/audit_developers_guide_protocol.html#retrieving_all_mailbox_status
What I'm trying to do is to use 2 legged authentication to do this example
using System;
using Google.GData.Apps;
using Google.GData.Extensions.Apps;
...
MailMonitor monitor = new MailMonitor();
monitor.BeginDate = new DateTime(2009, 6, 15);
monitor.EndDate = new DateTime(2009, 6, 30, 23, 20, 0);
monitor.IncomingEmailMonitorLevel = MonitorLevel.FULL_MESSAGE;
monitor.OutgoingEmailMonitorLevel = MonitorLevel.HEADER_ONLY;
monitor.DraftMonitorLevel = MonitorLevel.FULL_MESSAGE;
monitor.ChatMonitorLevel = MonitorLevel.FULL_MESSAGE;
monitor.DestinationUserName = "namrata";
AuditService service = new AuditService("example.com", "example.com-auditapp-v1");
service.setUserCredentials("admin#example.com", "p#55w0rd");
MailMonitor monitorEntry = service.CreateMailMonitor("abhishek", monitor);
I've gotten as far as
var monitor = new MailMonitor
{
EndDate = DateTime.Now.AddDays(1),
IncomingEmailMonitorLevel = MonitorLevel.FULL_MESSAGE,
OutgoingEmailMonitorLevel = MonitorLevel.HEADER_ONLY,
DraftMonitorLevel = MonitorLevel.FULL_MESSAGE,
ChatMonitorLevel = MonitorLevel.FULL_MESSAGE,
DestinationUserName = "MYUSER"
};
var service = new AuditService("MYDOMAIN", "MYDOMAIN-auditapp-v1");
var requestFactory = new GOAuthRequestFactory("auditapi", "MYDOMAIN-auditapp-v1")
{
ConsumerKey = "MYDOMAIN",
ConsumerSecret = "MYKEY"
};
service.RequestFactory = requestFactory;
var monitorEntry = service.CreateMailMonitor("MYUSER", monitor);
This is trying to setup a monitor for any emails coming or going for one day. The response is Unknown authorization header (Error 401).
I got the key from following this guide http://code.google.com/googleapps/domain/articles/2lo-in-tasks-for-admins.html
I've no idea how to debug this, I can't find an example of 2 legged auth with the Email Audit API and I can't use wireshark because this is encrypted traffic.

What key did you use?
Remember API key is not the same as Consumer Secret. Consumer Secret is something which is unique to your domain.
You can find your consumer secret by going to your domain's Cpanel -> Advanced Settings -> Manage OAuth Domain Key. This is the secret your domain and Google share.
Here is a doc for your reference.

Related

Error protecting file using MIP SDK in service/daemon application

can someone help me with the following issue?
Scenario. I have a Windows Service running on an Azure VM. Service receives files, modifies them in some way (let's assume that it adds custom properties to Word files) and uses MIP SDK to protect them with template ID.
Issue. IFileHandler.SetProtection(string)+CommitAsync(...) fails with the following exception:
One or more errors occurred. ServiceDiscoveryHelper::GetServiceDetails - Cannot compute domain: license domains, identity, and cloud endpoint base URL are all empty, correlationId:[9add32ba-0cb7-4d31-b9d8-0000b7c694a4]
Other info
RemoveProtection()+CommitAsync(...) work fine.
I registered application in Azure Active Directory tenant.
Generated secret: <CLIENT_SECRET>.
Granted the following permissions
https://api.mipwebservice.com/InformationProtectionPolicy.Read.All
https://psor.o365syncservice.com/UnifiedPolicy.Tenant.Read
https://aadrm.com/Content.SuperUser
https://aadrm.com/Content.Writer
https://aadrm.com/Content.DelegatedWriter
https://aadrm.com/Content.DelegatedReader
IAuthDelegate implementation
uses ADAL to get access token using client_credentials authentication flow, because there is no interacting user (my app is service).
I do not whether I have to use identity parameter in client_credentials flow.
Main Code Snippet
MIP.Initialize(MipComponent.File);
var appInfo = new ApplicationInfo{
ApplicationId = ConfigurationManager.AppSettings["AppPrincipalId"],
ApplicationName = "App name",
ApplicationVersion = "1.0.0",
};
var authDelegate = new AuthDelegateImplementation(appInfo);
var fileProfileSettings = new FileProfileSettings("mip_data", false,
authDelegate, new ConsentDelegateImplementation(), appInfo, LogLevel.Trace);
var fileProfile = MIP.LoadFileProfileAsync(fileProfileSettings).Result;
var engineSettings = new FileEngineSettings("engine-id", "", "en-US"){
Identity = new Identity($"{appInfo.ApplicationId}#<TENANT-NAME>"){
DelegatedEmail = "<OWNER>#<TENANT-NAME>",
},
};
var fileEngine = fileProfile.AddEngineAsync(engineSettings).Result;
var fileHandler = fileEngine.CreateFileHandlerAsync("c:\\sample.docx", "0", true).Result;
fileHandler.SetProtection(new ProtectionDescriptor("<TEMPLATE-ID>"));
var success = fileHandler.CommitAsync("c:\\encrypted.docx").Result;
AuthDelegateImplementation
public string AcquireToken(Identity identity, string authority, string resource)
var authContext = new AuthenticationContext(authority + "/" + "<TENANT_ID>");
var clientCredential = new ClientCredential("<CLENT_ID>", "<CLIENT_SECRET>");
var res = await authContext.AcquireTokenAsync(resource, clientCredential);
return res.AccessToken;
}
ConsentDelegateImplementation
public class ConsentDelegateImplementation : IConsentDelegate {
public Consent GetUserConsent(string url) {
return Consent.Accept;
}
}
It seams that after testing MIP's local persistent state (see FileProfileSettings.Path property when UseInMemoryStorage is flase) was corrupted. After removing "mip_data" folder issue disappeared.

How to call SSRS Rest-Api V1.0 with custom security implemented (NOT SOAP)

I have implemented the custom security on my reporting services 2016 and it displays the login page once the URL for reporting services is typed on browser URL bar (either reports or reportserver)
I am using the following code to pass the Credentials
when i use the code WITHOUT my security extension it works and looks like this
ICredentials _executionCredentials;
CredentialCache myCache = new CredentialCache();
Uri reportServerUri = new Uri(ReportServerUrl);
myCache.Add(new Uri(reportServerUri.GetLeftPart(UriPartial.Authority)),
"NTLM", new NetworkCredential(MyUserName, MyUserPassword));
_executionCredentials = myCache;
when i use the code WITH the security extension it doesnt work and looks like this
ICredentials _executionCredentials;
CredentialCache myCache = new CredentialCache();
Uri reportServerUri = new Uri(ReportServerUrl);
myCache.Add(new Uri(reportServerUri.GetLeftPart(UriPartial.Authority)),
"Basic", new NetworkCredential(MyUserName, MyUserPassword));
_executionCredentials = myCache;
and i get an Exception saying "The response to this POST request did not contain a 'location' header. That is not supported by this client." when i actually use this credentials
Is "basic" the wrong option ?
Have anyone done this ?
Update 1
Well it turns out that my SSRS is expecting an Authorisation cookie
which i am unable to pass (according to fiddler, there is no cookie)
HttpWebRequest request;
request = (HttpWebRequest)HttpWebRequest.Create("http://mylocalcomputerwithRS/Reports_SQL2016/api/v1.0");
CookieContainer cookieJar = new CookieContainer();
request.CookieContainer = cookieJar;
Cookie authCookie = new Cookie("sqlAuthCookie", "username:password");
authCookie.Domain = ".mydomain.mylocalcomputerwithRS";
if (authCookie != null)
request.CookieContainer.Add(authCookie);
request.Timeout = -1;
HttpWebResponse myHttpWebResponse = (HttpWebResponse)request.GetResponse();
That's how I got it (SSRS 2017; api v2.0). I took the value for the "body" from Fiddler:
var handler = new HttpClientHandler();
var httpClient = new HttpClient(handler);
Assert.AreEqual(0, handler.CookieContainer.Count);
// Create a login form
var body = new Dictionary<string, string>()
{
{"__VIEWSTATE", "9cZYKBmLKR3EbLhJvaf1JI7LZ4cc0244Hpcpzt/2MsDy+ccwNaw9hswvzwepb4InPxvrgR0FJ/TpZWbLZGNEIuD/dmmqy0qXNm5/6VMn9eV+SBbdAhSupsEhmbuTTrg7sjtRig==" },
{"__VIEWSTATEGENERATOR", "480DEEB3"},
{ "__EVENTVALIDATION", "IS0IRlkvSTMCa7SfuB/lrh9f5TpFSB2wpqBZGzpoT/aKGsI5zSjooNO9QvxIh+QIvcbPFDOqTD7R0VDOH8CWkX4T4Fs29e6IL92qPik3euu5QpidxJB14t/WSqBywIMEWXy6lfVTsTWAkkMJRX8DX7OwIhSWZAEbWZUyJRSpXZK5k74jl4x85OZJ19hyfE9qwatskQ=="},
{"txtUserName", "User"},
{"txtPassword", "1"},
{"btnLogin","Войти"}
};
var content = new FormUrlEncodedContent(body);
// POST to login form
var response = await httpClient.PostAsync("http://127.0.0.1:777/ReportServer/Logon.aspx", content);
// Check the cookies created by server
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
var cookies = handler.CookieContainer.GetCookies(new Uri("http://127.0.0.1:777/ReportServer"));
Assert.AreEqual("sqlAuthCookie", cookies[0].Name);
// Make new request to secured resource
var myresponse = await httpClient.GetAsync("http://127.0.0.1:777/Reports/api/v2.0/Folders");
var stringContent = await myresponse.Content.ReadAsStringAsync();
Console.Write(stringContent);
As an alternative you can customize SSRS Custom Security Sample quite a bit.
I forked Microsoft's Custom Security Sample to do just what you are describing (needed the functionality at a client long ago and reimplemented as a shareable project on GitHub).
https://github.com/sonrai-LLC/ExtRSAuth
I created a YouTube walkthrough as well to show how one can extend and debug SSRS security with this ExtRSAuth SSRS security assembly https://www.youtube.com/watch?v=tnsWChwW7lA
TL; DR; just bypass the Microsoft example auth check in Login.aspx.cs and put your auth in Page_Load() or Page_Init() event of Login.aspx.cs- wherever you want to perform some custom logging check- and then immediately redirect auth'd user to their requested URI.

Docusign Soap API returns Unspecified Error

I have been trying to send a docusign envelope from Salesforce using the docusign SOAP API. I am using the CreateEnvelopeFromTemplates method of the Docusign API, I have a functional template created in my docusign sandbox, but everytime I send the request I get an Unspecified Error in my response. Below is the code the I am using
wwwDocusignNetApi30.EnvelopeInformation envelope = new wwwDocusignNetApi30.EnvelopeInformation();
envelope.Subject = 'Envelope Subject' ;
envelope.EmailBlurb = 'Email Blurb';
envelope.AccountId = '********-****-****-****-************';
//use custom field to store the id of the record that initiated the transaction
envelope.CustomFields = new wwwDocusignNetApi30.ArrayOfCustomField();
envelope.CustomFields.CustomField = new wwwDocusignNetApi30.CustomField[2];
wwwDocusignNetApi30.CustomField myCustomField = new wwwDocusignNetApi30.CustomField();
myCustomField.Name = 'DSFSSourceObjectId';
myCustomField.Value = '0012600000PQn9g';
myCustomField.Show = 'false';
myCustomField.Required = 'false';
myCustomField.CustomFieldType = 'Text';
envelope.CustomFields.CustomField.add(myCustomField);
wwwDocusignNetApi30.ArrayOfTemplateReference templateArray = new wwwDocusignNetApi30.ArrayOfTemplateReference();
templateArray.TemplateReference = new wwwDocusignNetApi30.TemplateReference[2];
wwwDocusignNetApi30.TemplateReference templat = new wwwDocusignNetApi30.TemplateReference();// TemplateReferences
templat.Template = '********-****-****-****-************';
templat.TemplateLocation = 'Server';
wwwDocusignNetApi30.ArrayOfRecipient1 recArray = new wwwDocusignNetApi30.ArrayOfRecipient1();
recArray.Recipient = new wwwDocusignNetApi30.Recipient[2];
wwwDocusignNetApi30.Recipient recipient = new wwwDocusignNetApi30.Recipient();
recipient.ID = 100987;
recipient.Type_x = 'Signer';
recipient.RoutingOrder = 2;
recipient.Email = 'example#example.com';
recipient.UserName = 'Test';
recArray.Recipient.add(recipient);
wwwDocusignNetApi30.TemplateReferenceRoleAssignment trra = new wwwDocusignNetApi30.TemplateReferenceRoleAssignment();
trra.RoleName='Signer 1';
trra.RecipientID = recipient.ID;
wwwDocusignNetApi30.ArrayOfTemplateReferenceRoleAssignment roleArray = new wwwDocusignNetApi30.ArrayOfTemplateReferenceRoleAssignment();
roleArray.RoleAssignment = new wwwDocusignNetApi30.TemplateReferenceRoleAssignment[1];
roleArray.RoleAssignment.add(trra);
templat.RoleAssignments = new wwwDocusignNetApi30.ArrayOfTemplateReferenceRoleAssignment();
templat.RoleAssignments = (roleArray);
templateArray.TemplateReference.add(templat);
String auth = '<DocuSignCredentials><Username>********-****-****-****-************</Username><Password>PASSWORD</Password><IntegratorKey>********-****-****-****-************</IntegratorKey></DocuSignCredentials>';
wwwDocusignNetApi30.APIServiceSoap service = new wwwDocusignNetApi30.APIServiceSoap();
service.inputHttpHeaders_x = new Map<String, String>();
service.inputHttpHeaders_x.put('X-DocuSign-Authentication',auth);
service.CreateEnvelopeFromTemplates(templateArray,recArray,envelope,true);
Below is the response I receive:
System.CalloutException: Web service callout failed: WebService returned a SOAP Fault: Unspecified_Error faultcode=soap:Server faultactor=https://demo.docusign.net/api/3.0/dsapi.asmx
Since the error message is vague, I am not able to debug the issue. Any help is appreciated.
I suggest that you start with a simpler request. Look at the recipes on github.com/docusign that start with sfdc
Get the simpler request working, then add features to get it to your needs.
One thing I did notice was that you are not giving a routing order of 1 to your only recipient. But that's probably OK.
I'm not sure that your template reference is correct since you should not be using composite templates for a simple template reference. Unfortunately I don't have a lot of experience with the soap api. HTH.

Pass a ADFS token to a custom STS service

I am testing a product that authenticates uses using a custom STS service. The way it used to work is, when a user hits the website using the browser, we issue a redirect to hit the STS service. the STS service authenticates the user by hitting AD and then issues a SAML token with some custom claims for the user. The website then hits the STS once again to get a ActAs token so we can communicate with the data service.
And I had a automation that would mimic this behavior and its working fine in production.
We are not modifying the STS to use ADFS to authenticate instead of hitting the AD directly. So now when I hit the website, the request gets redirected to a ADFS endpoint which authenticates the user and issues a token. Then we hit the custom STS service that would use the token to authenticate the user (instead of hitting AD), add custom claims and issue a SAML token for the user. We then generate a ActAs token using this to finally hit the data service.
I am trying to update my automation for this changed behavior. So what I am doing now is hit the ADFS service, obtain a token and pass the token to the STS service so it can issue me a SAML token.
I am quite an amateur when it comes to windows identity service so i am having hard time trying to get this work. I have successfully obtained the token (Bearer Token) from the ADFS but i cant figureout how to pass this token to my custom STS so it can issue me a SAML token.
Any help would be highly appreciated. Thanks!
here is the code i am using
public static SecurityToken GetSecurityToken()
{
var endPoint = new EndpointAddress(new Uri(#"ADFS endpoint"));
var msgBinding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);
msgBinding.Security.Message.EstablishSecurityContext = false;
msgBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
var factory = new WSTrustChannelFactory(msgBinding, endPoint);
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.SupportInteractive = true;
factory.Credentials.UserName.UserName = "user";
factory.Credentials.UserName.Password = "pwd";
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Bearer,
AppliesTo = new EndpointReference(#"custom STS endpoint")
};
return factory.CreateChannel().Issue(rst);
}
public static void GetUserClaimsFromSecurityTokenService(SecurityToken secToken)
{
var securityTokenManager = new SecurityTokenHandlerCollectionManager(string.Empty);
securityTokenManager[string.Empty] = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
var trustChannelFactory = new WSTrustChannelFactory(Binding, new EndpointAddress("custom STS endpoint"))
{
TrustVersion = TrustVersion.WSTrust13,
SecurityTokenHandlerCollectionManager = securityTokenManager,
};
var rst = new RequestSecurityToken(RequestTypes.Issue)
{
AppliesTo = new EndpointReference("website url"),
TokenType = SamlSecurityTokenHandler.Assertion
};
var channel = (WSTrustChannel)trustChannelFactory.CreateChannel();
channel.Open(TimeSpan.FromMinutes(15));
try
{
RequestSecurityTokenResponse rstr;
SecurityToken token = channel.Issue(rst, out rstr);
var genericToken = (GenericXmlSecurityToken)token;
var req = new SamlSecurityTokenRequirement();
var handler = new SamlSecurityTokenHandler(req)
{
Configuration = new SecurityTokenHandlerConfiguration()
};
var newToken = handler.ReadToken(new XmlNodeReader(genericToken.TokenXml));
}
finally
{
channel.Close();
}
}

Reusing ClaimsPrincipal to authenticate against sharepoint online

I have an Office 365 account (using the latest SharePoint 2013 instance)
I also have a simple .net web app that is authenticating against Office 365, I created an AppPrincipalId and added it using New-MsolServicePrincipal powershell commmand.
This works correctly. I launch the app (in debug), it redirects to 365 login, I login, it comes back to the app, and I have derived a class from ClaimsAuthenticationManager and overriden the Authenticate method.
I can now see the ClaimsPrincipal, with the relevant claims and identity etc.
Now I would like to re-use this identity to programmatically access SharePoint.
My questions:
a) Will SharePoint permit this Identity (seeing that it was issued by sts.windows.net)
b) How can I reconstruct a valid JWT (or use the existing one), and encapsulate this in a HttpRequest using authentication bearer.
The code I am using is below - this is coming back 401 not authorized.
Any help would be highly appreciated.
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated == true)
{
List<Claim> claims = null;
claims = (from item in incomingPrincipal.Claims
where item.Type.StartsWith("http", StringComparison.InvariantCultureIgnoreCase)
select item).ToList();
RNGCryptoServiceProvider cryptoProvider = new RNGCryptoServiceProvider();
byte[] keyForHmacSha256 = Convert.FromBase64String("Gs8Qc/mAF5seXcGHCUY/kUNELTE=");
// Create our JWT from the session security token
JWTSecurityToken jwt = new JWTSecurityToken
(
"https://sts.windows.net/myAppIdGuid/",
"00000003-0000-0ff1-ce00-000000000000", // sharepoint id
claims,
new SigningCredentials(
new InMemorySymmetricSecurityKey(keyForHmacSha256),
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
"http://www.w3.org/2001/04/xmlenc#sha256"),
DateTime.UtcNow,
DateTime.UtcNow.AddHours(1)
);
var validationParameters = new TokenValidationParameters()
{
AllowedAudience = "00000003-0000-0ff1-ce00-000000000000", // sharepoint id
ValidIssuer = "https://sts.windows.net/myAppIdGuid/", // d3cbe is my app
ValidateExpiration = true,
ValidateNotBefore = true,
ValidateIssuer = true,
ValidateSignature = true,
SigningToken = new BinarySecretSecurityToken(Convert.FromBase64String("mySecretKeyFromPowerShellCommand")),
};
JWTSecurityTokenHandler jwtHandler = new JWTSecurityTokenHandler();
var jwtOnWire = jwtHandler.WriteToken(jwt);
var claimPrincipal = jwtHandler.ValidateToken(jwtOnWire, validationParameters);
JWTSecurityToken parsedJwt = jwtHandler.ReadToken(jwtOnWire) as JWTSecurityToken;
HttpWebRequest endpointRequest =
(HttpWebRequest)HttpWebRequest.Create(
"https://MySharepointOnlineUrl/_api/web/lists");
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";
endpointRequest.Headers.Add("Authorization",
"Bearer " + parsedJwt.RawData);
HttpWebResponse endpointResponse =
(HttpWebResponse)endpointRequest.GetResponse();
}
}
If your scenario is about consuming SharePoint Online data from a remote web app, you probably want to use the OAuth flow. You can't generate the token yourself. Instead you ask for consent to the user to access certain scopes (resource + permission). These two links should help
http://msdn.microsoft.com/en-us/library/office/apps/jj687470(v=office.15).aspx
http://jomit.blogspot.com.ar/2013/03/authentication-and-authorization-with.html