clone a git repository with SSH and libgit2sharp - libgit2sharp

I'm trying to use the library "libgit2sharp" to clone a repository via a SSH key and... I can't find anything... I can clone it via "https" but what I'd like to do is using an SSH key. It's really unclear if it is supported or not.

As of now, there is a SSH implementation using libssh2 library. You can find it here LibGit2Sharp - SSH
You should add libgit2sharp-ssh dependency on you Project to be able to use it. It is available as a nugget: https://www.nuget.org/packages/LibGit2Sharp-SSH
Disclaimer: I haven't found a formal usage guide yet, what I know is from putting together bits and pieces from other user questions through LibGit2 forums.
From what I understood, you would need to create a new credential using eitherSshUserKeyCredentials OR SshAgentCredentials to authenticate using SSH, and pass it as part of CloneOptions.
In the sample code I use "git" as user, simply because the remote would be something like git#bitbucket.org:project/reponame.git , in which case "git" is the correct user, otherwise you will get an error saying
$exception {"username does not match previous request"}LibGit2Sharp.LibGit2SharpException
The code to clone a repo with SSH should be something like that:
public CloneOptions cloningSSHAuthentication(string username, string path_to_public_key_file, string path_to_private_key_file)
{
CloneOptions options = new CloneOptions();
SshUserKeyCredentials credentials = new SshUserKeyCredentials();
credentials.Username = username;
credentials.PublicKey = path_to_public_key_file;
credentials.PrivateKey = path_to_private_key_file;
credentials.Passphrase = "ssh_key_password";
options.CredentialsProvider = new LibGit2Sharp.Handlers.CredentialsHandler((url, usernameFromUrl, types) => credentials) ;
return options;
}
public CloneOptions cloneSSHAgent(string username){
CloneOptions options = new CloneOptions();
SshAgentCredentials credentials = new SshAgentCredentials();
credentials.Username = username;
var handler = new LibGit2Sharp.Handlers.CredentialsHandler((url, usernameFromUrl, types) => credentials);
options.CredentialsProvider = handler;
return options;
}
public void CloneRepo(string remotePath, string localPath){
CloneOptions options = cloningSSHAuthentication("git", "C:\\folder\\id_rsa.pub", "C:\\folder\\id_rsa");
Repository.Clone(remotePath, localPath, options);
}

Related

Configure Teams call forwarding policy via MS Graph API

