カスタムエンティティを匿名化し、簡単にGDPR準拠する方法 - Japan

null カスタムエンティティを匿名化し、簡単にGDPR準拠する方法
by Yasuyuki Takeo

カスタムエンティティを匿名化し、
簡単にGDPR準拠する方法

画像

こんにちは、日本ライフレイサポータビリティエンジニアの竹生です。

EU域内の個人情報保護を規定する法律として制定されたGDPRいわゆる一般データ保護規則ですが、そのGDPRにまつわる有益なセキュリティーに関するテクニカル記事を紹介したいと思います。欧州ユーザに限らず、Liferayでサービス構築する方にはおすすめです!

以下の知識レベルの方たち、ユースケースが対象です。ご参照ください。


  

  • 上級レベル*
  • Liferay DXP開発に必須の知識

*レベルの定義については、こちらのブログの冒頭で紹介しています。


  ※本記事はLiferay Community Blogに投稿されている”Anonymize your custom entities and comply with GDPR the easy way!”を翻訳したものです。配信元または著者の許可を得て配信しています。

はじめに


以前スペインのシンポジウムにて、私の同僚であるセルジオ・サンチェス(Sergio Sanchez)のGDPRにまつわるプレゼンテーションを手伝った際、Liferay 7.1でGDPR対応に非常に有効な機能を発見しました。

それはカスタムService Builderエンティティを、LiferayのGDPRフレームワーク(UAD)と統合し、自分のエンティティ内の個人データを匿名化できる、というものです。

使ってみるとわかりやすく、優れた機能であることがわかりました。利用する上でのいくつかの課題は、すでにLPSに上がっており、本記事でも紹介します。

では実際どのように使えるかを見てみましょう。

サービスビルダーの変更点


最初のステップは、使い慣れたツール(Blade、Liferay IDEなど)を使って、Service Builderプロジェクトを作成することです。これにより、通常どおりAPIとサービスという2つのプロジェクトが作成されるのですが、ここで最初の課題に直面します。

Bladeは7.1 DTDを使用してservice.xmlファイルを生成するのではなく、依然として7.0を使用しているため、DTDを7.1に更新する必要があります。

<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 7.1.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_7_1_0.dtd">

この問題はLPS-86544で報告され、2019年8月現在、解決されています。

2つ目の問題は、DTDをバージョン7.1に更新すると、Service BuilderによってLiferay CE 7.1 GA1でコンパイルまたは実行されないコードが生成されることです。

コンパイルするには、Petraに依存関係を追加し、カーネルを少なくともバージョン3.23.0(Liferay CE 7.1 GA2のカーネルバージョンで未リリース)に更新する必要がありますが、 Liferay CE 7.1 GA1インスタンスでは、デプロイしても残念ながら実行されません。

これを指摘してくれたMinhchau Dangのおかげで、本バグも報告されており(LPS-86835)、2019年8月現在、解決されています。

私は、build.gradle(-serviceプロジェクトの)で以下を実行しました。Liferay DXP 7.1 FP2を使​​っています。


dependencies {
    compileOnly group: "biz.aQute.bnd", name: "biz.aQute.bndlib", version: "3.5.0"
    compileOnly group: "com.liferay", name: "com.liferay.portal.spring.extender", version: "2.0.0"
    compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "3.26.0"
    compileOnly group: "com.liferay", name: "com.liferay.petra.string", version: "2.0.0"
}

注:Githubの例では、-serviceプロジェクトだけでなく、あらゆる場所でカーネルバージョン3.26.0を使用しています。

正確には、「何を」匿名化したいのか?


上記処理により、サービスプロジェクトとAPIプロジェクトをコンパイルする準備が整いました。次のステップは、service.xmlに必要な情報を含めてエンティティを匿名化できるようにすることです。

含める必要がある最初の2つは、エンティティレベルでの2つの属性、uad-application-name、およびuad-package-pathです。

uad-application-nameはLiferayが匿名化UIでアプリケーションを表示するために使用する名前であり、uad-package-pathはService BuilderがUADクラスを作成するために使用するパッケージです(上級者知識:パッケージ名に“ uad”は含めないでください。SBが含めてくれます)

