Skip to content

Commit

Permalink
add some calls
Browse files Browse the repository at this point in the history
  • Loading branch information
lvermeulen committed Jul 3, 2019
1 parent b298cf5 commit dcbfe35
Show file tree
Hide file tree
Showing 13 changed files with 352 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,4 @@ ASALocalRun/

# MFractors (Xamarin productivity tool) working folder
.mfractor/
/test/Keycloak.Net.Tests/appsettings.json
70 changes: 70 additions & 0 deletions Keycloak.Net.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29020.237
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{A56F65F6-B549-4FB3-9710-7E5D4AEB20F1}"
ProjectSection(SolutionItems) = preProject
build\build.ps1 = build\build.ps1
build\test.ps1 = build\test.ps1
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{04ECC844-41D5-4A2B-85F1-DA1E3B3C58B3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{46B1B298-8884-4FE7-831D-FBCA62E10A72}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
appveyor.yml = appveyor.yml
global.json = global.json
LICENSE = LICENSE
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Keycloak.Net", "src\Keycloak.Net\Keycloak.Net.csproj", "{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Keycloak.Net.Tests", "test\Keycloak.Net.Tests\Keycloak.Net.Tests.csproj", "{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Debug|x64.ActiveCfg = Debug|Any CPU
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Debug|x64.Build.0 = Debug|Any CPU
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Debug|x86.ActiveCfg = Debug|Any CPU
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Debug|x86.Build.0 = Debug|Any CPU
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Release|Any CPU.Build.0 = Release|Any CPU
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Release|x64.ActiveCfg = Release|Any CPU
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Release|x64.Build.0 = Release|Any CPU
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Release|x86.ActiveCfg = Release|Any CPU
{5A3C6B69-F05E-476A-AF73-FF2D6088DEF0}.Release|x86.Build.0 = Release|Any CPU
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}.Debug|x64.ActiveCfg = Debug|Any CPU
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}.Debug|x64.Build.0 = Debug|Any CPU
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}.Debug|x86.ActiveCfg = Debug|Any CPU
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}.Debug|x86.Build.0 = Debug|Any CPU
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}.Release|x64.ActiveCfg = Release|Any CPU
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}.Release|x64.Build.0 = Release|Any CPU
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}.Release|x86.ActiveCfg = Release|Any CPU
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{3614BF25-4947-47A7-9C7E-7E3A0BFED2AA} = {04ECC844-41D5-4A2B-85F1-DA1E3B3C58B3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B4842084-5CB2-44EE-8494-6E05D534809A}
EndGlobalSection
EndGlobal
44 changes: 44 additions & 0 deletions src/Keycloak.Net/Common/FlurlRequestExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;

namespace Keycloak.Net.Common
{
public static class FlurlRequestExtensions
{
private static async Task<string> GetAccessTokenAsync(string url, string realm, string userName, string password)
{
var result = await url
.AppendPathSegment($"/auth/realms/{realm}/protocol/openid-connect/token")
.WithHeader("Accept", "application/json")
.PostUrlEncodedAsync(new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", userName),
new KeyValuePair<string, string>("password", password),
new KeyValuePair<string, string>("client_id", "admin-cli")
})
.ReceiveJson();

string accessToken = result
.access_token.ToString();

return accessToken;
}

private static string GetAccessToken(string url, string realm, string userName, string password) => GetAccessTokenAsync(url, realm, userName, password).GetAwaiter().GetResult();

public static IFlurlRequest WithAuthentication(this IFlurlRequest request, Func<string> getToken, string url, string realm, string userName, string password)
{
if (getToken != null)
{
string token = getToken();
return request.WithOAuthBearerToken(token);
}

return request.WithOAuthBearerToken(GetAccessToken(url, realm, userName, password));
}
}
}
16 changes: 16 additions & 0 deletions src/Keycloak.Net/Keycloak.Net.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net452;netstandard1.4</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Flurl.Http" Version="2.4.2" />
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
</ItemGroup>

<ItemGroup>
<Folder Include="Root\" />
</ItemGroup>

</Project>
2 changes: 2 additions & 0 deletions src/Keycloak.Net/Keycloak.Net.csproj.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=users/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
56 changes: 56 additions & 0 deletions src/Keycloak.Net/KeycloakClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using Flurl;
using Flurl.Http;
using Flurl.Http.Configuration;
using Keycloak.Net.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace Keycloak.Net
{
public partial class KeycloakClient
{
private static readonly ISerializer s_serializer = new NewtonsoftJsonSerializer(new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
});

static KeycloakClient()
{
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
};
}