TL;DR:
what's the MS Graph API for setting the teams call forwarding policy of an user?
Background:
Currently I'm trying to migrate a Lync/Skype-based .NET application to Teams.
The Teams related part is about setting the call forwarding preferences of a few specific users.
Those users have direct routing enabled, i.e. you can call a fixed PSTN/suffix number and the user will receive the call on his mobile. That mobile number is depending on the shift, so the programm is adapting it to whoever has the shift duty at that time.
What I've tried so far?
I can authenticate with the MS Graph API.
I know that there's TAC extension for this purpose ([1] and [2])
There's also a Powershell extension [3]
I'm not the first one to ask the question, but other threads usually got stuck [4]
The Call-Redirect is not what I want, as I'm not actively listening on those instances.
There's a github for Teams related scripts, but unfortunately without sources ...
I haven't yet reflected the Powershell extension
There is a promising user settings entry, where you can change shifts but not the call forwarding
Plan B?
invoke the powershell cmdlet, but that seems to be so 2000-ish
Update 2022-06-20
I'm starting to reflect the ps module. So API seems to be something like https://api.interfaces.records.teams.microsoft.com/Skype.VoiceGroup/userRoutingSettings/ + userId
The teams user id can be retrieved
Some parts of teams rely still on an older REST API (german only, sorry)
Update 2022-06-30
a POC which can be improved would look like this (... if I've packed into the usual AcquireTokenOnBehalfOf, then I'll add it as an answer ...)
Imports System.IO
Imports Microsoft.Identity.Client
Imports System.Globalization
Imports System.Net.Http
Imports System.Text
Imports System.Net.Http.Headers
Imports System.Net
Imports Newtonsoft.Json
Imports System.IdentityModel.Tokens.Jwt
Public Class LyncTest
Public Shared Sub Test()
Dim InstanceId As String = "https://login.microsoftonline.com/"
Dim RedirectURI As String = "https://login.microsoftonline.com/common/oauth2/nativeclient"
' Ids / Secrets and can be found on your Azure application page
Dim TenantId As String = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Dim AppId As String = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Dim secretVal As String = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Dim username As String = "xxxxxxx.xxxxxx#xxxxxxxxxxxx.com"
Dim password As String = "xxxxxxxxxxxx"
' Teams scope
Dim scope As String = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239/.default"
Dim httpClient = New HttpClient()
' start resource owner password credential flow
' see https://learn.microsoft.com/en-us/powershell/module/teams/connect-microsoftteams?view=teams-ps#example-4-connect-to-microsoftteams-using-accesstokens
Dim baseParam As String =
$"client_id={AppId}" &
$"&username={WebUtility.UrlEncode(username)}" &
$"&password={WebUtility.UrlEncode(password)}" &
$"&grant_type=password" &
$"&client_secret={WebUtility.UrlEncode(secretVal)}" &
$"&scope={scope}"
' get user_impersonation token
Dim tokenReq As New HttpRequestMessage(HttpMethod.Post, $"https://login.microsoftonline.com/{TenantId}/oauth2/v2.0/token") With {
.Content = New StringContent(baseParam, Encoding.UTF8, "application/x-www-form-urlencoded")
}
Dim TokenRes As HttpResponseMessage = httpClient.SendAsync(tokenReq).Result
Dim TokenObj As GraphToken = JsonConvert.DeserializeObject(Of GraphToken)(TokenRes.Content.ReadAsStringAsync.Result())
Dim JwtReader As New JwtSecurityTokenHandler
Dim JwtToken As JwtSecurityToken = JwtReader.ReadToken(TokenObj.AccessToken)
Dim UserOid As String = JwtToken.Payload("oid")
' set user calling routing
Dim RoutingURL As String = $"https://api.interfaces.records.teams.microsoft.com/Skype.VoiceGroup/userRoutingSettings/{UserOid}"
httpClient.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", TokenObj.AccessToken)
Dim RoutingJSON As String =
"{""sipUri"":""sip:andreas.beeker#kraiburg-tpe.com""," &
"""forwardingSettings"":{""isEnabled"":false,""forwardingType"":""Simultaneous"",""targetType"":""Unknown"",""target"":""""}," &
"""unansweredSettings"":{""isEnabled"":true,""targetType"":""SingleTarget"",""target"":""+491701234567"",""delay"":""00:00:20""}," &
"""callGroupDetails"":{""targets"":[],""order"":""Simultaneous""},""callGroupMembershipSettings"":{""callGroupMembershipDetails"":[]}}"
Dim RoutingReq As New HttpRequestMessage(HttpMethod.Post, RoutingURL) With {
.Content = New StringContent(RoutingJSON, Encoding.UTF8, "application/json")
}
Dim RoutingRes As HttpResponseMessage = httpClient.SendAsync(RoutingReq).Result
Console.WriteLine(If(RoutingRes.IsSuccessStatusCode, "success", "failed"))
End Sub
Public Class GraphToken
<JsonProperty(PropertyName:="access_token")>
Public Property AccessToken As String
<JsonProperty(PropertyName:="expires_in")>
Public Property ExpiresIn As Integer
<JsonProperty(PropertyName:="ext_expires_in")>
Public Property ExpiresInExt As Integer
<JsonProperty(PropertyName:="scope")>
Public Property Scope As String
<JsonProperty(PropertyName:="token_type")>
Public Property TokenType As String
End Class
End Class
There is no Graph API available for setting the teams call forwarding policy of an user.
Any user policy/tenant configuration are only exposed through PowerShell or admin portal now.
If you just want to change the forwarding status in Teams without catching callId and transferring individual calls, there is a simpler way by using PowerShell:
Install PowerShell module for M$Teams
https://www.powershellgallery.com/packages/MicrosoftTeams straight to PowerShell, for example by using
Install-Module -Name MicrosoftTeams -RequiredVersion 4.6.0 -AllowClobber
Assuming that you have permission set up forwarding by using Set-CsUserCallingSettings command, for example
Set-CsUserCallingSettings -Identity user#email.com -IsUnansweredEnabled $FALSE
Set-CsUserCallingSettings -Identity user#email.com -IsForwardingEnabled $true -ForwardingType Immediate -ForwardingTargetType SingleTarget -ForwardingTarget "+123456789"
In theory, only the second line is necessary, but I've noticed that PowerShell throws an error if Voicemail is enabled
This will change the forwarding status for all calls incoming to the selected identity. Note, that the user can change it still in Teams GUI.

Azure DevOps Client Library - Download Earlier Repository Files

