레이블이 Federated Authentication인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Federated Authentication인 게시물을 표시합니다. 모든 게시물 표시

2019년 1월 15일 화요일

사이트코어 Federated Authentication - Azure AD Workflow

이전 포스트에서는 Sitecore Federated Authentication을 사용하여 어떻게 Azure AD를 컨넥하고 유저정보를 인증하는지 그리고 어떻게 Customize한 코드를 적용하는지에 대하여 알아보았다.
이번에는 조금 더 디테일하게 접근하기위하여 필자는 유저의 이벤트 Request부터 시작하여 어떻게 Azure AD를 통하여 사이트코어 로그인을 성공하는지에 대하여 Workflow를 그려보았다.

순서부터 설명하자면,

  1. 유저는 Authentication 버튼이 생성되어진 로그인 페이지로 이동한다.
  2. 개발자의 의해 Customize되어진 사이트코어 Pipleline을 통하여 등록되어진 Microsoft Identity Server로 이동한다.
  3. MS 로그인페이지에서 유저 이메일 및 암호를 입력하고 로그인을 시도한다.
  4. MS Identity Server는 사이트코어 Pipeline를 통하여 받은 정보와 유저의 로그인 정보를 통하여 Azure AD로 이동한다.
  5. 유저정보가 Azure AD에 등록 또는 이용가능한 정보인지 검증한다.
  6. 검증이 확인되면 다시 MS Identity Server로 이동 후, 유정정보를 이용하여 Unique한 Token을 생성한다.
  7. 사이트코어는 생성된 Token과 함께 유저정보를 사이트코어 Pipeline에 보낸다.
  8. 사이트코어 Pipeline 및 설정에 등록된 Claims에 따라 유저정보 및 프로파일을 업데이트 한다.
  9. 유저는 사이트코어 Dashboard로 이동하여 사이트코어 CMS를 이용한다.




2018년 3월 26일 월요일

사이트코어 Federated Authentication 설정 및 사용하기

이번에는 사이트코어 9에서 소개된 Federated Authentication (FA)에 대하여 알아보도록 하자.

사이트코어는 .NET 프레임워크를 베이스로 사용하여 플랫폼을 윈도우 환경에 설치한다. 많은 유저 및 컴퍼니들은 CMS 사용자 로그인 프로세스를 Active Directory (AD)와 연동하여 사용하고 있으며, 대표적인 모듈로는 사이트코어에서 제공하는 Activie Direcotry 모듈이 있다.
이는 AD 도메인을 사이트코어 플랫폼과 연동시킨다. 기존 AD에 세팅되는 모든 유저의 Role 및 Permission을 똑같이 사이트코어에 적용하여 추가적인 어카운트 세팅없이 AD에 account가 존재하다면, 똑같이 유저정보로 사이트코어 CMS에 로그인할수있다.

사이트코어 9에서는 다양한 Authentication Provider를 제공한다. 가장 대포적인 예가 ADFS를 통하여 사이트코어를 로그인 하는 방법이다. 이는 기본적으로 AD On-Perm을 Azure Activie Directory Connect synchronization을 통하여 AzureAD와 연동을 하고, AzureAD에 Sync된 정보를 Microsoft의 Owin 미들웨어를 통하여 Token 기반의 OpenID Connect를 사용한다.

