mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-18 17:23:27 +00:00
gsuite directory service implementation
This commit is contained in:
@@ -323,6 +323,17 @@ namespace Bit.Console
|
|||||||
{
|
{
|
||||||
config.GSuite.SecretFile = parameters["f"];
|
config.GSuite.SecretFile = parameters["f"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(parameters.ContainsKey("d"))
|
||||||
|
{
|
||||||
|
config.GSuite.Domain = parameters["d"];
|
||||||
|
config.GSuite.Customer = null;
|
||||||
|
}
|
||||||
|
else if(parameters.ContainsKey("c"))
|
||||||
|
{
|
||||||
|
config.GSuite.Customer = parameters["c"];
|
||||||
|
config.GSuite.Domain = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -442,6 +453,13 @@ namespace Bit.Console
|
|||||||
{
|
{
|
||||||
config.GSuite.SecretFile = input.Trim();
|
config.GSuite.SecretFile = input.Trim();
|
||||||
}
|
}
|
||||||
|
Con.Write("Domain [{0}]: ", config.GSuite.Domain);
|
||||||
|
input = Con.ReadLine();
|
||||||
|
if(!string.IsNullOrEmpty(input))
|
||||||
|
{
|
||||||
|
config.GSuite.Domain = input.Trim();
|
||||||
|
config.GSuite.Customer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,5 +3,7 @@
|
|||||||
public class GSuiteConfiguration
|
public class GSuiteConfiguration
|
||||||
{
|
{
|
||||||
public string SecretFile { get; set; } = "client_secret.json";
|
public string SecretFile { get; set; } = "client_secret.json";
|
||||||
|
public string Customer { get; set; }
|
||||||
|
public string Domain { get; set; } = "yourcompany.com";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,9 @@ using Google.Apis.Auth.OAuth2;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Google.Apis.Admin.Directory.directory_v1.Data;
|
||||||
|
using System.Threading;
|
||||||
|
using Google.Apis.Util.Store;
|
||||||
|
|
||||||
namespace Bit.Core.Services
|
namespace Bit.Core.Services
|
||||||
{
|
{
|
||||||
@@ -18,12 +21,28 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
private GSuiteDirectoryService()
|
private GSuiteDirectoryService()
|
||||||
{
|
{
|
||||||
GoogleCredential creds;
|
//GoogleCredential creds;
|
||||||
using(var stream = new FileStream(SettingsService.Instance.Server.GSuite.SecretFile, FileMode.Open))
|
UserCredential creds;
|
||||||
|
|
||||||
|
var secretFilePath = Path.Combine(Constants.BaseStoragePath, SettingsService.Instance.Server.GSuite.SecretFile);
|
||||||
|
using(var stream = new FileStream(secretFilePath, FileMode.Open, FileAccess.Read))
|
||||||
|
{
|
||||||
|
var scopes = new List<string>
|
||||||
{
|
{
|
||||||
creds = GoogleCredential.FromStream(stream).CreateScoped(
|
|
||||||
DirectoryService.Scope.AdminDirectoryUserReadonly,
|
DirectoryService.Scope.AdminDirectoryUserReadonly,
|
||||||
DirectoryService.Scope.AdminDirectoryGroupReadonly);
|
DirectoryService.Scope.AdminDirectoryGroupReadonly,
|
||||||
|
DirectoryService.Scope.AdminDirectoryGroupMemberReadonly
|
||||||
|
};
|
||||||
|
|
||||||
|
//creds = GoogleCredential.FromStream(stream).CreateScoped(scopes);
|
||||||
|
|
||||||
|
var credsPath = Path.Combine(Constants.BaseStoragePath, "gsuite_credentials");
|
||||||
|
creds = GoogleWebAuthorizationBroker.AuthorizeAsync(
|
||||||
|
GoogleClientSecrets.Load(stream).Secrets,
|
||||||
|
scopes,
|
||||||
|
"user",
|
||||||
|
CancellationToken.None,
|
||||||
|
new FileDataStore(credsPath, true)).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
_service = new DirectoryService(new BaseClientService.Initializer
|
_service = new DirectoryService(new BaseClientService.Initializer
|
||||||
@@ -80,12 +99,124 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
private async Task<List<GroupEntry>> GetGroupsAsync(bool force)
|
private async Task<List<GroupEntry>> GetGroupsAsync(bool force)
|
||||||
{
|
{
|
||||||
return new List<GroupEntry>();
|
var entries = new List<GroupEntry>();
|
||||||
|
|
||||||
|
var request = _service.Groups.List();
|
||||||
|
request.Domain = SettingsService.Instance.Server.GSuite.Domain;
|
||||||
|
request.Customer = SettingsService.Instance.Server.GSuite.Customer;
|
||||||
|
var groups = await request.ExecuteAsync();
|
||||||
|
|
||||||
|
if(groups.GroupsValue != null)
|
||||||
|
{
|
||||||
|
foreach(var group in groups.GroupsValue)
|
||||||
|
{
|
||||||
|
// TODO: Group filter?
|
||||||
|
|
||||||
|
var entry = await BuildGroupAsync(group);
|
||||||
|
entries.Add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async static Task<GroupEntry> BuildGroupAsync(Group group)
|
||||||
|
{
|
||||||
|
var entry = new GroupEntry
|
||||||
|
{
|
||||||
|
ReferenceId = group.Id,
|
||||||
|
ExternalId = group.Id,
|
||||||
|
Name = group.Name
|
||||||
|
};
|
||||||
|
|
||||||
|
var memberRequest = _service.Members.List(group.Id);
|
||||||
|
var members = await memberRequest.ExecuteAsync();
|
||||||
|
|
||||||
|
if(members.MembersValue != null)
|
||||||
|
{
|
||||||
|
foreach(var member in members.MembersValue)
|
||||||
|
{
|
||||||
|
if(!member.Role.Equals("member", StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
!member.Status.Equals("active", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(member.Type.Equals("user", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
entry.UserMemberExternalIds.Add(member.Id);
|
||||||
|
}
|
||||||
|
else if(member.Type.Equals("group", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
entry.GroupMemberReferenceIds.Add(member.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<UserEntry>> GetUsersAsync(bool force)
|
private async Task<List<UserEntry>> GetUsersAsync(bool force)
|
||||||
{
|
{
|
||||||
return new List<UserEntry>();
|
var entries = new List<UserEntry>();
|
||||||
|
|
||||||
|
var request = _service.Users.List();
|
||||||
|
request.Domain = SettingsService.Instance.Server.GSuite.Domain;
|
||||||
|
request.Customer = SettingsService.Instance.Server.GSuite.Customer;
|
||||||
|
request.Query = SettingsService.Instance.Sync.UserFilter;
|
||||||
|
var users = await request.ExecuteAsync();
|
||||||
|
|
||||||
|
if(users.UsersValue != null)
|
||||||
|
{
|
||||||
|
foreach(var user in users.UsersValue)
|
||||||
|
{
|
||||||
|
var entry = BuildUser(user, false);
|
||||||
|
if(entry != null)
|
||||||
|
{
|
||||||
|
entries.Add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var deletedRequest = _service.Users.List();
|
||||||
|
request.Domain = SettingsService.Instance.Server.GSuite.Domain;
|
||||||
|
request.Customer = SettingsService.Instance.Server.GSuite.Customer;
|
||||||
|
request.Query = SettingsService.Instance.Sync.UserFilter;
|
||||||
|
request.ShowDeleted = "true";
|
||||||
|
var deletedUsers = await request.ExecuteAsync();
|
||||||
|
|
||||||
|
if(deletedUsers.UsersValue != null)
|
||||||
|
{
|
||||||
|
foreach(var user in deletedUsers.UsersValue)
|
||||||
|
{
|
||||||
|
var entry = BuildUser(user, true);
|
||||||
|
if(entry != null)
|
||||||
|
{
|
||||||
|
entries.Add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserEntry BuildUser(User user, bool deleted)
|
||||||
|
{
|
||||||
|
var entry = new UserEntry
|
||||||
|
{
|
||||||
|
ReferenceId = user.Id,
|
||||||
|
ExternalId = user.Id,
|
||||||
|
Email = user.PrimaryEmail,
|
||||||
|
Disabled = user.Suspended.GetValueOrDefault(false),
|
||||||
|
Deleted = deleted
|
||||||
|
};
|
||||||
|
|
||||||
|
if(string.IsNullOrWhiteSpace(entry.Email) && !entry.Deleted)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user