Skip to content

Commit

Permalink
Merge branch 'develop' into security/archive-unarchive
Browse files Browse the repository at this point in the history
  • Loading branch information
gsmithun4 committed Jun 14, 2022
2 parents 0553367 + a6c0277 commit 421298f
Show file tree
Hide file tree
Showing 74 changed files with 2,394 additions and 152 deletions.
2 changes: 1 addition & 1 deletion .version
@@ -1 +1 @@
1.17.1
1.17.2
9 changes: 8 additions & 1 deletion cypress/constants/selectors/manageUsers.js
Expand Up @@ -29,7 +29,7 @@ export const usersSelector ={
firstNameLabel: "[data-cy=first-name-label]",
lastNameLabel:"[data-cy=last-name-label]",
companyLabel: "[data-cy=company-label]",
roleLable: "[data-cy=role-label]",
roleLabel: "[data-cy=role-label]",
passwordLabel: "[data-cy=password-label]",
confirmpasswordLabel: "[data-cy=confirm-password-label]",
termsInfo: "[data-cy=terms-and-condition-info]",
Expand All @@ -47,4 +47,11 @@ export const usersSelector ={
createNewApp: "[data-cy=create-new-application]",
dropdownText: "[data-cy=dropdown-organization-list]>>:eq(0)",
arrowIcon: "[data-cy=workspace-arrow-icon]",
singleWorkspaceElements:{
cardTitle: "[data-cy=card-title]",
passwordLabel: "[data-cy=password-label]",
confirmpasswordLabel: "[data-cy=confirm-password-label]",
termsInfo: "[data-cy=terms-and-condition-info]",
}

}
10 changes: 9 additions & 1 deletion cypress/constants/texts/manageUsers.js
Expand Up @@ -40,5 +40,13 @@ export const usersText = {
archivedStatus: "archived",
invitedStatus: "invited",
archivedToast: "The user has been archived",
inviteToast: "Added to the workspace successfully."
inviteToast: "Added to the workspace successfully.",
singleWorkspaceElements:{
cardTitle: "Set up your account",
passwordLabel: "Password",
confirmpasswordLabel: "Confirm Password",
termsInfo: "By clicking the button below, you agree to our Terms and Conditions.",
},
swPasswordSuccessToast: "Added to the workspace and password has been set successfully."

}
185 changes: 185 additions & 0 deletions cypress/integration/dashboard/single-workspace/manageUsers.spec.js
@@ -0,0 +1,185 @@
import {commonSelectors} from "Selectors/common";
import { fake } from "Fixtures/fake";
import { usersSelector } from "Selectors/manageUsers";
import { usersText } from "Texts/manageUsers";
import * as users from "Support/utils/manageUsers";
import * as common from "Support/utils/common";
import { path } from "Texts/common";
import { commonText } from "Texts/common";

const firstName = fake.firstName;
const lastName = fake.lastName.replaceAll("[^A-Za-z]", "");
const email = (`${firstName}@example.com`).toLowerCase();

describe("Manage Users for single workspace", ()=>{
before(()=>{
cy.appUILogin();
});
it("Should verify the Manage users page", ()=>{
common.navigateToManageUsers();
users.manageUsersElements();

cy.get(usersSelector.cancelButton).click();
cy.get(usersSelector.usersElements.nameTitile).should("be.visible");
cy.get(usersSelector.inviteUserButton).click();

cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.fisrtNameError).should("be.visible").and("have.text", usersText.fieldRequired);
cy.get(usersSelector.lastNameError).should("be.visible").and("have.text", usersText.fieldRequired);
cy.get(usersSelector.emailError).should("be.visible").and("have.text", usersText.fieldRequired);

cy.clearAndType(usersSelector.firstNameInput, firstName);
cy.get(usersSelector.lastNameInput).clear();
cy.get(usersSelector.emailInput).clear();
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.lastNameError).should("be.visible").and("have.text", usersText.fieldRequired);
cy.get(usersSelector.emailError).should("be.visible").and("have.text", usersText.fieldRequired);

cy.get(usersSelector.firstNameInput).clear();
cy.get(usersSelector.emailInput).clear();
cy.clearAndType(usersSelector.lastNameInput, lastName);
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.fisrtNameError).should("be.visible").and("have.text", usersText.fieldRequired);
cy.get(usersSelector.emailError).should("be.visible").and("have.text", usersText.fieldRequired);

cy.get(usersSelector.firstNameInput).clear();
cy.get(usersSelector.lastNameInput).clear();
cy.clearAndType(usersSelector.emailInput, email);
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.fisrtNameError).should("be.visible").and("have.text", usersText.fieldRequired);
cy.get(usersSelector.lastNameError).should("be.visible").and("have.text", usersText.fieldRequired);

cy.get(usersSelector.firstNameInput).clear();
cy.clearAndType(usersSelector.lastNameInput, lastName);
cy.clearAndType(usersSelector.emailInput, email);
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.fisrtNameError).should("be.visible").and("have.text", usersText.fieldRequired);

cy.get(usersSelector.lastNameInput).clear();
cy.clearAndType(usersSelector.firstNameInput, firstName);
cy.clearAndType(usersSelector.emailInput, email);
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.lastNameError).should("be.visible").and("have.text", usersText.fieldRequired);

