Composer での ThingWorx モデルの定義 > システム > サブシステム > ファイル転送サブシステム > リモートファイル転送のオプションのセキュリティ強化
リモートファイル転送のオプションのセキュリティ強化
リモートファイル転送に関連する制御とセキュリティを強化する必要がある場合、以下のサンプルエンティティと付随する購読の一部またはすべてを実装することをお勧めします。
以下の 1 つ目のエンティティはデータシェイプであり、これによって管理者はリモートファイル転送の頻度とサイズが適切になるように目的のパラメータを設定できます。データシェイプを使用することで、必要に応じて、ThingWorx ユーザー (およびその関連アプリケーションキー) ごとに異なる設定のコンフィギュレーションが可能になります。
2 つ目のエンティティは値ストリームであり、ユーザーごとにファイル転送のサイズと頻度が記録されます。
以下の 3 つ目のエンティティは、各リモートファイル転送イベントによってトリガーされる購読を実装します。購読は以下を自動的に実行します。
1. アラートを提供します。
2. ファイル転送をフリーズします。
3. 一定のファイル転送頻度を超えた場合には必ず、関連する WebSocket 接続を終了します。
* 
以下の例では logger 文はコメントアウトされており、デバッグ目的にのみ使用されます。不必要に情報を公開することを避けるため、本番環境ではこれらを有効にしないことをお勧めします。
データシェイプエンティティ
最初に、SizeUserFrequency の 3 つのフィールドから成るデータシェイプをインポートまたは作成します。これにより、ユーザーごとのファイル転送の最大許容制限が追跡されます。
<?xml version="1.0" encoding="UTF-8"?>
<!-- This entity is for informational and example purposes only, and you must configure/validate it to ensure that it meets your functional and security requirements. -->
<Entities build="latest" majorVersion="0" minorVersion="0" modelPersistenceProviderPackage="PostgresPersistenceProviderPackage" revision="0" schemaVersion="1045" universal="">
<DataShapes>
<DataShape baseDataShape="" description="DataShape for permissible file transfer limits" documentationContent="" homeMashup="" lastModifiedDate="2020-10-01T00:00:00.000-00:00" name="SizeLimits" projectName="FileTransfer" tags="">
<Owner name="Administrator" type="User" />
<avatar />
<DesignTimePermissions>
<Create />
<Read />
<Update />
<Delete />
<Metadata />
</DesignTimePermissions>
<RunTimePermissions />
<VisibilityPermissions>
<Visibility />
</VisibilityPermissions>
<ConfigurationTableDefinitions />
<ConfigurationTables />
<FieldDefinitions>
<FieldDefinition aspect.isPrimaryKey="false" aspect.minimumValue="1.0" baseType="NUMBER" description="" name="Frequency" ordinal="3" />
<FieldDefinition aspect.isPrimaryKey="false" aspect.minimumValue="1.0" baseType="NUMBER" description="SizeLimit for user in bytes" name="Size" ordinal="1" />
<FieldDefinition aspect.isPrimaryKey="false" baseType="STRING" description="User name" name="User" ordinal="2" />
</FieldDefinitions>
</DataShape>
</DataShapes>
</Entities>
値ストリームエンティティ
データシェイプをインポートまたは作成した後で、ユーザーごとにファイル転送の履歴を記録する以下のエンティティをインポートまたは作成します。
<?xml version="1.0" encoding="UTF-8"?>
<!-- This entity is for informational and example purposes only, and you must configure/validate it to ensure that it meets your functional and security requirements. -->
<Entities build="latest" majorVersion="0" minorVersion="0" modelPersistenceProviderPackage="PostgresPersistenceProviderPackage" revision="0" schemaVersion="1045" universal="">
<Things>
<Thing description="ValueStream to log history of file transfers" documentationContent="" effectiveThingPackage="ValueStreamThing" enabled="true" homeMashup="StreamMashup" identifier="" lastModifiedDate="2020-10-01T00:00:00.000-00:00" name="VS" projectName="FileTransfer" published="false" tags="" thingTemplate="ValueStream" valueStream="">
<Owner name="Administrator" type="User" />
<avatar />
<DesignTimePermissions>
<Create />
<Read />
<Update />
<Delete />
<Metadata />
</DesignTimePermissions>
<RunTimePermissions />
<VisibilityPermissions>
<Visibility />
</VisibilityPermissions>
<ConfigurationTableDefinitions />
<ConfigurationTables>
<ConfigurationTable description="Data Thing Configuration" isMultiRow="false" name="DataThingSettings" ordinal="0">
<DataShape>
<FieldDefinitions>
<FieldDefinition baseType="STRING" description="Persistence Provider Name" name="persistenceProvider" ordinal="0" />
</FieldDefinitions>
</DataShape>
<Rows>
<Row>
<persistenceProvider><![CDATA[ThingworxPersistenceProvider]]></persistenceProvider>
</Row>
</Rows>
</ConfigurationTable>
<ConfigurationTable description="Configurable options to tune Value Stream performance" isMultiRow="false" name="PersistenceProviderCustomSettings" ordinal="2">
<DataShape>
<FieldDefinitions>
<FieldDefinition aspect.friendlyName="Persistence Provider Custom Settings Table" baseType="INFOTABLE" description="Persistence Provider Custom Config Table" name="customConfigTable" ordinal="0" />
</FieldDefinitions>
</DataShape>
<Rows>
<Row>
<customConfigTable>
<infoTable>
<DataShape>
<FieldDefinitions />
</DataShape>
<Rows />
</infoTable>
</customConfigTable>
</Row>
</Rows>
</ConfigurationTable>
</ConfigurationTables>
<ThingShape>
<PropertyDefinitions />
<ServiceDefinitions />
<EventDefinitions />
<ServiceMappings />
<ServiceImplementations />
<Subscriptions />
</ThingShape>
<PropertyBindings />
<RemotePropertyBindings />
<RemoteServiceBindings />
<RemoteEventBindings />
<AlertConfigurations />
<ImplementedShapes />
<ThingProperties />
</Thing>
</Things>
</Entities>
リモートファイル転送エンティティ
最後に、各ファイル転送イベントによってトリガーされる以下の購読を含む Thing をインポートまたは作成します。
<?xml version="1.0" encoding="UTF-8"?>
<!-- This entity is for informational and example purposes only, and you must configure/validate it to ensure that it meets your functional and security requirements. -->
<Entities build="latest" majorVersion="0" minorVersion="0" modelPersistenceProviderPackage="PostgresPersistenceProviderPackage" revision="0" schemaVersion="1045" universal="">
<Things>
<Thing description="Thing for regulating Remote File Transfer" documentationContent="" effectiveThingPackage="RemoteThingWithFileTransfer" enabled="true" homeMashup="" identifier="FileRepo@ServerA" lastModifiedDate="2020-10-01T00:00:00.000-00:00" name="RemoteFileTransfer" projectName="FileTransfer" published="false" tags="" thingTemplate="RemoteThingWithFileTransfer" valueStream="VS">
<Owner name="Administrator" type="User" />
<avatar />
<DesignTimePermissions>
<Create />
<Read />
<Update />
<Delete />
<Metadata />
</DesignTimePermissions>
<RunTimePermissions />
<VisibilityPermissions>
<Visibility />
</VisibilityPermissions>
<ConfigurationTableDefinitions />
<ConfigurationTables>
<ConfigurationTable description="Reporting Settings" isMultiRow="false" name="ReportingConfiguration" ordinal="0">
<DataShape>
<FieldDefinitions>
<FieldDefinition aspect.defaultValue="NotReporting" aspect.isPrimaryKey="true" aspect.isReadOnly="false" aspect.thingTemplate="ReportingStrategy" baseType="THINGNAME" description="Strategy to determine health" name="reportingStrategy" ordinal="0" />
</FieldDefinitions>
</DataShape>
<Rows>
<Row>
<reportingStrategy><![CDATA[AlwaysOnReporting]]></reportingStrategy>
</Row>
</Rows>
</ConfigurationTable>
</ConfigurationTables>
<ThingShape>
<PropertyDefinitions>
<PropertyDefinition aspect.cacheTime="0.0" aspect.dataChangeType="VALUE" aspect.isLogged="true" aspect.isPersistent="true" baseType="NUMBER" category="" description="" isLocalOnly="false" name="Administrator" ordinal="2" />
<PropertyDefinition aspect.cacheTime="0.0" aspect.dataChangeType="VALUE" aspect.defaultValue="0.0" aspect.isLogged="true" aspect.isPersistent="true" baseType="NUMBER" category="" description="" isLocalOnly="false" name="EventProp" ordinal="4" />
<PropertyDefinition aspect.cacheTime="0.0" aspect.dataChangeType="VALUE" aspect.dataShape="SizeLimits" aspect.isLogged="false" aspect.isPersistent="true" baseType="INFOTABLE" category="" description="" isLocalOnly="false" name="Users" ordinal="3" />
</PropertyDefinitions>
<ServiceDefinitions>
<ServiceDefinition aspect.isAsync="false" category="" description="" isAllowOverride="false" isLocalOnly="false" isOpen="false" isPrivate="false" name="s1">
<ResultType baseType="INFOTABLE" description="" name="result" ordinal="0" />
<ParameterDefinitions />
</ServiceDefinition>
</ServiceDefinitions>
<EventDefinitions />
<ServiceMappings />
<ServiceImplementations>
<ServiceImplementation description="" handlerName="Script" name="s1">
<ConfigurationTables>
<ConfigurationTable description="" isMultiRow="false" name="Script" ordinal="0">
<DataShape>
<FieldDefinitions>
<FieldDefinition baseType="STRING" description="code" name="code" ordinal="0" />
</FieldDefinitions>
</DataShape>
<Rows>
<Row>
<code><![CDATA[var ed = new Date();
var result = me.QueryNumberPropertyHistory({
oldestFirst: undefined /* BOOLEAN */,
maxItems: undefined /* NUMBER */,
endDate: ed /* DATETIME */,
propertyName: "Administrator" /* STRING */,
query: undefined /* QUERY */,
startDate: ed-(24*3600*1000) /* DATETIME */
});]]></code>
</Row>
</Rows>
</ConfigurationTable>
</ConfigurationTables>
</ServiceImplementation>
</ServiceImplementations>
<Subscriptions>
<Subscription description="" enabled="false" eventName="FileTransfer" name="FileTransferSub" source="" sourceProperty="" sourceType="Thing">
<ServiceImplementation description="" handlerName="Script" name="FileTransferSub">
<ConfigurationTables>
<ConfigurationTable description="" isMultiRow="false" name="Script" ordinal="0">
<DataShape>
<FieldDefinitions>
<FieldDefinition baseType="STRING" description="code" name="code" ordinal="0" />
</FieldDefinitions>
</DataShape>
<Rows>
<Row>
<code><![CDATA[var activeTransferJobs = Subsystems["FileTransferSubsystem"].GetActiveTransferJobs();
for each (activeTransferJob in activeTransferJobs.rows) {
var bytesTransferred = activeTransferJob.bytesTransferred;
var transferSize = activeTransferJob.maxSize;
//QueryPropertyHistoryfor24hours
var ed = new Date();
var user = eventData.user;
var last24HrsFileTransfer = me.QueryNumberPropertyHistory({
oldestFirst: undefined /* BOOLEAN */,
maxItems: undefined /* NUMBER */,
endDate: ed /* DATETIME */,
propertyName: user /* STRING */,
query: undefined /* QUERY */,
startDate: ed-(24*3600*1000) /* DATETIME */
});
//Aggregate for 24 hrs.
var totalTransferredBytes = Resources["InfoTableFunctions"].Aggregate({
t: last24HrsFileTransfer,
columns: "value",
aggregates: "SUM"
});
var totalFrequency = last24HrsFileTransfer.length;
var defaultSizeLimitForUser;
var defaultFrequencyForUser;
for each(var user in me.Users.rows){
if(user.User == eventData.user){
defaultSizeLimitForUser = user.Size;
defaultFrequencyForUser = user.Frequency;
}
}
if(totalFrequency>defaultFrequencyForUser || (totalTransferredBytes.SUM_value + transferSize)> defaultSizeLimitForUser){
//logger.error("File Transfer Limit Exceeded : " + activeTransferJob.transferId);
//Send Alert
var eventPropValue = Things['RemoteFileTransfer']['EventProp'];
Things['RemoteFileTransfer']['EventProp'] = eventPropValue + 1;

//Freeze Transfer
//logger.warn("FreezingTransfer : " + activeTransferJob.transferId);
Subsystems["FileTransferSubsystem"].CancelTransfer({
reason: "Surpassed file transfer limit of : " + defaultSizeLimitForUser + " bytes or frequency of " + defaultFrequencyForUser,
transferId: activeTransferJob.transferId
});
//logger.warn("Transfer Freezed : " + activeTransferJob.transferId);
//Closing Endpoint Session for User
result = Subsystems["WSCommunicationsSubsystem"].CloseEndpointSessions({
userName: activeTransferJob.user
});
//logger.warn("Session Closed for userContext : " + activeTransferJob.user);
}
me[eventData.user] = bytesTransferred;
}]]></code>
</Row>
</Rows>
</ConfigurationTable>
</ConfigurationTables>
</ServiceImplementation>
</Subscription>
</Subscriptions>
</ThingShape>
<PropertyBindings />
<RemotePropertyBindings />
<RemoteServiceBindings />
<RemoteEventBindings />
<AlertConfigurations>
<AlertDefinitions name="Administrator" />
<AlertDefinitions name="EventProp" />
<AlertDefinitions name="Users" />
</AlertConfigurations>
<ImplementedShapes />
<ThingProperties>
<Users>
<Value>
<infoTable>
<DataShape>
<FieldDefinitions>
<FieldDefinition aspect.isPrimaryKey="false" aspect.minimumValue="1.0" baseType="NUMBER" description="" name="Frequency" ordinal="3" />
<FieldDefinition aspect.isPrimaryKey="false" aspect.minimumValue="1.0" baseType="NUMBER" description="SizeLimit for user in bytes" name="Size" ordinal="1" />
<FieldDefinition aspect.isPrimaryKey="false" baseType="STRING" description="User name" name="User" ordinal="2" />
</FieldDefinitions>
</DataShape>
<Rows>
<Row>
<Frequency>10.0</Frequency>
<Size>1500000.0</Size>
<User><![CDATA[Administrator]]></User>
</Row>
</Rows>
</infoTable>
</Value>
<Timestamp>2020-10-01T00:00:00.000-00:00</Timestamp>
<Quality>GOOD</Quality>
</Users>
</ThingProperties>
</Thing>
</Things>
</Entities>