2016-10-28 3 views
16

Я пытаюсь выяснить, как разрешить использование групп в Azure Active Directory B2C. Я могу авторизовать через пользователя, например:Авторизовать по группе в Azure Active Directory B2C

[Authorize(Users="Bill")] 

Однако это не очень эффективно, и я вижу очень мало случаев использования для этого. Альтернативным решением будет разрешение через роль. Однако по какой-то причине это не похоже на wowrk. Если я даю пользователю роль «Глобальный администратор», например, и попробуйте:

[Authorize(Roles="Global Admin")] 

Это не работает. Есть ли способ авторизации через группы или роли?

ответ

11

Это будет работать, однако вы должны написать пару строк кода в своей логике аутентификации, чтобы достичь того, что вы ищете.

Прежде всего, вы должны различать Roles и Groups в Azure AD (B2C).

User Role является очень специфичным и действителен только в пределах Azure AD (B2C). Роль определяет, какие разрешения внутри Azure AD есть у пользователя.

Group (или Security Group) определяет членство в группе пользователей, которое может подвергаться внешним приложениям. Внешние приложения могут моделировать Управление доступом на основе ролей наверх Группы безопасности. Да, я знаю, это может показаться немного запутанным, но это то, что есть.

Итак, ваш первый шаг - смоделировать Groups в Azure AD B2C - вам необходимо создать группы и вручную назначить пользователей этим группам. Вы можете сделать это в Azure Portal (https://portal.azure.com/):

enter image description here

Затем обратно в приложение, вам придется кодировать немного и попросить Azure AD B2C Graph API для членства пользователей после того, как пользователь успешно прошел проверку подлинности. Вы можете использовать this sample, чтобы получить представление о том, как получить членство в группах пользователей. Лучше всего выполнить этот код в одном из уведомлений OpenID (т. Е. SecurityTokenValidated) и добавить роль пользователей в ClaimsPrincipal.

Как только вы измените ClaimsPrincipal на наличие групп безопасности Azure AD и значений "Role Claim", вы сможете использовать атрибут Authrize с функцией Роли. Это действительно 5-6 строк кода.

Наконец, вы можете дать свой голос за эту функцию здесь: https://feedback.azure.com/forums/169401-azure-active-directory/suggestions/1-get-user-membership-groups-in-the-claims-with-ad-b, чтобы получить заявку на членство в группе, не запрашивая для этого Graph API.

+0

Возможно, вы можете показать эти 5-6 строк? Я пытаюсь собрать ответ на этот вопрос в течение нескольких дней, и у меня уже более 100 строк кода (и он еще не работает!). Если его так же просто, как 5 или 6 строк, чтобы подключить уведомление, запросите график для данных групп пользователей и добавьте группы в роли ClaimsPrincipal, я, очевидно, лаяю неправильное дерево. Я бы очень признателен за перенаправление! – reidLinden

25

Получение членства в группах для пользователей из Azure AD требует совсем немного, чем просто «пары строк кода», поэтому я решил поделиться тем, что в конечном итоге сработало для меня, чтобы сохранить других на несколько дней, потянув и забивая головой.

Давайте начнем с добавления следующих зависимостей в project.json:

"dependencies": { 
    ... 
    "Microsoft.IdentityModel.Clients.ActiveDirectory": "3.13.8", 
    "Microsoft.Azure.ActiveDirectory.GraphClient": "2.0.2" 
} 

Первый необходимо, как нам нужно, чтобы проверить подлинность нашего приложения для того, чтобы иметь возможность получить доступ к AAD Graph API. Вторая - это клиентская библиотека Graph API, которую мы будем использовать для запросов пользователей. Само собой разумеется, что версии действительны только на момент написания этой статьи и могут измениться в будущем.

Далее в методе Configure() класса запуска, возможно, прежде чем мы настроить аутентификацию OpenID Connect, мы создаем клиента API Graph следующим образом:

var authContext = new AuthenticationContext("https://login.microsoftonline.com/<your_directory_name>.onmicrosoft.com"); 
var clientCredential = new ClientCredential("<your_b2c_app_id>", "<your_b2c_secret_app_key>"); 
const string AAD_GRAPH_URI = "https://graph.windows.net"; 
var graphUri = new Uri(AAD_GRAPH_URI); 
var serviceRoot = new Uri(graphUri, "<your_directory_name>.onmicrosoft.com"); 
this.aadClient = new ActiveDirectoryClient(serviceRoot, async() => await AcquireGraphAPIAccessToken(AAD_GRAPH_URI, authContext, clientCredential)); 

ВНИМАНИЕ: НЕ жестко прописать секретный ключ приложения, но вместо этого сохраните его в надежном месте. Ну, ты уже это знал, да? :)

Асинхронный метод AcquireGraphAPIAccessToken(), который мы передали конструктору клиента AD, будет вызываться по мере необходимости, когда клиенту необходимо получить токен аутентификации. Вот что метод выглядит следующим образом:

private async Task<string> AcquireGraphAPIAccessToken(string graphAPIUrl, AuthenticationContext authContext, ClientCredential clientCredential) 
{ 
    AuthenticationResult result = null; 
    var retryCount = 0; 
    var retry = false; 

    do 
    { 
     retry = false; 
     try 
     { 
      // ADAL includes an in-memory cache, so this will only send a request if the cached token has expired 
      result = await authContext.AcquireTokenAsync(graphAPIUrl, clientCredential); 
     } 
     catch (AdalException ex) 
     { 
      if (ex.ErrorCode == "temporarily_unavailable") 
      { 
       retry = true; 
       retryCount++; 
       await Task.Delay(3000); 
      } 
     } 
    } while (retry && (retryCount < 3)); 

    if (result != null) 
    { 
     return result.AccessToken; 
    } 

    return null; 
} 

