Skip to content

Commit

Permalink
upgrade okta to 12.0.2 (#6125)
Browse files Browse the repository at this point in the history
* upgrade okta

* use the new ResourceException location

* use the new user status

* use the new user status

* replace factor soup

* use correct sms user factor

* replace password credential

* replace user credential

* replace user

* replace ActivateFactorRequest

* replace CallUserFactor

* replace EmailUserFactor

* replace FactorProvider

* replace RecoveryQuestionCredential

* replace userfactor

* replace application

* replace group

* replace group type

* replace user profile

* replace client

* replace _client.listGroup with groupApi.listGroup

* replace client with apiclient

* add a todo

* add application api

* update the new userbuilder

* add user api and replace client.listUser calls

* use group api to list group users

* remove application api variable

* replace single() with get(0)

* replace user.update with userApi.updateUser

and make arrayLists not empty

* replace reset, deactivate, and activate with userApi

* replace listGroup with userApi.listUserGroups

* replace removeUser with unassignUserFromGroup

* replace addToGroup with assignUserToGroup

* replace user.(un)suspend with userApi.(un)suspend

* replace user reset password with userapi reset password

* replace user reactivate with userapi reactivate

* use applicationApi assignGroupToApplication insted of createApplicationGroupAssignment

* use group api to delete groups

* add user api to live okta authentication

* add user factor api getFactor

* use userFactorApi to get factors instead of from user

* use new PasswordCredential object

* use RecoveryQuestionCredential object

* use new SmsUserFactor

* update enrollFactor to use userFactorApi

* instantiate factors using new

* use userApi to update user

* use userFactorApi to activate factor

* remove empty line

* replace user status

* update constructor to remove userAPI and factorAPI

* exclude sl4j from okta sdk

* remove mock list iterator

* fix reset UserPassword to use correct method

was previously using reactivate by accident

* mock the getId method for deletefacility

* make application api return application

* fix assertion on "update user email resource exception error test"

* add groups to group list in createUser_illegalGraphqlArgumentError_noGroupsFound

* loosen the restrictions on matchers for listGroupUsers in getAllUsersForOrganization

* mock group repsonse for "createUser_illegalGraphqlArgumentError_withoutLastName"

* mock group repsonse for "createUser_illegalGraphqlArgumentError_withoutEmail"

* update the mock to accept false param in "updateUserEmail_conflictingUser_error"

* mock id from group in "getAllUsersWithStatusForOrganization"

* add user to list in "getUserStatus"

* fix mocks for update user privileges

* clean up unused client variable and autowired constructor

* fix authentication to work with new okta sdk

* remove old wiremock mappings

* add new wiremock mappings

* Replace OktaClientProperties with strings because it's giving an error of bean not found

* fix code smells

* update rhino package to resolve vulnerability

* move apiclient to be local variable

remove curly brace around single statement labmda

* remove useless initialize method

add override annotations

* move validation into a separate method

* rename _client to client

* REMOVE - add logging for cypress

* remove expected body in mappings

* REMOVE BODY MATCHING

* move search parameter in right position

* add mapping for list groups

* REMOVE add logs

* REMOVE update logs

* remove q mapping

* update mapping for q

* remove console logs

* change the group search q to use queryParameters section

* set the url pattern to include a questionmark

* set the url pattern to include a questionmark

* remove extra slash from url pattern

* change url pattern again and hope it works this time

* add a matches statement

* update additional patterns

* update password setting to POST

* update the remaining mappings for setting password to POST

* change body pattern for account credentials

* update the mapping for the security question

* replace question mark with '

* change ' to ? in mapping

* update wiremock

* revert wiremock upgrade

* change security question

* change security question to town for first job

* add priority

* remove wiremock logs

* TEST list users by q

* update User Priveleges get users by q and search

* add listUsers by q for getUserStatus

* update okta to 10.2.2

* add logging to dev

* update to encode string before using api

* remove encoding from search term

* encode username only in search term and don't encode for q

* remove encoding

* change Collector.toList() to .toList() thx java 17

* remove logs

* upgrade to okta sdk 12

Replace ResourceException with ApiException

* fix codsmells for assertThrows to only have one invocation

* chain on object creation

* Revert "chain on object creation"

This reverts commit 1b33144.

* remove todo

* remove commit check e2e spec

* add additional test for unknown user status

* change the url pattern to remove CA

* change query matching for get groups

* rename variables to remove underscore and replace standard switch statements with enhanced switch statements

* rename variables to remove underscore and replace standard switch statements with enhanced switch statements

* add back assertions to tests for phone number and email

* fix linting issue with empty statement

* refactor resendActivationPasscode to use okta api

* replace http call with sdk and return a proper object rather than a JsonObject

* expand test coverage to include removing group

* remove additional constructor in favor of just one

* get error summary for apiexceptions

* add log message for enroll security key

* add log message for activating security key

* add log message for password failed to set

* remove ; from the prettified okta error since it's expected in the error handler

* Revert "add log message for enroll security key"

This reverts commit 107d471.

* Revert "add log message for activating security key"

This reverts commit 353f48b.

* Revert "add log message for password failed to set"

This reverts commit 2c1630b.

* Revert "Revert "add log message for activating security key""

This reverts commit 603f8fe.

* actually remove log message for error key enrollment

* delete duplicate mappings

* delete duplicate factors mappings

* Revert "delete duplicate mappings"

This reverts commit 7ec2fc1.

* Revert "delete duplicate factors mappings"

This reverts commit 1d1d9d1.

* add okta preview to img-src

* upgrade okta

* remove RestClientException since it's not possible to send from api

* update httpclient5 dependency to 5.2.1

* remove old comment

* confirm phone number in sms factor test

* update comment to be more claer

* update mock to return results from q parameter only

---------

Co-authored-by: Zedd Shmais <zedd@skylight.digital>
  • Loading branch information
BobanL and zdeveloper authored Aug 1, 2023
1 parent 1aff3dd commit dc9f544
Show file tree
Hide file tree
Showing 347 changed files with 3,857 additions and 10,342 deletions.
8 changes: 5 additions & 3 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ dependencies {

// Okta dependencies
implementation 'com.okta.spring:okta-spring-boot-starter:2.1.7'
implementation 'com.okta.sdk:okta-sdk-api:8.2.1'
runtimeOnly 'com.okta.sdk:okta-sdk-impl:8.2.1'
runtimeOnly 'com.okta.sdk:okta-sdk-httpclient:8.2.1'
implementation 'com.okta.sdk:okta-sdk-api:12.0.2'
runtimeOnly 'com.okta.sdk:okta-sdk-impl:12.0.2'
// Spring dependency management pulls 5.1.4, but okta 12.0.2 requires 5.2+ for the new
// This can be removed in the springboot 3 upgrade
implementation 'org.apache.httpcomponents.client5:httpclient5:5.2.1'

// SpringSession dependencies
runtimeOnly 'org.springframework.session:spring-session-jdbc'
Expand Down
33 changes: 23 additions & 10 deletions backend/gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.5=compileClasspath,
com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:2.13.5=compileClasspath,runtimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.5=compileClasspath,runtimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.5=compileClasspath,runtimeClasspath
com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:2.13.5=compileClasspath,runtimeClasspath
com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.13.5=compileClasspath,runtimeClasspath
com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.13.5=compileClasspath,runtimeClasspath
com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.5=compileClasspath,runtimeClasspath
com.fasterxml.jackson:jackson-bom:2.13.5=compileClasspath,runtimeClasspath
com.fasterxml.woodstox:woodstox-core:6.4.0=compileClasspath,runtimeClasspath
com.fasterxml:classmate:1.5.1=compileClasspath,runtimeClasspath
com.github.jknack:handlebars-jackson2:4.3.1=compileClasspath,runtimeClasspath
com.github.jknack:handlebars:4.3.1=compileClasspath,runtimeClasspath
com.github.stephenc.jcip:jcip-annotations:1.0-1=compileClasspath,runtimeClasspath
com.google.code.findbugs:jsr305:3.0.2=compileClasspath,runtimeClasspath
com.google.errorprone:error_prone_annotations:2.7.1=compileClasspath,runtimeClasspath
Expand All @@ -46,11 +51,9 @@ com.nimbusds:nimbus-jose-jwt:9.22=compileClasspath,runtimeClasspath
com.nimbusds:oauth2-oidc-sdk:9.35=compileClasspath,runtimeClasspath
com.okta.commons:okta-commons-lang:1.3.3=compileClasspath,runtimeClasspath
com.okta.commons:okta-config-check:1.3.3=compileClasspath,runtimeClasspath
com.okta.commons:okta-http-api:1.3.0=compileClasspath,runtimeClasspath
com.okta.commons:okta-http-httpclient:1.3.0=runtimeClasspath
com.okta.sdk:okta-sdk-api:8.2.1=compileClasspath,runtimeClasspath
com.okta.sdk:okta-sdk-httpclient:8.2.1=runtimeClasspath
com.okta.sdk:okta-sdk-impl:8.2.1=runtimeClasspath
com.okta.commons:okta-http-api:1.3.3=compileClasspath,runtimeClasspath
com.okta.sdk:okta-sdk-api:12.0.2=compileClasspath,runtimeClasspath
com.okta.sdk:okta-sdk-impl:12.0.2=runtimeClasspath
com.okta.spring:okta-spring-boot-starter:2.1.7=compileClasspath,runtimeClasspath
com.okta.spring:okta-spring-sdk:2.1.7=compileClasspath,runtimeClasspath
com.okta.spring:okta-spring-security-oauth2:2.1.7=compileClasspath,runtimeClasspath
Expand Down Expand Up @@ -79,9 +82,11 @@ io.github.openfeign.form:feign-form-spring:3.8.0=compileClasspath,runtimeClasspa
io.github.openfeign.form:feign-form:3.8.0=compileClasspath,runtimeClasspath
io.github.openfeign:feign-core:11.8=compileClasspath,runtimeClasspath
io.github.openfeign:feign-slf4j:11.8=compileClasspath,runtimeClasspath
io.jsonwebtoken:jjwt-api:0.11.2=compileClasspath,runtimeClasspath
io.jsonwebtoken:jjwt-impl:0.11.2=runtimeClasspath
io.jsonwebtoken:jjwt-jackson:0.11.2=compileClasspath,runtimeClasspath
io.jsonwebtoken:jjwt-api:0.11.2=compileClasspath
io.jsonwebtoken:jjwt-api:0.11.5=runtimeClasspath
io.jsonwebtoken:jjwt-impl:0.11.5=runtimeClasspath
io.jsonwebtoken:jjwt-jackson:0.11.2=compileClasspath
io.jsonwebtoken:jjwt-jackson:0.11.5=runtimeClasspath
io.netty:netty-buffer:4.1.94.Final=compileClasspath,runtimeClasspath
io.netty:netty-codec-dns:4.1.94.Final=compileClasspath,runtimeClasspath
io.netty:netty-codec-http2:4.1.94.Final=compileClasspath,runtimeClasspath
Expand All @@ -107,13 +112,15 @@ io.projectreactor.addons:reactor-extra:3.4.10=compileClasspath,runtimeClasspath
io.projectreactor.netty:reactor-netty-core:1.0.33=compileClasspath,runtimeClasspath
io.projectreactor.netty:reactor-netty-http:1.0.33=compileClasspath,runtimeClasspath
io.projectreactor:reactor-core:3.4.30=compileClasspath,runtimeClasspath
jakarta.activation:jakarta.activation-api:1.2.2=runtimeClasspath
io.swagger:swagger-annotations:1.6.8=compileClasspath,runtimeClasspath
jakarta.activation:jakarta.activation-api:1.2.2=compileClasspath,runtimeClasspath
jakarta.annotation:jakarta.annotation-api:1.3.5=compileClasspath,runtimeClasspath
jakarta.persistence:jakarta.persistence-api:2.2.3=compileClasspath,runtimeClasspath
jakarta.transaction:jakarta.transaction-api:1.3.3=compileClasspath,runtimeClasspath
jakarta.validation:jakarta.validation-api:2.0.2=compileClasspath,runtimeClasspath
jakarta.xml.bind:jakarta.xml.bind-api:2.3.3=compileClasspath,runtimeClasspath
javax.activation:javax.activation-api:1.2.0=compileClasspath,runtimeClasspath
javax.annotation:javax.annotation-api:1.3.2=compileClasspath,runtimeClasspath
javax.transaction:javax.transaction-api:1.3=compileClasspath,runtimeClasspath
javax.validation:validation-api:2.0.1.Final=compileClasspath,runtimeClasspath
javax.xml.bind:jaxb-api:2.3.1=compileClasspath,runtimeClasspath
Expand All @@ -126,9 +133,11 @@ net.minidev:json-smart:2.4.11=compileClasspath,runtimeClasspath
org.antlr:antlr4-runtime:4.9.3=runtimeClasspath
org.apache.commons:commons-lang3:3.12.0=compileClasspath,runtimeClasspath
org.apache.commons:commons-text:1.10.0=compileClasspath,runtimeClasspath
org.apache.httpcomponents.client5:httpclient5:5.2.1=compileClasspath,runtimeClasspath
org.apache.httpcomponents.core5:httpcore5-h2:5.1.5=compileClasspath,runtimeClasspath
org.apache.httpcomponents.core5:httpcore5:5.1.5=compileClasspath,runtimeClasspath
org.apache.httpcomponents:httpclient:4.5.14=compileClasspath,runtimeClasspath
org.apache.httpcomponents:httpcore:4.4.16=compileClasspath,runtimeClasspath
org.apache.httpcomponents:httpmime:4.5.14=runtimeClasspath
org.apache.logging.log4j:log4j-api:2.17.2=compileClasspath,runtimeClasspath
org.apache.logging.log4j:log4j-to-slf4j:2.17.2=compileClasspath,runtimeClasspath
org.apache.tomcat.embed:tomcat-embed-core:9.0.76=compileClasspath,runtimeClasspath
Expand All @@ -137,8 +146,11 @@ org.apache.tomcat.embed:tomcat-embed-websocket:9.0.76=compileClasspath,runtimeCl
org.aspectj:aspectjweaver:1.9.7=compileClasspath,runtimeClasspath
org.attoparser:attoparser:2.0.5.RELEASE=compileClasspath,runtimeClasspath
org.bouncycastle:bcpkix-jdk15on:1.70=compileClasspath,runtimeClasspath
org.bouncycastle:bcpkix-jdk18on:1.75=runtimeClasspath
org.bouncycastle:bcprov-jdk15on:1.70=compileClasspath,runtimeClasspath
org.bouncycastle:bcprov-jdk18on:1.75=runtimeClasspath
org.bouncycastle:bcutil-jdk15on:1.70=compileClasspath,runtimeClasspath
org.bouncycastle:bcutil-jdk18on:1.75=runtimeClasspath
org.checkerframework:checker-qual:3.12.0=compileClasspath,runtimeClasspath
org.codehaus.woodstox:stax2-api:4.2.1=compileClasspath,runtimeClasspath
org.glassfish.jaxb:jaxb-runtime:2.3.8=compileClasspath,runtimeClasspath
Expand All @@ -155,6 +167,7 @@ org.jetbrains.kotlin:kotlin-stdlib:1.6.21=compileClasspath,runtimeClasspath
org.jetbrains:annotations:13.0=compileClasspath,runtimeClasspath
org.json:json:20230618=compileClasspath,runtimeClasspath
org.liquibase:liquibase-core:4.9.1=compileClasspath,runtimeClasspath
org.openapitools:jackson-databind-nullable:0.2.6=compileClasspath,runtimeClasspath
org.ow2.asm:asm:9.3=compileClasspath,runtimeClasspath
org.postgresql:postgresql:42.3.8=runtimeClasspath
org.projectlombok:lombok:1.18.28=compileClasspath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import static gov.cdc.usds.simplereport.config.AuthorizationConfiguration.AUTHORIZER_BEAN;
import static gov.cdc.usds.simplereport.config.WebConfiguration.IDENTITY_VERIFICATION;

import com.okta.sdk.resource.ResourceException;
import gov.cdc.usds.simplereport.api.accountrequest.errors.AccountRequestFailureException;
import gov.cdc.usds.simplereport.api.model.accountrequest.AccountRequestOrganizationCreateTemplate;
import gov.cdc.usds.simplereport.api.model.accountrequest.IdentityVerificationAnswersRequest;
Expand All @@ -29,6 +28,7 @@
import javax.annotation.PostConstruct;
import javax.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.openapitools.client.ApiException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -165,8 +165,8 @@ private IdentityVerificationAnswersResponse checkAnswersAndCreateQueuedOrganizat
}

return verificationResponse;
} catch (ResourceException e) {
// The `ResourceException` is mostly thrown when a user requests an account with an email
} catch (ApiException e) {
// The `ApiException` is mostly thrown when a user requests an account with an email
// address that's already in Okta, but can be thrown for other Okta internal errors as well.
// Since there is no way for the user to fix the problem and resubmit, rethrow these as
// AccountRequestExceptions so we get paged.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

import static gov.cdc.usds.simplereport.config.WebConfiguration.USER_ACCOUNT_REQUEST;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import gov.cdc.usds.simplereport.api.model.errors.BadRequestException;
import gov.cdc.usds.simplereport.api.model.errors.InvalidActivationLinkException;
import gov.cdc.usds.simplereport.api.model.errors.OktaAuthenticationFailureException;
import gov.cdc.usds.simplereport.api.model.useraccountcreation.ActivateAccountRequest;
import gov.cdc.usds.simplereport.api.model.useraccountcreation.ActivateSecurityKeyRequest;
import gov.cdc.usds.simplereport.api.model.useraccountcreation.EnrollMfaRequest;
import gov.cdc.usds.simplereport.api.model.useraccountcreation.FactorAndActivation;
import gov.cdc.usds.simplereport.api.model.useraccountcreation.FactorAndQrCode;
import gov.cdc.usds.simplereport.api.model.useraccountcreation.SetPasswordRequest;
import gov.cdc.usds.simplereport.api.model.useraccountcreation.SetRecoveryQuestionRequest;
Expand All @@ -20,7 +19,6 @@
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -231,13 +229,12 @@ public FactorAndQrCode getAuthQrCode(
* their security key.
*/
@PostMapping("/enroll-security-key-mfa")
public JsonNode enrollSecurityKeyMfa(@SessionAttribute String userId, HttpServletRequest request)
public FactorAndActivation enrollSecurityKeyMfa(
@SessionAttribute String userId, HttpServletRequest request)
throws OktaAuthenticationFailureException {
JSONObject enrollResponse = _oktaAuth.enrollSecurityKey(userId);
request.getSession().setAttribute(FACTOR_ID_KEY, enrollResponse.getString(FACTOR_ID_KEY));
return JsonNodeFactory.instance
.objectNode()
.put("activation", enrollResponse.getJSONObject("activation").toString());
var enrollResponse = _oktaAuth.enrollSecurityKey(userId);
request.getSession().setAttribute(FACTOR_ID_KEY, enrollResponse.getFactorId());
return enrollResponse;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package gov.cdc.usds.simplereport.api.model;

import com.okta.sdk.resource.user.UserStatus;
import gov.cdc.usds.simplereport.api.model.facets.PersonWrapper;
import gov.cdc.usds.simplereport.db.model.ApiUser;
import gov.cdc.usds.simplereport.db.model.auxiliary.PersonName;
import gov.cdc.usds.simplereport.service.model.WrappedEntity;
import org.openapitools.client.model.UserStatus;

/** A wrapper class around APIUser, to return Okta-specific status information to GraphQL. */
public class ApiUserWithStatus extends WrappedEntity<ApiUser> implements PersonWrapper<ApiUser> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package gov.cdc.usds.simplereport.api.model;

import com.okta.sdk.resource.user.UserStatus;
import gov.cdc.usds.simplereport.api.model.facets.PersonWrapper;
import gov.cdc.usds.simplereport.config.authorization.UserPermission;
import gov.cdc.usds.simplereport.service.model.UserInfo;
import gov.cdc.usds.simplereport.service.model.WrappedEntity;
import java.util.List;
import java.util.Optional;
import org.openapitools.client.model.UserStatus;

public class User extends WrappedEntity<UserInfo> implements PersonWrapper<UserInfo> {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package gov.cdc.usds.simplereport.api.model.useraccountcreation;

import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class FactorAndActivation {
private String factorId;

private Map<String, Object> activation;
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package gov.cdc.usds.simplereport.idp.authentication;

import com.okta.sdk.resource.user.factor.FactorStatus;
import com.okta.sdk.resource.user.factor.FactorType;
import gov.cdc.usds.simplereport.api.model.errors.BadRequestException;
import gov.cdc.usds.simplereport.api.model.errors.InvalidActivationLinkException;
import gov.cdc.usds.simplereport.api.model.errors.OktaAuthenticationFailureException;
import gov.cdc.usds.simplereport.api.model.useraccountcreation.FactorAndActivation;
import gov.cdc.usds.simplereport.api.model.useraccountcreation.FactorAndQrCode;
import gov.cdc.usds.simplereport.api.model.useraccountcreation.UserAccountStatus;
import gov.cdc.usds.simplereport.config.BeanProfiles;
Expand All @@ -15,7 +14,8 @@
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.json.JSONObject;
import org.openapitools.client.model.FactorStatus;
import org.openapitools.client.model.FactorType;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

Expand Down Expand Up @@ -176,22 +176,21 @@ public FactorAndQrCode enrollAuthenticatorAppMfa(String userId, String appType)
return new FactorAndQrCode(factorId, qrCode);
}

public JSONObject enrollSecurityKey(String userId) throws OktaAuthenticationFailureException {
public FactorAndActivation enrollSecurityKey(String userId)
throws OktaAuthenticationFailureException {
validateUser(userId);
String factorId = "webAuthnFactorId";
JSONObject idJson = new JSONObject();
idJson.put("id", userId);
JSONObject activationContents = new JSONObject();
var userMap = new HashMap<String, String>();
userMap.put("id", userId);
var activationContents = new HashMap<String, Object>();
activationContents.put("challenge", "challengeString");
activationContents.put("user", idJson);
JSONObject resultJson = new JSONObject();
resultJson.put("activation", activationContents);
resultJson.put("factorId", factorId);
activationContents.put("user", userMap);
var enrollment = new FactorAndActivation(factorId, activationContents);

DemoMfa securityKeyMfa =
new DemoMfa(FactorType.WEBAUTHN, "FIDO", factorId, FactorStatus.PENDING_ACTIVATION);
this.idToUserMap.get(userId).setMfa(securityKeyMfa);
return resultJson;
return enrollment;
}

public void activateSecurityKey(
Expand Down
Loading

0 comments on commit dc9f544

Please sign in to comment.