Skip to content

ライセンス判定の実装 ​

第7版作成 最終更新 (日本時間)
確認バージョン1.5.7.01.5.8.1

プリザンターには OSS 版と商用ライセンス版があり、一部の機能は上位のライセンスがないと動きません。設定ファイルで有効にしたのに機能が効かない場合は、多くがライセンス判定によるものです。このページでは判定の実装と、1.5.7.0 での変更点をまとめます。

結論: 判定は Implem.ParameterAccessor の Parameters クラスに集約されており、多くの機能はエラーにならず静かに無効化されます。また、期限切れのトライアルライセンスが残っていると、有効な商用ライセンスがあってもオプション機能が無効になります。

全体の構造 ​

判定の流れは次のとおりです。

図を読み込み中…

要素実体役割
License外部アセンブリのクラス商用ライセンスの内容(期限・ユーザー数・オプション)
TrialLicenseOSS 側のクラストライアルライセンス
LicenseOptionsOSS 側の enum機能ごとのフラグ

商用ライセンスはリフレクションで読まれる ​

Parameters.License の型 License.License はソースツリーに含まれておらず、外部アセンブリとして供給される想定です。

csharp
public static License.License License = new License.License();

そのため、プロパティの読み取りはすべてリフレクション経由です。

csharp
private static LicenseOptions GetLicenseOptions()
{
    if (TrialLicense?.Check() == true)
    {
        return LicenseOptions.Trial;
    }
    var prop = License.GetType().GetProperty("Options");
    return (LicenseOptions)(int?)(prop?.GetValue(License) ?? 0);
}

Implem.ParameterAccessor/Parameters.cs#L185-L194

GetProperty("Options") が null なら 0(LicenseOptions.None)になります。OSS 版のダミー実装が Options プロパティを持っていなくても、例外にならず「オプションなし」に落ちる作りです。

リフレクションで読まれるのは Copyright / CopyrightUrl / DisableAds / Environment / GracePeriodDays / Options の 6 つで、いずれも「プロパティがなければ既定値」という書き方です。

csharp
public static string Copyright()
{
    var prop = License.GetType().GetProperty("Copyright");
    return (string)(prop?.GetValue(License))
        ?? $"Copyright © Implem Inc. 2014 - {DateTime.Now.Year}";
}

public static bool DisableAds()
{
    var prop = License.GetType().GetProperty("DisableAds");
    return (bool?)(prop?.GetValue(License)) ?? false;
}

LicenseOptions:機能ごとのフラグ ​

csharp
[Flags]
public enum LicenseOptions
{
    None = 0,
    AdvancedCache = 1 << 0,
    MultiTenants = 1 << 1,
    Queue = 1 << 2,
    RateLimit = 1 << 3,
    SamlExtendedAttributes = 1 << 4,
    Scim = 1 << 5,
    BlockSiteTaskWhileRunning = 1 << 6,

    Trial = AdvancedCache
        | Queue
        | RateLimit
        | SamlExtendedAttributes
        | Scim
        | BlockSiteTaskWhileRunning
}

Implem.ParameterAccessor/Parts/LicenseOptions.cs

フラグ値対応する機能
AdvancedCache1サイト設定キャッシュ(Sites.EnableSsCache)
MultiTenants2マルチテナント(テナント管理 API・保護テナント以外の認証)
Queue4バックグラウンドジョブ(エクスポート・インポート)
RateLimit8レートリミット
SamlExtendedAttributes16SAML の拡張属性
Scim32SCIM
BlockSiteTaskWhileRunning64テーブル単位の排他制御(TableExclusive)

1.5.7.0 での変更 1.5.7.0 以降 ​

1.5.6.0 と比べてフラグが 3 つ増え、3 つとも Trial に含められました(トライアルで試せる範囲が広がりました)。

diff
      AdvancedCache = 1 << 0,
      MultiTenants = 1 << 1,
      Queue = 1 << 2,
      RateLimit = 1 << 3,
+     SamlExtendedAttributes = 1 << 4,
+     Scim = 1 << 5,
+     BlockSiteTaskWhileRunning = 1 << 6,

