Merge branch 'lwm2m_fix_bug_release'

This commit is contained in:
Igor Kulikov 2022-01-13 10:41:40 +02:00
commit cffb657af7
6 changed files with 67 additions and 26 deletions

View File

@ -14,6 +14,7 @@
-- limitations under the License. -- limitations under the License.
-- --
CREATE OR REPLACE PROCEDURE update_profile_bootstrap() CREATE OR REPLACE PROCEDURE update_profile_bootstrap()
LANGUAGE plpgsql AS LANGUAGE plpgsql AS
$$ $$
@ -25,9 +26,11 @@ BEGIN
profile_data, profile_data,
'{transportConfiguration}', '{transportConfiguration}',
get_bootstrap( get_bootstrap(
profile_data::jsonb #> '{transportConfiguration}', profile_data::jsonb #> '{transportConfiguration}',
subquery.publickey_bs, subquery.publickey_bs,
subquery.publickey_lw), subquery.publickey_lw,
profile_data::json #>> '{transportConfiguration, bootstrap, bootstrapServer, securityMode}',
profile_data::json #>> '{transportConfiguration, bootstrap, lwm2mServer, securityMode}'),
true) true)
FROM ( FROM (
SELECT id, SELECT id,
@ -48,7 +51,8 @@ END;
$$; $$;
CREATE OR REPLACE FUNCTION get_bootstrap(transport_configuration_in jsonb, publickey_bs text, CREATE OR REPLACE FUNCTION get_bootstrap(transport_configuration_in jsonb, publickey_bs text,
publickey_lw text) RETURNS jsonb AS publickey_lw text, security_mode_bs text,
security_mode_lw text) RETURNS jsonb AS
$$ $$
DECLARE DECLARE
@ -56,10 +60,19 @@ DECLARE
bootstrap_in jsonb; bootstrap_in jsonb;
BEGIN BEGIN
IF security_mode_lw IS NULL THEN
security_mode_lw := 'NO_SEC';
END IF;
IF security_mode_bs IS NULL THEN
security_mode_bs := 'NO_SEC';
END IF;
bootstrap_in := transport_configuration_in::jsonb #> '{bootstrap}'; bootstrap_in := transport_configuration_in::jsonb #> '{bootstrap}';
bootstrap_new := json_build_array( bootstrap_new := json_build_array(
json_build_object('shortServerId', bootstrap_in::json #> '{bootstrapServer}' -> 'serverId', json_build_object('shortServerId', bootstrap_in::json #> '{bootstrapServer}' -> 'serverId',
'securityMode', bootstrap_in::json #> '{bootstrapServer}' ->> 'securityMode', 'securityMode', security_mode_bs,
'binding', bootstrap_in::json #> '{servers}' ->> 'binding', 'binding', bootstrap_in::json #> '{servers}' ->> 'binding',
'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime',
'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled',
@ -73,7 +86,7 @@ BEGIN
bootstrap_in::json #> '{bootstrapServer}' -> 'bootstrapServerAccountTimeout' bootstrap_in::json #> '{bootstrapServer}' -> 'bootstrapServerAccountTimeout'
), ),
json_build_object('shortServerId', bootstrap_in::json #> '{lwm2mServer}' -> 'serverId', json_build_object('shortServerId', bootstrap_in::json #> '{lwm2mServer}' -> 'serverId',
'securityMode', bootstrap_in::json #> '{lwm2mServer}' ->> 'securityMode', 'securityMode', security_mode_lw,
'binding', bootstrap_in::json #> '{servers}' ->> 'binding', 'binding', bootstrap_in::json #> '{servers}' ->> 'binding',
'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime',
'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled',
@ -93,7 +106,7 @@ BEGIN
bootstrap_new, bootstrap_new,
true) || '{"bootstrapServerUpdateEnable": true}'; true) || '{"bootstrapServerUpdateEnable": true}';
END ; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
CREATE OR REPLACE PROCEDURE update_device_credentials_to_base64_and_bootstrap() CREATE OR REPLACE PROCEDURE update_device_credentials_to_base64_and_bootstrap()
@ -102,9 +115,9 @@ $$
BEGIN BEGIN
UPDATE device_credentials UPDATE device_credentials
SET credentials_value = get_device_and_bootstrap(credentials_value::text) SET credentials_value = get_device_and_bootstrap(credentials_value::text)
WHERE credentials_type = 'LWM2M_CREDENTIALS'; WHERE credentials_type = 'LWM2M_CREDENTIALS';
END; END;
$$; $$;
@ -112,7 +125,7 @@ CREATE OR REPLACE FUNCTION get_device_and_bootstrap(IN credentials_value text, O
LANGUAGE plpgsql AS LANGUAGE plpgsql AS
$$ $$
DECLARE DECLARE
client_secret_key text; client_secret_key text;
client_public_key_or_id text; client_public_key_or_id text;
client_key_value_object jsonb; client_key_value_object jsonb;
client_bootstrap_server_value_object jsonb; client_bootstrap_server_value_object jsonb;
@ -130,7 +143,7 @@ BEGIN
'key', client_public_key_or_id); 'key', client_public_key_or_id);
credentials_value_new := credentials_value_new :=
credentials_value_new::jsonb || json_build_object('client', client_key_value_object)::jsonb; credentials_value_new::jsonb || json_build_object('client', client_key_value_object)::jsonb;
END IF; END IF;
IF credentials_value::jsonb #> '{client}' ->> 'securityConfigClientMode' = 'X509' AND IF credentials_value::jsonb #> '{client}' ->> 'securityConfigClientMode' = 'X509' AND
NULLIF((credentials_value::jsonb #> '{client}' ->> 'cert' ~ '^[0-9a-fA-F]+$')::text, 'false') = 'true' THEN NULLIF((credentials_value::jsonb #> '{client}' ->> 'cert' ~ '^[0-9a-fA-F]+$')::text, 'false') = 'true' THEN
client_public_key_or_id := client_public_key_or_id :=
@ -141,8 +154,8 @@ END IF;
'cert', client_public_key_or_id); 'cert', client_public_key_or_id);
credentials_value_new := credentials_value_new :=
credentials_value_new::jsonb || json_build_object('client', client_key_value_object)::jsonb; credentials_value_new::jsonb || json_build_object('client', client_key_value_object)::jsonb;
END IF; END IF;
IF credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'securityMode' = 'RPK' OR IF credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'securityMode' = 'RPK' OR
credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'securityMode' = 'X509' THEN credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'securityMode' = 'X509' THEN
IF NULLIF((credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'clientSecretKey' ~ '^[0-9a-fA-F]+$')::text, IF NULLIF((credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'clientSecretKey' ~ '^[0-9a-fA-F]+$')::text,
@ -165,9 +178,9 @@ END IF;
client_bootstrap_object := credentials_value_new::jsonb #> '{bootstrap}' || client_bootstrap_server_object::jsonb; client_bootstrap_object := credentials_value_new::jsonb #> '{bootstrap}' || client_bootstrap_server_object::jsonb;
credentials_value_new := credentials_value_new :=
jsonb_set(credentials_value_new::jsonb, '{bootstrap}', client_bootstrap_object::jsonb, false)::jsonb; jsonb_set(credentials_value_new::jsonb, '{bootstrap}', client_bootstrap_object::jsonb, false)::jsonb;
END IF; END IF;
END IF; END IF;
IF credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'securityMode' = 'RPK' OR IF credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'securityMode' = 'RPK' OR
credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'securityMode' = 'X509' THEN credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'securityMode' = 'X509' THEN
IF NULLIF( IF NULLIF(
@ -193,8 +206,8 @@ END IF;
client_bootstrap_object := credentials_value_new::jsonb #> '{bootstrap}' || client_bootstrap_server_object::jsonb; client_bootstrap_object := credentials_value_new::jsonb #> '{bootstrap}' || client_bootstrap_server_object::jsonb;
credentials_value_new := credentials_value_new :=
jsonb_set(credentials_value_new::jsonb, '{bootstrap}', client_bootstrap_object::jsonb, false)::jsonb; jsonb_set(credentials_value_new::jsonb, '{bootstrap}', client_bootstrap_object::jsonb, false)::jsonb;
END IF; END IF;
END IF; END IF;
END; END;
$$; $$;

View File

@ -63,6 +63,12 @@ public class LwM2MServiceImpl implements LwM2MService {
} else { } else {
bsServ.setServerPublicKey(Base64.encodeBase64String(publicKeyBase64)); bsServ.setServerPublicKey(Base64.encodeBase64String(publicKeyBase64));
} }
byte[] certificateBase64 = getCertificate(bsServerConfig);
if (certificateBase64 == null) {
bsServ.setServerCertificate("");
} else {
bsServ.setServerCertificate(Base64.encodeBase64String(certificateBase64));
}
return bsServ; return bsServ;
} }
@ -77,5 +83,17 @@ public class LwM2MServiceImpl implements LwM2MService {
} }
return null; return null;
} }
private byte[] getCertificate(LwM2MSecureServerConfig config) {
try {
SslCredentials sslCredentials = config.getSslCredentials();
if (sslCredentials != null) {
return sslCredentials.getCertificateChain()[0].getEncoded();
}
} catch (Exception e) {
log.trace("Failed to fetch certificate from key store!", e);
}
return null;
}
} }