I am trying to download earlier repository versions (.csproj files) from the commit records that I am obtaining from the Azure DevOps NuGet client library. I want to do this so I can access the Assembly Version information in the .csproj file. The GetFile() function I am using to get the current version of the file works fine but I want to download the older versions of the file from the commit records.
This is the GetFile function.
public string GetFile(string projectName, string repoName, string fileName)
{
try
{
var items = ListItems(projectName, repoName);
var projectPath = items.FirstOrDefault(i => i.Path.Contains(fileName))?.Path ?? "";
GitHttpClient gitClient = GetGitHttpClient();
GitRepository repo = GetRepositoryAsync(projectName, repoName);
var stream = gitClient.GetItemTextAsync(repo.Id, projectPath).Result;
var reader = new StreamReader(stream);
return reader.ReadToEnd();
}
catch (Exception e)
{
return "";
}
}
And this function gets the commits.
public async Task<List<GitCommitRef>> GetCommitsAsync(string projectName, string repoName)
{
var client = GetGitHttpClient();
var repo = GetRepositoryAsync(projectName, repoName);
var gitQueryCommitsCriteria = new GitQueryCommitsCriteria();
return await client.GetCommitsAsync(repo.Id, gitQueryCommitsCriteria);
}
Now I want to download each version of the .csproj that relates to each of these commits.
Any help anyone can give me with this would be greatly appreciated.
Kind regards, Stuart
The GetFile() function I am using to get the current version of the
file works fine but I want to download the older versions of the file
from the commit records.
I think you're in the right direction. I once used Azure Devops Rest Api Items-Get to get content of one specific version of file successfully with the help of versionDescriptor parameter.
https://dev.azure.com/MyOrgName/MyProjectName/_apis/git/repositories/MyReposName/Items?path=/README.md&versionDescriptor%5BversionOptions%5D=0&versionDescriptor%5BversionType%5D=2&versionDescriptor%5Bversion%5D={Commit ID}&download=true&resolveLfs=true&%24format=octetStream&api-version=5.0-preview.1
Since functions available in client library are corresponding to that in Rest Api, so client library must have corresponding parameters to do that.
And here's what I found:
Most of the overloads of gitClient.GetItemTextAsync() functions have GitVersionDescriptor versionDescriptor = null as input, and I think this is what you need.
Hope it makes some help.

How to create GoogleCredential object referencing the service account json file in Dataflow?

I have written a pipeline to extract G suite activity logs by referring the G suite java-quickstart where the code reads client_secret.json file as below,
InputStream in = new FileInputStream("D://mypath/client_secret.json");
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
Pipeline runs as expected in local(runner=DirectRunner) but the same code fails with java.io.FileNotFoundException expection when executed on cloud(runner=DataflowRunner)
I understand local path is invalid when executed on cloud. Any suggestion here?
Updated:
I have modified the code as below and I am able to read the client_secrets.json file
InputStream in =
Activities.class.getResourceAsStream("client_secret.json");
Actual problem is in creating the credential object
private static java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"),
".credentials/admin-reports_v1-java-quickstart");
private static final List<String> SCOPES = Arrays.asList(ReportsScopes.ADMIN_REPORTS_AUDIT_READONLY);
static {
try {
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
}
}
public static Credential authorize() throws IOException {
// Load client secrets.
InputStream in =
Activities.class.getResourceAsStream("client_secret.json");
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,
clientSecrets, SCOPES).setDataStoreFactory(DATA_STORE_FACTORY).setAccessType("offline").build();
Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
System.out.println("Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
return credential;
}
Observations:
Local execution:
On initial execution, program attempts to open browser to authorize the request and stores the authenticated object in a file - "StoredCredential".
On further executions, the stored file is used to make API calls.
Running on cloud(DataFlowRunner):
When I check logs, dataflow tries to open a browser to authenticate the request and stops there.
What I need?
How to modify GoogleAuthorizationCodeFlow.Builder such that the credential object can be created while running as dataflow pipeline?
I have found a solution to create GoogleCredential object using the service account. Below is the code for it.
public static Credential authorize() throws IOException, GeneralSecurityException {
String emailAddress = "service_account.iam.gserviceaccount.com";
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(emailAddress)
.setServiceAccountPrivateKeyFromP12File(Activities.class.getResourceAsStream("MYFILE.p12"))
.setServiceAccountScopes(Collections.singleton(ReportsScopes.ADMIN_REPORTS_AUDIT_READONLY))
.setServiceAccountUser("USER_NAME")
.build();
return credential;
}
Can you try running the program multiple times locally. What I am wondering is, if the "StoredCredential" file is available, will it just work? Or will it try to load up the browser again?
If so, can you determine the proper place to store that file, and download a copy of it from GCS onto the Dataflow worker? There should be APIs to download GCS files bundled with the dataflow SDK jar. So you should be able to use those to download the credential file.

How to download files/subfolders from Git using libgit2sharp