-     Trial = AdvancedCache | Queue | RateLimit
+     Trial = AdvancedCache
+         | Queue
+         | RateLimit
+         | SamlExtendedAttributes
+         | Scim
+         | BlockSiteTaskWhileRunning
  • MultiTenants は 1.5.6.0 と同様、Trial に含まれていません(トライアル対象外)。
  • Scim は 1.5.7.0 時点でフラグと HasScim() は用意されていますが、参照している箇所はまだありません。確認したソースでは、SCIM の有効判定 ScimFeatureUtilities.Enabled() が Parameters.Scim.Enabled == true && CommercialLicense() && HasScim() として参照しています(ScimFeatureUtilities.cs#L7-L8)。

Allow*() と Has*() ​

判定メソッドは 2 層に分かれています。利用側が呼ぶのは基本的に Allow*() です。

メソッド見ているもの
Has*()オプションフラグが立っているかだけ(GetLicenseOptions() 経由)
Allow*()ライセンスの有効性とフラグを組み合わせて、実際に使えるか
csharp
public static bool AllowQueue()
{
    return TrialLicense?.Check() ?? License.Check() && HasQueue();
}

public static bool AllowSsCache()
{
    return TrialLicense?.Check() ?? License.Check() && HasAdvancedCache();
}

public static bool AllowRateLimit()
{
    return TrialLicense?.Check() ?? License.Check() && HasRateLimit();
}

public static bool AllowBlockSiteTaskWhileRunning()
{
    return TrialLicense?.Check() ?? License.Check() && HasBlockSiteTaskWhileRunning();
}

public static bool AllowMultiTenants()
{
    return License.Check() && HasMultiTenants();
}

Implem.ParameterAccessor/Parameters.cs#L90-L113

演算子の優先順位と期限切れトライアル ​

C# では && が ?? より優先順位が高いため、TrialLicense?.Check() ?? (License.Check() && HasQueue()) と解釈されます。

TrialLicense評価結果
null右辺を評価商用ライセンスが有効かつフラグが立っていれば true
期限内true を返すフラグを見ずに true
期限切れfalse を返す商用ライセンスを見ずに false

期限切れの場合、?? の左辺は false(null ではない)なので右辺は評価されません。GetLicenseOptions() も同様で、トライアルが有効なら LicenseOptions.Trial を返し、商用ライセンスの Options は見ません。

WARNING

期限切れのトライアルライセンスが残っていると、有効な商用ライセンスがあってもオプション機能が無効になります。 トライアルから商用へ切り替える際は、トライアルライセンスのファイルを確実に取り除いてください。

AllowMultiTenants だけ形が違う ​

AllowMultiTenants() だけは TrialLicense?.Check() ?? ... の形をとっていません。その形だとトライアル期間中は TrialLicense.Check() が true を返してそのまま通ってしまうため、意図的に形を変えていると読めます。結果として、マルチテナント機能は商用ライセンスに MultiTenants オプションが含まれている場合にのみ利用できます。

1.5.7.0 で追加された判定と影響 1.5.7.0 以降 ​

Parameters に次のメソッドが追加されました。

diff
+ public static bool AllowBlockSiteTaskWhileRunning()
+ {
+     return TrialLicense?.Check() ?? License.Check() && HasBlockSiteTaskWhileRunning();
+ }
+
+ public static bool AllowMultiTenants()
+ {
+     return License.Check() && HasMultiTenants();
+ }

+ public static bool HasBlockSiteTaskWhileRunning()
+ public static bool HasSamlExtendedAttributes()
+ public static bool HasScim()

TableExclusive にライセンス判定が入った ​

テーブル単位の排他制御(TableExclusive)は、General.json の BlockSiteTaskWhileRunning で有効化する機能で、BulkUpsert などの一括処理で同じサイトへの同時実行を防ぐために使われます。1.5.7.0 で、この有効条件にライセンス判定が追加されました。

diff
  public TableExclusive(Context context, long? siteId = null, [CallerMemberName] string callerMethodName = "")
      : base(
            context: context,
-           enabled: Parameters.General.BlockSiteTaskWhileRunning == true,
+           enabled: Parameters.General.BlockSiteTaskWhileRunning == true
+               && Parameters.AllowBlockSiteTaskWhileRunning(),
            key: $"TableExclusive_SiteId={siteId ?? context.SiteId}",
            siteId: siteId,
            comment: callerMethodName)

Implem.Pleasanter/Models/Sessions/SessionExclusive.cs#L92-L101

WARNING

General.json で BlockSiteTaskWhileRunning を true にしていても、対象ライセンスがない環境では排他制御が効きません。enabled が false になるだけでエラーにはならないため、効いていないことに気づきにくい点に注意してください。

マルチテナントが認証にも効くようになった ​

AllowMultiTenants() は API のガードだけでなく、Context の認証処理からも呼ばれます。

csharp
if (!Parameters.MultiTenant.IsProtectedTenant(TenantId) && !Parameters.AllowMultiTenants())
{
    Authenticated = false;
}

保護テナント(MultiTenant.json の DefaultTenantId、既定は 1)以外は、マルチテナントライセンスがないと認証が通りません。

WARNING

ライセンスなしの環境で 2 つ目以降のテナントを運用していた場合、1.5.7.0 へバージョンアップした時点でそのテナントのユーザーがログインできなくなります。該当する環境では、バージョンアップ前に Tenants テーブルの状況を確認してください。

ライセンス種別と猶予期間 ​

GetLicenseType() ​

管理画面などに表示するライセンス種別は GetLicenseType() が返します。商用ライセンスの中身が空(期限が DateTime.MinValue、ライセンシー未設定、ユーザー数 0)かどうかで分岐します。

csharp
public static int GetLicenseType()
{
    if (License.Deadline == DateTime.MinValue
        && (License.Licensee == null || License.Licensee == "")
        && License.Users == 0)
    {
        if (TrialLicense == null) return 0x02;
        return TrialLicense.Check() ? 0x08 : 0x09;
    }
    return License.Check() ? 0x04 : 0x05;
}
戻り値状態
0x02商用ライセンスなし・トライアルもなし(OSS 版)
0x08トライアルライセンスが有効
0x09トライアルライセンスが期限切れ
0x04商用ライセンスが有効
0x05商用ライセンスが期限切れ

猶予期間(GracePeriod) ​

csharp
public static bool GracePeriod()
{
    if (TrialLicense != null && TrialLicense.Check()) return false;
    var prop = License.GetType().GetProperty("GracePeriodDays");
    return License.Deadline < DateTime.Now
        && License.Deadline.AddDays((int)(prop?.GetValue(License) ?? 0)) >= DateTime.Now;
}

GracePeriodDays もリフレクションで読まれ、プロパティがなければ 0 日(猶予なし)です。期限切れ後この日数以内なら GracePeriod() が true を返し、警告表示をしつつ利用を継続できます。

トライアルライセンス ​

csharp
[Serializable()]
public class TrialLicense
{
    public bool Check() => Deadline >= DateTime.Now.Date;
    public int? Users { get; set; }
    public DateTime Deadline { get; set; }
    public string Licensee { get; set; }
    public DateTime CreatedTime { get; set; }
    public string CheckSum { get; set; }
}

Implem.ParameterAccessor/Parts/TrialLicense.cs

  • Check() は期限の比較だけで、オプションフラグは持ちません。代わりに GetLicenseOptions() が LicenseOptions.Trial を返します。
  • CheckSum による改ざん検知の検証は Implem.Pleasanter/Libraries/TrialLicenses/TrialLicenseUtilities.cs 側で行われます。

機能とライセンスの対応表 ​

1.5.7.0 時点でライセンス判定が入っている機能です。1.5.8.1 で変わった箇所は表の下に書いています。

機能判定メソッド必要なオプショントライアル
サイト設定キャッシュAllowSsCache()AdvancedCache可
バックグラウンドジョブAllowQueue()Queue可
レートリミット(設定)AllowRateLimit()RateLimit可
テーブル排他制御AllowBlockSiteTaskWhileRunning()BlockSiteTaskWhileRunning可
SAML 拡張属性HasSamlExtendedAttributes()SamlExtendedAttributes可
マルチテナントAllowMultiTenants()MultiTenants不可
SCIMHasScim()Scim可(1.5.7.0 では未使用)

1.5.7.0 では、SAML 拡張属性だけは Allow*() ではなく Has*() が直接呼ばれています。

csharp
if (!Parameters.HasSamlExtendedAttributes())

Has*() は GetLicenseOptions() を経由するため、トライアルが有効なら LicenseOptions.Trial で判定されます。ただし License.Check() を通らないので、期限切れの商用ライセンスでもフラグが立っていれば通ってしまうという違いがあります。意図的なのか実装の揺れなのかは、コードだけでは判断できません。

1.5.8.1 での変化

確認したソースでは、Parameters に AllowSamlExtendedAttributes()(TrialLicense?.Check() ?? License.Check() && HasSamlExtendedAttributes())があり、Saml.cs はこちらを呼んでいます。そのため 1.5.8.1 では、期限切れの商用ライセンスでは SAML 拡張属性は使えません(Parameters.cs#L112-L115、Saml.cs#L61)。SCIM は CommercialLicense() && HasScim() で判定され、トライアルが有効なら Trial に Scim が含まれるので使えます。LicenseOptions と GetLicenseOptions()・その他の Allow*() は 1.5.7.0 と同じです(LicenseOptions.cs、Parameters.cs#L79-L120、Parameters.cs#L192-L200)。

運用上のチェックポイント ​

  • 設定したはずの機能が動かないときは、まず対応する Allow*() の判定を疑います。多くはエラーにならず静かに無効化されます。
  • トライアルから商用ライセンスへ切り替えたら、トライアルライセンスのファイルを取り除きます。
  • BlockSiteTaskWhileRunning は、1.5.7.0 以降は対象ライセンスがないと true にしても効きません。
  • マルチテナント(保護テナント以外)は商用ライセンスの MultiTenants オプションが必須で、トライアルでは使えません。1.5.7.0 へのバージョンアップ前に Tenants テーブルを確認します。

関連ページ ​

変更履歴

第7版記事の確認版を繰り返す表現を整理する
第6版1.5.7.0の変更点を独立させ旧記事を版別に移行
第5版レートリミッターの解説と、フォーム投稿の制限・ウイルススキャン・拡張子制限・外部検索エンジン・管理画面設定の改修・設計メモを追加
第4版「外部連携・AI」「構築・運用」「内部実装を読む」に対応バージョンを表示
第3版「内部実装を読む」を 1.5.8.1 のソースで検証して修正
第2版記事のファイル名に並び順の番号を付け、元記事リンクを frontmatter の sources に移行
第1版「内部実装を読む」に CodeDefiner・多言語対応・ライセンス判定・拡張計算式を追加