Обратите внимание, что он имеет встроенный механизм повтора для обработки переходных условий, которые вы можете захотеть адаптировать к потребностям вашего приложения.

Теперь, когда мы позаботились о проверке подлинности приложения и настройке клиента AD, мы можем перейти к событиям OpenIdConnect, чтобы, наконец, использовать его. Назад в методе Configure(), где мы обычно называем app.UseOpenIdConnectAuthentication() и создать экземпляр OpenIdConnectOptions, мы добавим обработчик для события OnTokenValidated:

new OpenIdConnectOptions() 
{ 
    ...   
    Events = new OpenIdConnectEvents() 
    { 
     ... 
     OnTokenValidated = SecurityTokenValidated 
    }, 
}; 

Событие вызывается при маркер доступа для signing- в пользователе было получено, подтверждено и установлена ​​идентификация пользователя. (Не путать с собственным токеном доступа приложения, необходимым для вызова API AAD Graph!) Это выглядит как хорошее место для запроса API-интерфейса Graph для членства в группах пользователей и добавления этих групп в личность в виде дополнительных требований:

private Task SecurityTokenValidated(TokenValidatedContext context) 
{ 
    return Task.Run(async() => 
    { 
     var oidClaim = context.SecurityToken.Claims.FirstOrDefault(c => c.Type == "oid"); 
     if (!string.IsNullOrWhiteSpace(oidClaim?.Value)) 
     { 
      var pagedCollection = await this.aadClient.Users.GetByObjectId(oidClaim.Value).MemberOf.ExecuteAsync(); 

      do 
      { 
       var directoryObjects = pagedCollection.CurrentPage.ToList(); 
       foreach (var directoryObject in directoryObjects) 
       { 
        var group = directoryObject as Group; 
        if (group != null) 
        { 
         ((ClaimsIdentity)context.Ticket.Principal.Identity).AddClaim(new Claim(ClaimTypes.Role, group.DisplayName, ClaimValueTypes.String)); 
        } 
       } 
       pagedCollection = pagedCollection.MorePagesAvailable ? await pagedCollection.GetNextPageAsync() : null; 
      } 
      while (pagedCollection != null); 
     } 
    }); 
} 

Используемый здесь тип заявки на роль, однако вы можете использовать пользовательский.

Сделав выше, если вы используете ClaimType.Role, все, что вам нужно сделать, это украсить свой класс контроллера или метод, как так:

[Authorize(Role = "Administrators")] 

То есть, конечно, при условии, у вас есть назначенная группа, сконфигурированная в B2C с отображаемым именем «Администраторы».

Если, однако, вы решили использовать нестандартный тип претензии, вам нужно определить политики авторизации на основе типа претензии, добавляя что-то вроде этого в ConfigureServices() метод, например:

services.AddAuthorization(options => options.AddPolicy("ADMIN_ONLY", policy => policy.RequireClaim("<your_custom_claim_type>", "Administrators"))); 

, а затем декорировать привилегированный класс контроллера или метод следующим образом:

[Authorize(Policy = "ADMIN_ONLY")] 

Хорошо, мы сделали еще? - Ну, не совсем.

Если вы запустили приложение и попытались войти в систему, вы получите исключение из API графики, требующего «Недостаточно привилегий для завершения операции». Это может быть не очевидно, но пока ваше приложение успешно аутентифицируется с помощью AD с помощью app_id и app_key, у него нет привилегий, необходимых для чтения сведений о пользователях из вашего AD. Чтобы предоставить такой доступ приложения к, я решил использовать Azure Active Directory Module for PowerShell

Следующий скрипт сделал трюк для меня:

$tenantGuid = "<your_tenant_GUID>" 
$appID = "<your_app_id>" 

$userVal = "<admin_user>@<your_AD>.onmicrosoft.com" 
$pass = "<admin password in clear text>" 
$Creds = New-Object System.Management.Automation.PsCredential($userVal, (ConvertTo-SecureString $pass -AsPlainText -Force)) 

Connect-MSOLSERVICE -Credential $Creds 
$msSP = Get-MsolServicePrincipal -AppPrincipalId $appID -TenantID $tenantGuid 

$objectId = $msSP.ObjectId 

Add-MsolRoleMember -RoleName "Company Administrator" -RoleMemberType ServicePrincipal -RoleMemberObjectId $objectId 

И теперь мы, наконец, сделали! Как это для «пары строк кода»? :)

+1

Это выдающаяся рецензия. Благодаря! – Dan

+0

Такая красота, такая ясность, много жука! – Molibar

+0

@ChristerBrannstrom Спасибо! - Я очень рад, что это помогло нескольким людям. –

2

я implmented это как написано, но по состоянию на май 2017 г. линии

((ClaimsIdentity)context.Ticket.Principal.Identity).AddClaim(new Claim(ClaimTypes.Role, group.DisplayName, ClaimValueTypes.String)); 

должен быть изменен на

((ClaimsIdentity)context.Ticket.Principal.Identity).AddClaim(new Claim(ClaimTypes.Role, group.DisplayName)); 

Чтобы заставить его работать с последними LIBS

Большой работа автору

Также, если у вас возникли проблемы с Connect-MsolService givin g плохое имя пользователя и пароль для обновления до последнего lib