From ASP.NET application I want to download specific files and subfolders that are present in Git remote repository using LibGit2Sharp.
For Example :
Main Remote Repository URL : https://github.com/macmillanhighered/TestApplication
Sub folder URL : https://github.com/macmillanhighered/TestApplication/tree/develop/Scripts/PRODUCTS
Instead of getting all files/folders i want to get specific folder only using libgit2sharp API.
I am using below sample code to do this, but it is not working. Please help me out as soon as possible
// Url of the remote repository to clone
string url = "https://github.com/macmillanhighered/TestApplication/tree/develop/Scripts/PRODUCTS";
// Location on the disk where the local repository should be cloned
string workingDirectory = "C:\\TestGit";
var credential = new UsernamePasswordCredentials() { Username = "nitin", Password = "test" };
CloneOptions cloneOptions = new CloneOptions();
cloneOptions.Credentials = credential;
// Perform the initial clone
string repoPath = Repository.Clone(url, workingDirectory, cloneOptions);
using (var repo = new Repository(repoPath))
{
// "origin" is the default name given by a Clone operation
// to the created remote
var remote = repo.Network.Remotes["origin"];
// Retrieve the changes from the remote repository
// (eg. new commits that have been pushed by other contributors)
Signature sign = new Signature("Test", "", DateTime.Now);
FetchOptions fetchOptions = new FetchOptions();
fetchOptions.Credentials = credential;
MergeOptions mergeOptions = new MergeOptions();
PullOptions pullOptions = new PullOptions();
pullOptions.FetchOptions = fetchOptions;
pullOptions.MergeOptions = mergeOptions;
repo.Network.Pull(sign, pullOptions);
}
I am getting below error
Request failed with status code: 404
I am getting below error
Request failed with status code: 404
Clone() expects an url pointing to a git repository, not a file or folder with it.
Something like this should work better: string url = "https://github.com/macmillanhighered/TestApplication"
Instead of getting all files/folders i want to get specific folder only using libgit2sharp API.
The Git protocol doesn't work like this. You should fetch the whole repository and then locally work with the selected files you're interested in.

Authenticating on TFS 2010

I'm having trouble authenticating as a specific user on MS Team Foundation Server. In older versions it would look like:
teamFoundationCredential = new System.Net.NetworkCredential("<USERNAME>", "<PASSWORD>", "<DOMAIN>");
TeamFoundationServer tfs = new TeamFoundationServer("http://mars:8080/", teamFoundationCredential);
Can some one tell me the equivilent for the 2010 version. So far I have:
ICredentialsProvider cred = null;
tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://asebeast.cpsc.ucalgar.ca:8080/tfs/DefualtCollection"));
tfs.EnsureAuthenticated();
Thanks
For TFS 2010, use the following:
TfsTeamProjectCollection collection = new TfsTeamProjectCollection(
new Uri("http://asebeast.cpsc.ucalgar.ca:8080/tfs/DefaultCollection",
new System.Net.NetworkCredential("domain_name\\user_name", "pwd"));
collection.EnsureAuthenticated();
I've been having the same problem. The above solution doesn't work for me and really can't figure out why. I keep getting a cast exception.
Spent a day trying to figure this out - so thought I'd share my current workaround to the problem.
I've created my own internal class that implements ICredentialsProvider - as below:
private class MyCredentials : ICredentialsProvider
{
private NetworkCredential credentials;
#region ICredentialsProvider Members
public MyCredentials(string user, string domain, string password)
{
credentials = new NetworkCredential(user, password, domain);
}
public ICredentials GetCredentials(Uri uri, ICredentials failedCredentials)
{
return credentials;
}
public void NotifyCredentialsAuthenticated(Uri uri)
{
throw new NotImplementedException();
}
#endregion
}
I then instantiate this and pass it in as below:
MyCredentials credentials = new MyCredentials(UserName, Password, Domain);
TfsTeamProjectCollection configurationServer =
TfsTeamProjectCollectionFactory.GetTeamProjectCollection(
new Uri(tfsUri), credentials);
Note that I haven't implemented the NotifyCredentialsAuthenticated - not sure what this actually does, so left the NotImplementedException in there so I could catch when its called, which so far hasn't happened. Now successfully connected to TFS.
I've had some problems connecting to our old TFS 2008 server using this method as well, but the thing that solved my case was really simple:
First I defined the TFS Url to be:
private const string Tfs2008Url = #"http://servername:8080/tfs/";
static readonly Uri Tfs2008Uri = new Uri(Tfs2008Url);
The path used in the URL is the one we use when connecting via VisualStudio, so I thought this had to be the same in API calls, but when I tried to use this with the following authentication, I got a TF31002 / 404 error:
var collection = new TfsTeamProjectCollection(Tfs2008Uri,new NetworkCredential("AdminUser","password","domain_name"));
collection.EnsureAuthenticated();
But when I changed the Url to the TFS root, it authenticated OK!
private const string Tfs2008Url = #"http://servername:8080/";
static readonly Uri Tfs2008Uri = new Uri(Tfs2008Url);
Don't know if that helped anyone, but it sure did the trick for me!
This has worked pretty good for me:
_tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(tfsUri);
_tfs.ClientCredentials = new TfsClientCredentials(new WindowsCredential(new NetworkCredential("myUserName", "qwerty_pwd", "myDomainName")));
_tfs.EnsureAuthenticated();

Resources