private readonly Url _url;
private readonly string _userName;
private readonly string _password;
private readonly Func<string> _getToken;

private KeycloakClient(string url)
{
_url = url;
}

public KeycloakClient(string url, string userName, string password)
: this(url)
{
_userName = userName;
_password = password;
}

public KeycloakClient(string url, Func<string> getToken)
: this(url)
{
_getToken = getToken;
}

private IFlurlRequest GetBaseUrl(string authenticationRealm) => new Url(_url)
.AppendPathSegment("/auth")
.ConfigureRequest(settings => settings.JsonSerializer = s_serializer)
.WithAuthentication(_getToken, _url, authenticationRealm, _userName, _password);
}
}
18 changes: 18 additions & 0 deletions src/Keycloak.Net/Models/Users/Access.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Newtonsoft.Json;

namespace Keycloak.Net.Models.Users
{
public class Access
{
[JsonProperty("manageGroupMembership")]
public bool ManageGroupMembership { get; set; }
[JsonProperty("view")]
public bool View { get; set; }
[JsonProperty("mapRoles")]
public bool MapRoles { get; set; }
[JsonProperty("impersonate")]
public bool Impersonate { get; set; }
[JsonProperty("manage")]
public bool Manage { get; set; }
}
}
35 changes: 35 additions & 0 deletions src/Keycloak.Net/Models/Users/User.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Collections.ObjectModel;
using Newtonsoft.Json;

namespace Keycloak.Net.Models.Users
{
public class User
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("createdTimestamp")]
public long CreatedTimestamp { get; set; }
[JsonProperty("username")]
public string UserName { get; set; }
[JsonProperty("enabled")]
public bool Enabled { get; set; }
[JsonProperty("totp")]
public bool Totp { get; set; }
[JsonProperty("emailVerified")]
public bool EmailVerified { get; set; }
[JsonProperty("firstName")]
public string FirstName { get; set; }
[JsonProperty("lastName")]
public string LastName { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("disableableCredentialTypes")]
public ReadOnlyCollection<string> DisableableCredentialTypes { get; set; }
[JsonProperty("requiredActions")]
public ReadOnlyCollection<string> RequiredActions { get; set; }
[JsonProperty("notBefore")]
public int NotBefore { get; set; }
[JsonProperty("access")]
public Access Access { get; set; }
}
}
31 changes: 31 additions & 0 deletions src/Keycloak.Net/Users/KeycloakClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Flurl.Http;
using Keycloak.Net.Models.Users;
using Newtonsoft.Json;

namespace Keycloak.Net
{
public partial class KeycloakClient
{
public async Task<IEnumerable<User>> GetUsersAsync(string realm)
{
string stringResult = await GetBaseUrl(realm)
.AppendPathSegment($"/admin/realms/{realm}/users")
.GetStringAsync();

var result = JsonConvert.DeserializeObject<IEnumerable<User>>(stringResult);
return result;
}

public async Task<int> GetUsersCountAsync(string realm)
{
string stringResult = await GetBaseUrl(realm)
.AppendPathSegment($"/admin/realms/{realm}/users/count")
.GetStringAsync();

int result = JsonConvert.DeserializeObject<int>(stringResult);
return result;
}
}
}
30 changes: 30 additions & 0 deletions test/Keycloak.Net.Tests/Keycloak.Net.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Flurl.Http" Version="2.4.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Keycloak.Net\Keycloak.Net.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
2 changes: 2 additions & 0 deletions test/Keycloak.Net.Tests/Keycloak.Net.Tests.csproj.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=users/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
24 changes: 24 additions & 0 deletions test/Keycloak.Net.Tests/KeycloakClientShould.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.IO;
using Microsoft.Extensions.Configuration;

namespace Keycloak.Net.Tests
{
public partial class KeycloakClientShould
{
private readonly KeycloakClient _client;

public KeycloakClientShould()
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.Build();

string url = configuration["url"];
string userName = configuration["userName"];
string password = configuration["password"];

_client = new KeycloakClient(url, userName, password);
}
}
}
23 changes: 23 additions & 0 deletions test/Keycloak.Net.Tests/Users/KeycloakClientShould.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Threading.Tasks;
using Xunit;

namespace Keycloak.Net.Tests
{
public partial class KeycloakClientShould
{
[Fact]
public async Task GetUsersAsync()
{
var result = await _client.GetUsersAsync("Insurance");
Assert.NotNull(result);
Assert.NotEmpty(result);
}

[Fact]
public async Task GetUsersCountAsync()
{
int result = await _client.GetUsersCountAsync("Insurance");
Assert.True(result >= 0);
}
}
}

0 comments on commit dcbfe35

Please sign in to comment.