지금부터 Federated Authentication을 세팅 및 설정하는 방법에 대하여 알아보도록 하자.
  1. 사이트코어에서 FA를 사용하기 위해서는 "/wwwroot/App_Config/Include/Examples"폴더에 "Sitecore.Owin.Authentication.Enabler.config" 파일을 Include 폴더에 복사하고, "FederatedAuthentication.Enabled"을 "true"로 설정을 한다.
  2. 새로운 class를 만들어 IdentityProvider를 설정한다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    using Microsoft.Owin.Security.OpenIdConnect;
    using Owin;
    using Sitecore.Configuration;
    using Sitecore.Diagnostics;
    using Sitecore.Owin.Authentication.Configuration;
    using Sitecore.Owin.Authentication.Pipelines.IdentityProviders;
    using Sitecore.Owin.Authentication.Services;
    using System.Globalization;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using Microsoft.Owin.Security;
    
    namespace MyProject.Sitecore.Owin.AzureAD.Pipelines
    {
        public class CustomAzureADIdentityProvider : IdentityProvidersProcessor
        {
    
            public CustomAzureADIdentityProvider(FederatedAuthenticationConfiguration federatedAuthenticationConfiguration) : base(federatedAuthenticationConfiguration)
            {
            }
    
            protected override string IdentityProviderName => "AzureAd";
    
            protected override void ProcessCore(IdentityProvidersArgs args)
            {
                Assert.ArgumentNotNull(args, nameof(args));
    
                var identityProvider = this.GetIdentityProvider();
                var authenticationType = this.GetAuthenticationType();
    
                string aadInstance = Settings.GetSetting("AADInstance");
                string tenant = Settings.GetSetting("Tenant");
                string clientId = Settings.GetSetting("ClientId");
                string postLogoutRedirectURI = Settings.GetSetting("PostLogoutRedirectURI");
                string redirectURI = Settings.GetSetting("RedirectURI");
    
                string authority = string.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
    
                args.App.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
                {
                    Caption = identityProvider.Caption,
                    AuthenticationType = authenticationType,
                    AuthenticationMode = AuthenticationMode.Passive,
                    ClientId = clientId,
                    Authority = authority,
                    PostLogoutRedirectUri = postLogoutRedirectURI,
                    RedirectUri = redirectURI,
                    
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        SecurityTokenValidated = (context) =>
                        {
                            ClaimsIdentity identity = context.AuthenticationTicket.Identity;
                            foreach (Transformation current in identityProvider.Transformations)
                            {
                                current.Transform(identity, new TransformationContext(FederatedAuthenticationConfiguration, identityProvider));
                            }
                            return Task.FromResult(0);
                        }
                    }
                });
            }
        }
    }


  3. 새로운 만들어진 Provider를 MyProject.Owin.AzureADconfig 파일을 만들고, /Include 폴더에 적용시킨다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
        <sitecore role:require="Standalone or ContentDelivery or ContentManagement">
            <settings>
                <setting name="ClientId" value="{{Azure Web service의 클라이언트 아이디를 입력한다}}" />
                <setting name="AADInstance" value="https://login.microsoftonline.com/{0}" />
                <setting name="Tenant" value="{{Azure의 Tenant 정보를 입력한다.}}" />
                <setting name="PostLogoutRedirectURI" value="https://mysite/sitecore/login" />
                <setting name="RedirectURI" value="https://mysite/sitecore" />
            </settings>
            <pipelines>
                <owin.identityProviders help="Processors should derive from Sitecore.Owin.Authentication.Pipelines.IdentityProviders.IdentityProvidersProcessor">
                    <processor type="MyProject.Sitecore.Owin.AzureAD.Pipelines.CustomAzureADIdentityProvider, MyProject.Sitecore.Owin.AzureAD" resolve="true" />            </owin.identityProviders>
            </pipelines>
            <federatedAuthentication type="Sitecore.Owin.Authentication.Configuration.FederatedAuthenticationConfiguration, Sitecore.Owin.Authentication">
                <identityProvidersPerSites hint="list:AddIdentityProvidersPerSites">
                    <mapEntry name="0" type="Sitecore.Owin.Authentication.Collections.IdentityProvidersPerSitesMapEntry, Sitecore.Owin.Authentication">
                        <sites hint="list">
                            <site>shell</site>
                            <site>login</site>
                            <site>admin</site>
                            <site>service</site>
                            <site>modules_shell</site>
                            <site>modules_website</site>
                            <site>website</site>
                            <site>scheduler</site>
                            <site>system</site>
                            <site>publisher</site>
                        </sites>
                        <identityProviders hint="list:AddIdentityProvider">
                            <identityProvider ref="federatedAuthentication/identityProviders/identityProvider[@id='AzureAd']" />
                        </identityProviders>
                        <externalUserBuilder type="Sitecore.Owin.Authentication.Services.DefaultExternalUserBuilder, Sitecore.Owin.Authentication">
                            <param desc="isPersistentUser">true</param>
                        </externalUserBuilder>
                    </mapEntry>
                </identityProvidersPerSites>
                <identityProviders hint="list:AddIdentityProvider">
                    <identityProvider id="AzureAd" type="Sitecore.Owin.Authentication.Configuration.DefaultIdentityProvider, Sitecore.Owin.Authentication">
                        <param desc="name">$(id)</param>
                        <param desc="domainManager" type="Sitecore.Abstractions.BaseDomainManager" resolve="true" />
                        <caption>Sitecore Login by Microsoft ADFS</caption>
                        <icon>/sitecore/shell/themes/standard/Images/24x24/msazure.png</icon>
                        <domain>sitecore</domain>
                        <transformations hint="list:AddTransformation">
                            <transformation name="set idp claim" ref="federatedAuthentication/sharedTransformations/setIdpClaim" />
                            <!-- 해당 그룹의 모든 유저에게 "sitecore\developer" role의 권한을 준다. -->
                            <transformation name="Sitecore Client Users Role" type="Sitecore.Owin.Authentication.Services.DefaultTransformation, Sitecore.Owin.Authentication">
                                <sources hint="raw:AddSource">
                                    <claim name="groups" value="f5428848-ca62-4bcd-a3d1-189977c26c2e" />
                                </sources>
                                <targets hint="raw:AddTarget">
                                    <claim name="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" value="sitecore\Sitecore Minimal Page Editor" />
                                </targets>
                                <keepSource>true</keepSource>
                            </transformation>
                        </transformations>
                    </identityProvider>
                </identityProviders>
                <sharedTransformations hint="list:AddSharedClaimsTransformation">
                    <setIdpClaim name="setIdpClaim" type="Sitecore.Owin.Authentication.Services.SetIdpClaimTransform, Sitecore.Owin.Authentication" />
                </sharedTransformations>
                <propertyInitializer type="Sitecore.Owin.Authentication.Services.PropertyInitializer, Sitecore.Owin.Authentication">
                    <maps hint="list">
                        <!-- Mapping을 통하여 해당 그룹에 있는 모든 유저에게 Administrator 권한을 준다. -->
                        <map name="Sitecore Admin to Administartor" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication">
                            <data hint="raw:AddData">
                                <source name="idp" value="AzureAd" />
                                <source name="groups" value="3e677ddd-89a7-4fab-9f33-b25c5c35f7e6" />
                                <target name="IsAdministrator" value="true" />
                            </data>
                        </map>
                        <!-- Mapping을 통하여 유저 Profile의 Email 필드에 유저 이메일 정보를 업데이트 한다. -->
                        <map name="Emailaddress to email" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication">
                            <data hint="raw:AddData">
                                <!-- <source name="idp" value="AzureAd" /> -->
                                <source name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" />
                                <target name="Email" />
                            </data>
                        </map>
                        <!-- Mapping을 통하여 유저 Profile의 FullName 필드에 유저 이름을 업데이트 한다. -->
                        <map name="Name claim" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication">
                            <data hint="raw:AddData">
                                <source name="name" />
                                <target name="FullName" />
                            </data>
                        </map>
                        <!-- Mapping을 통하여 유저 Profile의 Comment 필드에 추가적인 정보를 업데이트 한다. -->
                        <map name="Description claim" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication">
                            <data hint="raw:AddData">
                                <source name="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" />
                                <target name="Comment" />
                            </data>
                        </map>
                    </maps>
                </propertyInitializer>
            </federatedAuthentication>
        </sitecore>
    </configuration>
    

  4. Azure Active Directory -> App registrations 에서 Sitecore CMS의 Sign-on URL을 등록한다.
  5. 등록되어진 사이트코어 App에서 Settings -> Reply URL에서 "https://{yoursitecoresite}/sitecore" 로 등록한다.
  6. Settings -> Required permissions에서 Window Azure Active Directory API의 Delecated Permission을 설정한다.
    1. 체크 "Access the directory as the signed-in user"
    2. 체크 "Sign in and read user profile"
    3. Save
  7. Manifest를 업데이트한다.
    1. "groupMembershipClaims": "SecurityGroup"
    2. "oauth2AllowImplicatFlow": true
  8. Sitecore 9+ 버전을 사용하고 있다면, Web.config 파일에서 "owin:AutomaticAppStartup" 세팅을 True로 설정한다.
  9. AzureAD에 등록된 이메일로 사이트코어 CMS에 로그인한다.