私の例では、以下のエンティティを使いました。

<entity local-service="true" name="Promotion" remote-service="true" uuid="true" uad-application-name="Citytour" uad-package-path="com.liferay.symposium.citytour.uad">

指定を終えたら、エンティティのデータを匿名化する方法をService Builderに伝えます。これには、フィールドレベルで2つの属性:uad-anonymize-field-nameとuad-nonanonymizableを使用できます。

7.1 service.xml DTDからのUad-anonymize-field-name:

「uad-anonymize-field-name値は、自動匿名化中にこの列の値を置き換えるのに使用する、匿名ユーザーフィールドを指定します。たとえば、「fullName」が指定されている場合、自動匿名化中に匿名ユーザーのフルネームでこの列の値が置き換わります。 uad-anonymize-field-nameの値は、ユーザー名列でのみ使用する必要があります(例: "statusByUserName")。

たとえば、次のようにフィールドが定義されているとします。

<column name="userName" type="String" uad-anonymize-field-name="fullName"/>

この場合、自動匿名化プロセスが実行されると、そのフィールドの値が匿名ユーザーのフルネームに置き換えられます

一方、7.1 DTDからuad-nonanonymizableが追加されました。

「uad-nonanonymizableは、GDPRコンプライアンスリクエストが発生した場合に、管理者が確認する必要がかどうかを指定します。これは、データが自動的に匿名化できないことを意味します。」

つまり、このフィールドは自動で匿名化できず、ユーザーデータを削除するときに手動で修正する必要があります。と言っても、実際には管理ユーザーはエンティティを確認して「匿名化」をクリックするだけで済みます。(エンティティの匿名化プロセスが実装されているので、こちらも後述します)。

私は「プロモーション」エンティティで以下フィールドを使用しました。


        <!-- PK fields -->
        <column name="promotionId" primary="true" type="long" />
        <!-- Group instance -->
        <column name="groupId" type="long" />
        <!-- Audit fields -->
        <column name="companyId" type="long" />
        <column name="userId" type="long" />
        <column name="userName" type="String" uad-anonymize-field-name="fullName"/>
        <column name="createDate" type="Date" />
        <column name="modifiedDate" type="Date" />
        <!-- Promotion Data -->
        <column name="description" type="String" uad-nonanonymizable="true"/>
        <column name="price" type="double" uad-nonanonymizable="true"/>
        <column name="destinationCity" type="String" uad-nonanonymizable="true"/>
        <!-- Personal User Data -->
        <column name="offereeFirstName" type="String"/>
        <column name="offereeLastName" type="String"/>
        <column name="offereeIdNumber" type="String" />
        <column name="offereeTelephone" type="String" />

この場合は、説明、価格、およびdestinationCityの各フィールドを手動でレビューする必要があるとフレームワークに伝えています。

SBはこの2つの属性で何をしているのか?実際、uad-anonymize-field-nameでマークされたフィールドを持つエンティティがある場合、buildServiceを実行すると、匿名化、表示、およびデータエクスポートロジックを保持するための2つの新しいプロジェクトが作成されます。 Service Builderは非常に優秀だと感じました。

buildServiceを使用してService Builderサービスを構築する


これでb​​uildService Gradleタスクを実行する準備が整いました。サービスビルダーによって2つのプロジェクト<entity> -uadと<entity> -uad-testが作成されたことがわかります。 <entity> -uadプロジェクト(私の場合はcampaign-uad)は、カスタム匿名化とデータエクスポートロジックを含んだエンティティで、*-uad-testはテストクラスを含みます。

ここでもう一つの「落とし穴」を修正しなければなりません。このままの状態でgradleタスクのビルドまたはデプロイを実行すると、見事に失敗します。

理由は、build.gradleファイルがないからです。 Service Builderのおしいところですが、手動で作成しましょう。これで依存関係に含めることができます(私のシステム構築時の場合です。)