View File

@ -42,17 +42,23 @@ public class LwM2MServerSecurityConfig {
@ApiModelProperty(position = 8, value = "Server Public Key for 'Security' mode (DTLS): RPK or X509. Format: base64 encoded", example = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAZ0pSaGKHk/GrDaUDnQZpeEdGwX7m3Ws+U/kiVat\n" + @ApiModelProperty(position = 8, value = "Server Public Key for 'Security' mode (DTLS): RPK or X509. Format: base64 encoded", example = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAZ0pSaGKHk/GrDaUDnQZpeEdGwX7m3Ws+U/kiVat\n" +
"+44sgk3c8g0LotfMpLlZJPhPwJ6ipXV+O1r7IZUjBs3LNA==", readOnly = true) "+44sgk3c8g0LotfMpLlZJPhPwJ6ipXV+O1r7IZUjBs3LNA==", readOnly = true)
protected String serverPublicKey; protected String serverPublicKey;
@ApiModelProperty(position = 9, value = "Bootstrap Server Account Timeout (If the value is set to 0, or if this resource is not instantiated, the Bootstrap-Server Account lifetime is infinite.)", example = "0", readOnly = true) @ApiModelProperty(position = 9, value = "Server Public Key for 'Security' mode (DTLS): X509. Format: base64 encoded", example = "MMIICODCCAd6gAwIBAgIUI88U1zowOdrxDK/dOV+36gJxI2MwCgYIKoZIzj0EAwIwejELMAkGA1UEBhMCVUs\n" +
"xEjAQBgNVBAgTCUt5aXYgY2l0eTENMAsGA1UEBxMES3lpdjEUMBIGA1UEChMLVGhpbmdzYm9hcmQxFzAVBgNVBAsMDkRFVkVMT1BFUl9URVNUMRkwFwYDVQQDDBBpbnRlcm1lZGlhdGVfY2EwMB4XDTIyMDEwOTEzMDMwMFoXDTI3MDEwODEzMDMwMFowFDESMBAGA1UEAxM\n" +
"JbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUO3vBo/JTv0eooY7XHiKAIVDoWKFqtrU7C6q8AIKqpLcqhCdW+haFeBOH3PjY6EwaWkY04Bir4oanU0s7tz2uKOBpzCBpDAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/\n" +
"BAIwADAdBgNVHQ4EFgQUEjc3Q4a0TxzP/3x3EV4fHxYUg0YwHwYDVR0jBBgwFoAUuSquGycMU6Q0SYNcbtSkSD3TfH0wLwYDVR0RBCgwJoIVbG9jYWxob3N0LmxvY2FsZG9tYWlugglsb2NhbGhvc3SCAiAtMAoGCCqGSM49BAMCA0gAMEUCIQD7dbZObyUaoDiNbX+9fUNp\n" +
"AWrD7N7XuJUwZ9FcN75R3gIgb2RNjDkHoyUyF1YajwkBk+7XmIXNClmizNJigj908mw=", readOnly = true)
protected String serverCertificate;
@ApiModelProperty(position = 10, value = "Bootstrap Server Account Timeout (If the value is set to 0, or if this resource is not instantiated, the Bootstrap-Server Account lifetime is infinite.)", example = "0", readOnly = true)
Integer bootstrapServerAccountTimeout = 0; Integer bootstrapServerAccountTimeout = 0;
/** Config -> ObjectId = 1 'LwM2M Server' */ /** Config -> ObjectId = 1 'LwM2M Server' */
@ApiModelProperty(position = 10, value = "Specify the lifetime of the registration in seconds.", example = "300", readOnly = true) @ApiModelProperty(position = 11, value = "Specify the lifetime of the registration in seconds.", example = "300", readOnly = true)
private Integer lifetime = 300; private Integer lifetime = 300;
@ApiModelProperty(position = 11, value = "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation. " + @ApiModelProperty(position = 12, value = "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation. " +
"If this Resource doesnt exist, the default value is 0.", example = "1", readOnly = true) "If this Resource doesnt exist, the default value is 0.", example = "1", readOnly = true)
private Integer defaultMinPeriod = 1; private Integer defaultMinPeriod = 1;
/** ResourceID=6 'Notification Storing When Disabled or Offline' */ /** ResourceID=6 'Notification Storing When Disabled or Offline' */
@ApiModelProperty(position = 12, value = "If true, the LwM2M Client stores “Notify” operations to the LwM2M Server while the LwM2M Server account is disabled or the LwM2M Client is offline. After the LwM2M Server account is enabled or the LwM2M Client is online, the LwM2M Client reports the stored “Notify” operations to the Server. " + @ApiModelProperty(position = 13, value = "If true, the LwM2M Client stores “Notify” operations to the LwM2M Server while the LwM2M Server account is disabled or the LwM2M Client is offline. After the LwM2M Server account is enabled or the LwM2M Client is online, the LwM2M Client reports the stored “Notify” operations to the Server. " +
"If false, the LwM2M Client discards all the “Notify” operations or temporarily disables the Observe function while the LwM2M Server is disabled or the LwM2M Client is offline. " + "If false, the LwM2M Client discards all the “Notify” operations or temporarily disables the Observe function while the LwM2M Server is disabled or the LwM2M Client is offline. " +
"The default value is true.", example = "true", readOnly = true) "The default value is true.", example = "true", readOnly = true)
private boolean notifIfDisabled = true; private boolean notifIfDisabled = true;