2017년 10월 26일 목요일

Sitecore 9.0 새로운 기능 및 기술

저번 주에 라스베가스에서 열린 Sitecore Symposium 2017을 무사히 마치고 돌아왔며, 이번 Symposium에서 사이트코어는 Sitecore Experience Cloud 9.0 릴리즈 하였다.

개인적으로 이번 토론회는 처음 참석하는 것이므로 무엇보다 기대가 많았다. Sitecore MVP로써 Sitecore 9.0을 미리 시험할수 있었으며, MVP들의 피드백을 토대로 사이트코어는 새로운 SIF (Sitecore Installation Framework) 보완하는 계기도 되었다.

아래는 이번 Sitecore 9.0 에서 적용되는 새로운 중요 기술 및 기능들이며, 차후 각각 기술에 대한 상세한 설명을 포스트 할 예정이다.

xConnect

사이트코어 XP와 xDB 사이에 존재하는 새로운 Service Layer로써, xConnect는 사이트코어가 아닌 다른 플랫폼 및 디바이스와 연동 할수가 있다. xConnect는 Collection과 Search 서비스로 구성되어 있으며, 다른 플랫폼과 디바이스는 xConnect를 통하여 사이트코어 xDB의 데이타를 불러올 수 있으며, 또한 xConnect는 다른 플랫폼의 데이타를 xDB를 가져올수가 있다.