dependencies {   
    compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "3.26.0"
    compileOnly group: "com.liferay", name: "com.liferay.user.associated.data.api", version: "3.0.1"   
    compileOnly group: "com.liferay", name: "com.liferay.petra.string", version: "2.0.0"
    compileOnly group: "org.osgi", name: "osgi.cmpn", version: "6.0.0"   
    compileOnly project(":modules:promotions:promotions-api")
}

このバグもLPS-86814で報告されています。

これで、プロジェクトは問題なくコンパイルされるはずです。カスタム匿名化ロジックを追加しましょう

匿名化するためのカスタマイズ


作成された*-uadプロジェクトには3つのパッケージがあります(定数も含めるなら4つ):

  • Anonymizer:エンティティのためのカスタム匿名化ロジックを保持します。
  • Display:LiferayのUAD UI用のカスタム表示ロジックを保持しています。
  • Exporter:カスタムの個人データのエクスポートロジックを保持します。


それぞれに、BaseクラスとBaseクラスを拡張する別のクラスがあります。私の例のアノニマイザーパッケージには、BasePromotionUADAnonymizerクラスとPromotionUADAnonymizerクラスがあります。具体的なクラス(私の場合はPromotionUADAnonymizer)を使用し、autoAnonymizeメソッドを上書きします。このメソッドでは、カスタムエンティティの各フィールドを匿名化する方法をフレームワークに指示します。私の例では、以下を実行しました:


@Component(immediate = true, service = UADAnonymizer.class)
public class PromotionUADAnonymizer extends BasePromotionUADAnonymizer {
    @Override
    public void autoAnonymize(Promotion promotion, long userId,
        User anonymousUser) throws PortalException {
        if (promotion.getUserId() == userId) {
            promotion.setUserId(anonymousUser.getUserId());
            promotion.setUserName(anonymousUser.getFullName());
            promotion.setOffereeFirstName(anonymousUser.getFirstName());
            promotion.setOffereeLastName(anonymousUser.getLastName());
            promotion.setOffereeIdNumber("XXXXXXXXX");
            promotion.setOffereeTelephone("XXX-XXX-XXX");           
        }

        promotionLocalService.updatePromotion(promotion);
    }
}

エンティティの姓名にanonymousUserフィールドを使用し、IDフィールドと電話番号フィールドを匿名エントリに設定していますが、匿名化するフィールドとその方法は選択できます。

まとめ


作業はこれで終了です!あなたのエンティティはLiferayのUADフレームワークと統合され、ユーザーを削除すると、本処理がしっかりと機能することがわかります。ユーザーの観点からUADがどのように機能するのかを確認するには、コミュニティドキュメントの「ユーザーデータの管理(英語)」の章を参照してください。

今回の例を、GitHubレポジトリに、プロモーションを作成するためのWebポートレットとともにアップロードしました。単にプロモーションWebポートレットをページに追加し、Test Testとは異なるユーザーでいくつかのプロモーションを作成してから、ユーザーを削除するだけで、そのユーザーによって作成されたすべてのエントリに匿名フィールドが表示されることを確認できます。

是非試してみてください:https://github.com/ibairuiz/sympo-demo

 


 

本記事は以上です。

いかがでしたでしょうか?

 


 

■ これまで発信してきた日本語による技術コンテンツを、Qiitaでお読みいただけます。よろしければそちらの記事も合わせてご役立てください。
https://qiita.com/yasuflatland-lf

Doorkeeperのライフレイコミュニティメンバー大歓迎!
コーポレートブログの技術コンテンツ更新情報など定期的におとどけしています。
https://liferay.doorkeeper.jp/

■ライフレイ公式Slackチャネルもできました!
https://liferay-community.slack.com/
このスラック内の#lug-japanが日本語でLiferayスタッフとやりとりできるチャンネルになります。ぜひご利用ください! 

 

 

業界最高の評価

Gartner

Gartnerレポート:『リーダー』に位置づけ
ライフレイは9年連続で、Gartner社によるデジタルエクスペリエンスプラットフォーム(DXP )分野のマジック・クアドラントにおいて、リーダーに選出されました。

レポートの詳細、ダウンロード