View File

@ -765,15 +765,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
X509LwM2MBootstrapServerCredential x509ServerCredentials = (X509LwM2MBootstrapServerCredential) bootstrapServerConfig; X509LwM2MBootstrapServerCredential x509ServerCredentials = (X509LwM2MBootstrapServerCredential) bootstrapServerConfig;
server = x509ServerCredentials.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server"; server = x509ServerCredentials.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server";
if (StringUtils.isEmpty(x509ServerCredentials.getServerPublicKey())) { if (StringUtils.isEmpty(x509ServerCredentials.getServerPublicKey())) {
throw new DeviceCredentialsValidationException(server + " X509 public key must be specified!"); throw new DeviceCredentialsValidationException(server + " X509 certificate must be specified!");
} }
try { try {
String certServer = EncryptionUtil.certTrimNewLines(x509ServerCredentials.getServerPublicKey()); String certServer = EncryptionUtil.certTrimNewLines(x509ServerCredentials.getServerPublicKey());
x509ServerCredentials.setServerPublicKey(certServer); x509ServerCredentials.setServerPublicKey(certServer);
SecurityUtil.publicKey.decode(x509ServerCredentials.getDecodedCServerPublicKey()); SecurityUtil.certificate.decode(x509ServerCredentials.getDecodedCServerPublicKey());
} catch (Exception e) { } catch (Exception e) {
throw new DeviceCredentialsValidationException(server + " X509 public key must be in standard [RFC7250] and then encoded to Base64 format!"); throw new DeviceCredentialsValidationException(server + " X509 certificate must be in DER-encoded X509v3 format and support only EC algorithm and then encoded to Base64 format!");
} }
break; break;
} }

View File

@ -112,6 +112,9 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
this.changeSecurityHostPortFields(serverSecurityConfig); this.changeSecurityHostPortFields(serverSecurityConfig);
} }
this.serverFormGroup.patchValue(serverSecurityConfig, {emitEvent: false}); this.serverFormGroup.patchValue(serverSecurityConfig, {emitEvent: false});
if (this.currentSecurityMode === Lwm2mSecurityType.X509) {
this.serverFormGroup.get('serverPublicKey').patchValue(serverSecurityConfig.serverCertificate, {emitEvent: false});
}
}); });
this.serverFormGroup.valueChanges.pipe( this.serverFormGroup.valueChanges.pipe(
takeUntil(this.destroy$) takeUntil(this.destroy$)

View File

@ -129,6 +129,7 @@ export interface ServerSecurityConfig {
securityHost?: string; securityHost?: string;
securityPort?: number; securityPort?: number;
serverPublicKey?: string; serverPublicKey?: string;
serverCertificate?: string;
clientHoldOffTime?: number; clientHoldOffTime?: number;
shortServerId?: number; shortServerId?: number;
bootstrapServerAccountTimeout: number; bootstrapServerAccountTimeout: number;