SQL Server

Sitecore 7.5부터 적용해오던 MongoDB 를 필수요소에서 제외하였다. SQL Server를 기본 Provider로 설정되어졌으며, MongoDB 는 선택적인 항목이 되었다. 사용자 및 개발자 환경에 따라 SQL Server, SQL Azure, CosmosDB, 또는 MongoDB를 사용할수있으며, 어떤 DB 타입 상관없이 xConnect는 이 모든 데이타베이스 서버와의 호환되며 작동한다.


Forms

사이트코어 8.2까지 WFFM (Web Form For Marketers) 모듈을 사용하여, 온라인 폼 페이지를 만들고, xMarketing과 컨넥하여 사용자 및 유저의 정보를 모아왔으나, 9.0부터는 새로운 Form 빌더를 Sitecore XP (Experience Platform)에 추가였으며, UI/UX 역시 더 세련(?)되어 만들어졌다.. 이로써, 새로운 폼 모듈을 추가적으로 설치 하지 않아도 된다. Sitecore 9.0까지는 계속 WFFM을 지원하고 서포트를 하지만, 9.1부터는 WFFM 모듈 및 서포트를 중단할 계획인다.

Marketing Automation

기존에 사용해오던, Engagement Plan를 보완한 기능이며, Drag/Drop을 통하여 쉽게 마케팅 로직을 생성할수있다. 손 쉬운 UI/UX 바탕으로 마케터는 쉽게 자동화된 마케팅 캠페인을 생성할 수 있다.

Search

Sitecore 8.2까지 기본 서치엔진이던 Lucene 사용을 중단하고, 기본 엔진으로 Solr 또는 Azure Search를 사용한다. Lucene를 파일을 기반으로한 서치엔진으로 모든 데이타가 파일형식으로 저장되는것으로 반해, Solr 은 웹어플리케이션으로써 Lucene 을 탑재하여 다양한 API를 제공하며, 서치엔진은 사용 용도에 맞게 구현할수가 있다. 
Sitecore 9.0는 OWIN authentication 미드웨어를 통하여 새로운 로그인 방식을 구현한다. 기존의 LDAP 모듈을 이용하여 Active Directory의 데이터를 Sitecore CMS와 통합하여 로그인을 구현하였지만, 이번 Federated Authentication을 사용함으로써 아래의 다양한 플랫폼과 연동시킬수 있다. 예를 들면, Sitecore의 로그인을 Azure AD와 통합을 할수가 있다.
  • OpenId Connect (AzureAD, identity server) 
  • Microsoft Account 
  • Google
  • Facebook 
  • Twitter 
  • WS-Trust (Web Services Trust Language)
  • OAuth 
  • SAML


Dynamic Placeholder

이전부터 많이 문제가 제기되어왔던 기존 Placeholder에 대한 기능은 많이 제약이 따랐다. 예를 들어 렌더링 아이템에는 같은 이름의 Placeholder를 사용하지 못하였으며, 이로인하여 각각 새로운 Placeholder Setting을 적용해야만 했다. 하지만, 이름처럼 이를 다이나믹하게 보안하여 하나의 Placeholder Setting 아이템을 다양하게 구현하도록 만들었다. 차후, 여기에 대한 자세한 설명을 포스트하도록 하겠다.