cy.get(usersSelector.emailInput).clear();
cy.clearAndType(usersSelector.firstNameInput, firstName);
cy.clearAndType(usersSelector.lastNameInput, lastName);
cy.get(usersSelector.createUserButton).click();
cy.get(usersSelector.emailError).should("be.visible").and("have.text", usersText.fieldRequired);

cy.clearAndType(usersSelector.firstNameInput, firstName);
cy.clearAndType(usersSelector.lastNameInput, lastName);
cy.clearAndType(usersSelector.emailInput, usersText.usersElements.userEmail);
cy.get(usersSelector.createUserButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.exsitingEmail);
});

it("Should verify the confirm invite page", ()=>{
users.inviteUser(firstName,lastName,email);

cy.get(usersSelector.confirmInvitePage).should("be.visible");
cy.get(usersSelector.pageLogo).should("be.visible");
for( const element in usersSelector.singleWorkspaceElements){
cy.get(usersSelector.singleWorkspaceElements[element]).should("be.visible").and("have.text", usersText.singleWorkspaceElements[element]);
}
cy.get(usersSelector.finishSetup).click();
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.passwordErrToast);
cy.get(usersSelector.passwordInput).should("have.value", "");
cy.get(usersSelector.confirmPasswordInput).should("have.value", "");

cy.clearAndType(usersSelector.passwordInput, usersText.password);
cy.wait(1000);
cy.get(usersSelector.finishSetup).click();
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.passwordErrToast);
cy.get(usersSelector.passwordInput).should("have.value", usersText.password);
cy.get(usersSelector.confirmPasswordInput).should("have.value", "");

cy.get(usersSelector.passwordInput).clear();
cy.clearAndType(usersSelector.confirmPasswordInput, usersText.password);
cy.get(usersSelector.finishSetup).click();
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.passwordErrToast);
cy.get(usersSelector.passwordInput).should("have.value", "");
cy.get(usersSelector.confirmPasswordInput).should("have.value", usersText.password);

cy.clearAndType(usersSelector.passwordInput, usersText.password);
cy.clearAndType(usersSelector.confirmPasswordInput, usersText.mismatchPassword);
cy.get(usersSelector.finishSetup).click();
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.passwordMismatchToast);
cy.get(usersSelector.passwordInput).should("have.value", usersText.password);
cy.get(usersSelector.confirmPasswordInput).should("have.value", usersText.mismatchPassword);

cy.clearAndType(usersSelector.passwordInput, usersText.password);
cy.clearAndType(usersSelector.confirmPasswordInput, usersText.password);
cy.get(usersSelector.finishSetup).click();
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.swPasswordSuccessToast);
cy.url().should("include",path.loginPath);
});

it("should verify the new user account", ()=>{
cy.login(email,usersText.password);
cy.get(usersSelector.dropdownText).should('be.visible').and('have.text', "My workspace");
common.logout();

cy.appUILogin();
common.navigateToManageUsers();
cy.contains('td', email).parent().within(() => {
cy.get('td small').should("have.text", usersText.activeStatus);
});
});

it("Should verify the archive functionality",()=>{
cy.contains('td', email).parent().within(() => {
cy.get('td button').click();
});
cy.verifyToastMessage(commonSelectors.toastMessage,usersText.archivedToast);

cy.contains('td', email).parent().within(() => {
cy.get(usersSelector.userStatus, { timeout: 9000 }).should("have.text", usersText.archivedStatus);
});

common.logout();
cy.clearAndType(commonSelectors.emailField, email);
cy.clearAndType(commonSelectors.passwordField, usersText.password);
cy.get(commonSelectors.signInButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, commonText.loginErrorToast);

cy.appUILogin();
common.navigateToManageUsers();
cy.contains('td', email).parent().within(() => {
cy.get('td button').click();
});

cy.wait(2000);
cy.window().then(win => {
cy.stub(win, 'prompt').returns(win.prompt).as('copyToClipboardPrompt');
});
cy.contains('td', email).parent().within(() => {
cy.get('td img').click();
});
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.inviteCopiedToast);

cy.contains('td', email).parent().within(() => {
cy.get(usersSelector.userStatus, { timeout: 9000 }).should("have.text", usersText.invitedStatus);
});

cy.get('@copyToClipboardPrompt').then(prompt => {
common.logout();
cy.visit(prompt.args[0][1]);
cy.url().should("include",path.confirmInvite);
});

cy.get(usersSelector.confirmInvitePage).should("be.visible");
cy.get(usersSelector.pageLogo).should("be.visible");
cy.clearAndType(usersSelector.passwordInput, usersText.password);
cy.clearAndType(usersSelector.confirmPasswordInput, usersText.password);
cy.get(usersSelector.finishSetup).click();
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.swPasswordSuccessToast);
cy.url().should("include",path.loginPath);

cy.appUILogin();
common.navigateToManageUsers();
cy.contains('td', email).parent().within(() => {
cy.get('td small').should("have.text", usersText.activeStatus);
});
});
});
20 changes: 12 additions & 8 deletions docs/docs/user-authentication/general-settings.md
Expand Up @@ -5,21 +5,21 @@ title: General Settings

# Single Sign-On General Settings

Select `Manage SSO` from workspace options
- Select `Manage SSO` from workspace options

<div style={{textAlign: 'center'}}>
<div style={{textAlign: 'center'}}>

![ToolJet - SSO configs](/img/password-login/organization-menu.png)
![ToolJet - SSO configs](/img/password-login/organization-menu.png)

</div>
</div>

Select `General Settings`
- Select `General Settings`

<div style={{textAlign: 'center'}}>
<div style={{textAlign: 'center'}}>

![ToolJet - SSO configs](/img/sso/general/general-settings.png)
![ToolJet - SSO configs](/img/sso/general/general-settings.png)

</div>
</div>

## Enable Signup

Expand All @@ -28,3 +28,7 @@ You can enable/disable `Enable signup`. If it is enabled, new account will be cr
## Allowed domains

You can set allowed domains for SSO login, can add multiple domains comma separated. Allowed all domains by default.

## Login URL

You can use the login URL to login directly to the workspace. This will be hidden if Multi-Workspace is disabled.
67 changes: 67 additions & 0 deletions docs/docs/user-authentication/sso/azuread.md
@@ -0,0 +1,67 @@
---
id: azuread
title: AzureAD
---

# AzureAD Single Sign-on

:::info
To construct a Well Known URL refer this link :: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc
:::

- Open your organisation page and select `app registration`
<div style={{textAlign: 'center'}}>

![ToolJet - AzureAD app registration](/img/sso/azuread/azure-app-reg.png)

</div>

- Select `new registration`
<div style={{textAlign: 'center'}}>

![ToolJet - AzureAD app registration](/img/sso/azuread/select-new-reg-azure.png)

</div>

- Open your organisation page and select app registration.

- Enter name, select supported account type and enter the redirect URL which can be copied from `Manage SSO -> Open Id -> Redirect URL, click on register`.
<div style={{textAlign: 'center'}}>

![ToolJet - AzureAD app registration](/img/sso/azuread/azure-3.png)

</div>

- Application will be registered and will be able to view the details

- Configure Application (Client) ID as `client id` in Open Id configuration page.
<div style={{textAlign: 'center'}}>

![ToolJet - AzureAD app registration](/img/sso/azuread/azure-4-cred.png)

</div>

- Click on `Add certificate or secret` next to the **Client credentials**.

- Click on `+New Client Secret`
<div style={{textAlign: 'center'}}>

![ToolJet - AzureAD app registration](/img/sso/azuread/azure8.png)

</div>

- Give a description, set the expiry, and then click on the `Add` button.
<div style={{textAlign: 'center'}}>

![ToolJet - AzureAD app registration](/img/sso/azuread/azure7.png)

</div>

- Secret will be created, copy value and add it to the `client secret ` section of Open Id SSO config.

- You can brand the redirect page using the branding and properties option.
<div style={{textAlign: 'center'}}>

![ToolJet - AzureAD app registration](/img/sso/azuread/azure9.png)

</div>
54 changes: 54 additions & 0 deletions docs/docs/user-authentication/sso/okta.md
@@ -0,0 +1,54 @@
---
id: okta
title: Okta
---

# Okta Single Sign-on

- Sign in to [Okta developer console](https://developer.okta.com/)

- Go to the `Applications` section and click on the `Create App Integration`
<div style={{textAlign: 'center'}}>

![ToolJet - Okta create application](/img/sso/okta/create-app.png)

</div>

- Select `Sign-in method` as `OIDC - OpenID Connect` and `Application type` as `Web Application`. Go to the next step
<div style={{textAlign: 'center'}}>

![ToolJet - Okta create application](/img/sso/okta/create-app-s1.png)

</div>

- Enter `App integration name` and then enter `Sign-in redirect URIs` as `<YOUR-DOMAIN>/sso/okta`.
<div style={{textAlign: 'center'}}>

![ToolJet - Okta create application](/img/sso/okta/create-app-s2.png)

</div>

- Create application and configure `Client Credentials` in the UI.
<div style={{textAlign: 'center'}}>

![ToolJet - Okta create application](/img/sso/okta/create-app-s4.png)

</div>

- If you wish to show your application on Okta, edit the application and select `Login initiated by` section as `Either Okta or App`, set visibility according to your preference and `Login flow` should `Redirect to app to initiate login (OIDC Compliant)`.

<div style={{textAlign: 'center'}}>

![ToolJet - Okta create application](/img/sso/okta/create-app-s5.png)

</div>

:::info Change Grant type
To change the Login flow to `Redirect to app to initiate login (OIDC Compliant)`, its mandatory to change the `Grant type` - `Client acting on behalf of a user` section to `Implicit (hybrid)` and tick `Allow Access Token with implicit grant type`.
:::

- The Okta sign-in button will now be available in your ToolJet login screen.

:::info
To find Well Known URL refer this Link: https://developer.okta.com/docs/concepts/auth-servers/#org-authorization-server
:::

0 comments on commit 421298f

Please sign in to comment.