Merge branch 'release/v1.0.0' of https://github.com/ONLYOFFICE/DocSpace into release/v1.0.0

This commit is contained in:
Maria Sukhova 2023-04-18 14:31:20 +03:00
commit 73ffc81f24
16 changed files with 176 additions and 103 deletions

View File

@ -260,13 +260,13 @@ COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.Socket
CMD ["server.js", "ASC.Socket.IO"]
## ASC.SsoAuth ##
# FROM noderun AS ssoauth
# WORKDIR ${BUILD_PATH}/services/ASC.SsoAuth/
FROM noderun AS ssoauth
WORKDIR ${BUILD_PATH}/services/ASC.SsoAuth/
# COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
# COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.SsoAuth/service/ .
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.SsoAuth/service/ .
# CMD ["app.js", "ASC.SsoAuth"]
CMD ["app.js", "ASC.SsoAuth"]
## ASC.Studio.Notify ##
FROM dotnetrun AS studio_notify

View File

@ -106,12 +106,12 @@ services:
target: studio
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio:${DOCKER_TAG}"
# onlyoffice-ssoauth:
# build:
# context: ./
# dockerfile: "${DOCKERFILE}"
# target: ssoauth
# image: "${REPO}/${DOCKER_IMAGE_PREFIX}-ssoauth:${DOCKER_TAG}"
onlyoffice-ssoauth:
build:
context: ./
dockerfile: "${DOCKERFILE}"
target: ssoauth
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-ssoauth:${DOCKER_TAG}"
# onlyoffice-webhooks-service:
# build:

View File

@ -129,13 +129,13 @@ services:
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio:${DOCKER_TAG}"
container_name: ${STUDIO_HOST}
# onlyoffice-ssoauth:
# <<: *x-service-base
# image: "${REPO}/${DOCKER_IMAGE_PREFIX}-ssoauth:${DOCKER_TAG}"
# container_name: ${SSOAUTH_HOST}
# expose:
# - ${SERVICE_PORT}
# - "9834"
onlyoffice-ssoauth:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-ssoauth:${DOCKER_TAG}"
container_name: ${SSOAUTH_HOST}
expose:
- ${SERVICE_PORT}
- "9834"
# onlyoffice-webhooks-service:
# <<: *x-service-base
@ -168,7 +168,7 @@ services:
- onlyoffice-api
# - onlyoffice-api-system
- onlyoffice-studio
# - onlyoffice-ssoauth
- onlyoffice-ssoauth
environment:
- SERVICE_BACKUP=${SERVICE_BACKUP}
- SERVICE_FILES=${SERVICE_FILES}

View File

@ -29,16 +29,16 @@ namespace ASC.Geolocation;
[Scope]
public class GeolocationHelper
{
private readonly IDbContextFactory<CustomDbContext> _dbContextFactory;
private readonly CreatorDbContext _creatorDbContext;
private readonly ILogger<GeolocationHelper> _logger;
private readonly IHttpContextAccessor _httpContextAccessor;
public GeolocationHelper(
IDbContextFactory<CustomDbContext> dbContextFactory,
CreatorDbContext creatorDbContext,
ILogger<GeolocationHelper> logger,
IHttpContextAccessor httpContextAccessor)
{
_dbContextFactory = dbContextFactory;
_creatorDbContext = creatorDbContext;
_logger = logger;
_httpContextAccessor = httpContextAccessor;
}
@ -47,7 +47,7 @@ public class GeolocationHelper
{
try
{
using var dbContext = _dbContextFactory.CreateDbContext();
using var dbContext = _creatorDbContext.CreateDbContext<CustomDbContext>(nameConnectionString: "teamlabsite");
var ipformatted = FormatIP(ip);
var q = dbContext.DbipLocation
.Where(r => r.IPStart.CompareTo(ipformatted) <= 0)

View File

@ -136,20 +136,10 @@
"name": "default",
"connectionString": "Server=localhost;Database=docspace;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True;Connection Timeout=30;Maximum Pool Size=300;ConnectionReset=false",
"providerName": "MySql.Data.MySqlClient"
},
"postgre": {
"name": "postgre",
"connectionString": "Host=localhost;Port=5432;Database=docspace;Username=postgres;Password=dev;",
"providerName": "Npgsql"
},
"mysql": {
"name": "mysql",
"connectionString": "Server=localhost;Database=docspace;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True;Connection Timeout=30;Maximum Pool Size=300;ConnectionReset=false",
"providerName": "MySql.Data.MySqlClient"
},
"teamlabsite": {
"name": "docspacesite",
"connectionString": "Server=localhost;Database=docspacesite;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True;Connection Timeout=30;Maximum Pool Size=300;ConnectionReset=false",
"name": "teamlabsite",
"connectionString": "Server=localhost;Database=teamlabsite;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True;Connection Timeout=30;Maximum Pool Size=300;ConnectionReset=false",
"providerName": "MySql.Data.MySqlClient"
}
},

View File

@ -191,7 +191,9 @@ server {
location ~* /(authentication|modules|portal|security|settings|smtpsettings|capabilities|thirdparty|encryption|feed) {
proxy_pass http://127.0.0.1:5000;
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
location ~* portal/(.*)(backup|restore)(.*) {
rewrite (.*)/portal/(.*) $1/backup/$2 break;
proxy_redirect off;

View File

@ -17,6 +17,7 @@
"HideAuthPage": "Hide auth page",
"LogoutEndpointUrl": "IdP Single Logout Endpoint URL",
"LogoutEndpointUrlTooltip": "The URL used for the single logout on the Service provider side",
"MetadataLoadError": "Metadata file not transferred",
"NameIDFormat": "NameId Format",
"NewCertificate": "New Certificate",
"OpenCertificate": "Public Certificate",

View File

@ -82,6 +82,14 @@ export const QuotaBarTypes = Object.freeze({
export const BINDING_POST = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";
export const BINDING_REDIRECT =
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect";
export const SSO_NAME_ID_FORMAT =
"urn:oasis:names:tc:SAML:2.0:nameid-format:transient";
export const SSO_GIVEN_NAME = "givenName";
export const SSO_SN = "sn";
export const SSO_EMAIL = "email";
export const SSO_LOCATION = "location";
export const SSO_TITLE = "title";
export const SSO_PHONE = "phone";
export const DEFAULT_SELECT_TIMEZONE = {
key: "UTC",

View File

@ -344,12 +344,6 @@ class PureHome extends React.Component {
this.props.setHeaderVisible(this.props.isHeaderVisible);
}
if (isProgressFinished !== prevProps.isProgressFinished) {
setTimeout(() => {
console.log("render refresh", refreshFiles());
}, 100);
}
if (
isProgressFinished &&
itemsSelectionTitle &&

View File

@ -10,12 +10,14 @@ import Text from "@docspace/components/text";
import Checkbox from "@docspace/components/checkbox";
import SsoFormField from "./sub-components/SsoFormField";
const GIVENNAME = "givenName";
const SN = "sn";
const EMAIL = "email";
const LOCATION = "location";
const TITLE = "title";
const PHONE = "phone";
import {
SSO_GIVEN_NAME,
SSO_SN,
SSO_EMAIL,
SSO_LOCATION,
SSO_TITLE,
SSO_PHONE,
} from "SRC_DIR/helpers/constants";
const FieldMapping = (props) => {
const { t } = useTranslation(["SingleSignOn", "Common"]);
@ -60,7 +62,7 @@ const FieldMapping = (props) => {
<SsoFormField
labelText={t("Common:FirstName")}
name="firstName"
placeholder={GIVENNAME}
placeholder={SSO_GIVEN_NAME}
tabIndex={16}
value={firstName}
hasError={firstNameHasError}
@ -69,7 +71,7 @@ const FieldMapping = (props) => {
<SsoFormField
labelText={t("Common:LastName")}
name="lastName"
placeholder={SN}
placeholder={SSO_SN}
tabIndex={17}
value={lastName}
hasError={lastNameHasError}
@ -78,16 +80,16 @@ const FieldMapping = (props) => {
<SsoFormField
labelText={t("Common:Email")}
name="email"
placeholder={EMAIL}
placeholder={SSO_EMAIL}
tabIndex={18}
value={email}
hasError={emailHasError}
/>
<SsoFormField
{/*<SsoFormField
labelText={t("Common:Location")}
name="location"
placeholder={LOCATION}
placeholder={SSO_LOCATION}
tabIndex={19}
value={location}
hasError={locationHasError}
@ -96,7 +98,7 @@ const FieldMapping = (props) => {
<SsoFormField
labelText={t("Common:Title")}
name="title"
placeholder={TITLE}
placeholder={SSO_TITLE}
tabIndex={20}
value={title}
hasError={titleHasError}
@ -105,11 +107,11 @@ const FieldMapping = (props) => {
<SsoFormField
labelText={t("Common:Phone")}
name="phone"
placeholder={PHONE}
placeholder={SSO_PHONE}
tabIndex={21}
value={phone}
hasError={phoneHasError}
/>
/>*/}
<FieldContainer
className="advanced-block"

View File

@ -61,17 +61,17 @@ const IdpSettings = (props) => {
<SsoFormField
labelText={t("SignOnEndpointUrl")}
name={ssoBinding.includes("POST") ? "ssoUrlPost" : "ssoUrlRedirect"}
name={ssoBinding?.includes("POST") ? "ssoUrlPost" : "ssoUrlRedirect"}
placeholder={
ssoBinding.includes("POST")
ssoBinding?.includes("POST")
? "https://idpservice/SSO/POST"
: "https://idpservice/SSO/REDIRECT"
}
tabIndex={7}
tooltipContent={t("SignOnEndpointUrlTooltip")}
value={ssoBinding.includes("POST") ? ssoUrlPost : ssoUrlRedirect}
value={ssoBinding?.includes("POST") ? ssoUrlPost : ssoUrlRedirect}
hasError={
ssoBinding.includes("POST")
ssoBinding?.includes("POST")
? ssoUrlPostHasError
: ssoUrlRedirectHasError
}
@ -101,17 +101,17 @@ const IdpSettings = (props) => {
<SsoFormField
labelText={t("LogoutEndpointUrl")}
name={sloBinding.includes("POST") ? "sloUrlPost" : "sloUrlRedirect"}
name={sloBinding?.includes("POST") ? "sloUrlPost" : "sloUrlRedirect"}
placeholder={
sloBinding.includes("POST")
sloBinding?.includes("POST")
? "https://idpservice/SLO/POST"
: "https://idpservice/SLO/REDIRECT"
}
tabIndex={9}
tooltipContent={t("LogoutEndpointUrlTooltip")}
value={sloBinding.includes("POST") ? sloUrlPost : sloUrlRedirect}
value={sloBinding?.includes("POST") ? sloUrlPost : sloUrlRedirect}
hasError={
ssoBinding.includes("POST")
ssoBinding?.includes("POST")
? sloUrlPostHasError
: sloUrlRedirectHasError
}

View File

@ -18,6 +18,7 @@ const SubmitResetButtons = (props) => {
isSubmitLoading,
hasErrors,
hasChanges,
isLoadingXml,
} = props;
return (
@ -29,7 +30,7 @@ const SubmitResetButtons = (props) => {
primary
size="small"
tabIndex={23}
isDisabled={hasErrors || !hasChanges}
isDisabled={hasErrors || !hasChanges || isLoadingXml}
isLoading={isSubmitLoading}
/>
<Button
@ -37,7 +38,7 @@ const SubmitResetButtons = (props) => {
onClick={isSsoEnabled ? openResetModal : resetForm}
size="small"
tabIndex={24}
isDisabled={isSubmitLoading}
isDisabled={isSubmitLoading || isLoadingXml}
/>
{confirmationResetModal && <ResetConfirmationModal />}
</Box>
@ -54,6 +55,7 @@ export default inject(({ ssoStore }) => {
isSubmitLoading,
hasErrors,
hasChanges,
isLoadingXml,
} = ssoStore;
return {
@ -65,5 +67,6 @@ export default inject(({ ssoStore }) => {
isSubmitLoading,
hasErrors,
hasChanges,
isLoadingXml,
};
})(observer(SubmitResetButtons));

View File

@ -17,6 +17,9 @@ import ToggleSSO from "./sub-components/ToggleSSO";
import BreakpointWarning from "SRC_DIR/components/BreakpointWarning";
const SERVICE_PROVIDER_SETTINGS = "serviceProviderSettings";
const SP_METADATA = "spMetadata";
const SingleSignOn = (props) => {
const { load, serviceProviderSettings, spMetadata, isSSOAvailable } = props;
const { t } = useTranslation(["SingleSignOn", "Settings"]);
@ -34,7 +37,7 @@ const SingleSignOn = (props) => {
<HideButton
text={t("ServiceProviderSettings")}
label={t("ServiceProviderSettings")}
label={SERVICE_PROVIDER_SETTINGS}
value={serviceProviderSettings}
isDisabled={!isSSOAvailable}
/>
@ -55,7 +58,7 @@ const SingleSignOn = (props) => {
<HideButton
text={t("SpMetadata")}
label={t("SpMetadata")}
label={SP_METADATA}
value={spMetadata}
isDisabled={!isSSOAvailable}
/>

View File

@ -38,6 +38,10 @@ const UploadXML = (props) => {
disabled: !enableSso || uploadXmlUrl.trim().length === 0 || isLoadingXml,
};
const onUploadClick = () => {
uploadByUrl(t);
};
return (
<FieldContainer
className="xml-input"
@ -60,7 +64,7 @@ const UploadXML = (props) => {
isDisabled={
!enableSso || uploadXmlUrl.trim().length === 0 || isLoadingXml
}
onClick={uploadByUrl}
onClick={onUploadClick}
tabIndex={2}
/>

View File

@ -9,7 +9,17 @@ import {
validateCerts,
} from "@docspace/common/api/settings";
import toastr from "@docspace/components/toast/toastr";
import { BINDING_POST, BINDING_REDIRECT } from "../helpers/constants";
import {
BINDING_POST,
BINDING_REDIRECT,
SSO_GIVEN_NAME,
SSO_SN,
SSO_EMAIL,
SSO_LOCATION,
SSO_TITLE,
SSO_PHONE,
SSO_NAME_ID_FORMAT,
} from "../helpers/constants";
import isEqual from "lodash/isEqual";
class SsoFormStore {
@ -31,7 +41,7 @@ class SsoFormStore {
sloUrlPost = "";
sloUrlRedirect = "";
sloBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";
nameIdFormat = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient";
nameIdFormat = SSO_NAME_ID_FORMAT;
idpCertificate = "";
idpPrivateKey = null;
@ -64,12 +74,12 @@ class SsoFormStore {
// spVerifyAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
// Field mapping
firstName = "";
lastName = "";
email = "";
location = "";
title = "";
phone = "";
firstName = SSO_GIVEN_NAME;
lastName = SSO_SN;
email = SSO_EMAIL;
location = SSO_LOCATION;
title = SSO_TITLE;
phone = SSO_PHONE;
hideAuthPage = false;
@ -229,7 +239,7 @@ class SsoFormStore {
this.confirmationResetModal = false;
};
uploadByUrl = async () => {
uploadByUrl = async (t) => {
const data = { url: this.uploadXmlUrl };
try {
@ -239,7 +249,7 @@ class SsoFormStore {
this.isLoadingXml = false;
} catch (err) {
this.isLoadingXml = false;
toastr.error(err);
toastr.error(t("MetadataLoadError"));
console.error(err);
}
};
@ -474,41 +484,97 @@ class SsoFormStore {
}
};
getPropValue(obj, propName) {
let value = "";
if (!obj) return value;
if (obj.hasOwnProperty(propName)) return obj[propName];
if (
obj.hasOwnProperty("binding") &&
obj.hasOwnProperty("location") &&
obj["binding"] == propName
)
return obj["location"];
if (Array.isArray(obj)) {
obj.forEach(function (item) {
if (item.hasOwnProperty(propName)) {
value = item[propName];
return;
}
if (
item.hasOwnProperty("binding") &&
item.hasOwnProperty("location") &&
item["binding"] == propName
) {
value = item["location"];
return;
}
});
}
return value;
}
includePropertyValue(obj, value) {
let props = Object.getOwnPropertyNames(obj);
for (let i = 0; i < props.length; i++) {
if (obj[props[i]] === value) return true;
}
return false;
}
setFieldsFromMetaData = async (meta) => {
if (meta.entityID) {
this.entityId = meta.entityID;
this.entityId = meta.entityID || "";
}
if (meta.singleSignOnService) {
this.ssoUrlPost =
meta.singleSignOnService[
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
];
this.ssoUrlRedirect =
meta.singleSignOnService[
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
];
this.ssoUrlPost = this.getPropValue(
meta.singleSignOnService,
BINDING_POST
);
this.ssoUrlRedirect = this.getPropValue(
meta.singleSignOnService,
BINDING_REDIRECT
);
}
if (meta.singleLogoutService) {
this.sloBinding = meta.singleLogoutService.binding;
if (
meta.singleLogoutService.binding ===
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
) {
this.sloUrlRedirect = meta.singleLogoutService.location;
if (meta.singleLogoutService.binding) {
this.sloBinding = meta.singleLogoutService.binding;
}
if (
meta.singleLogoutService.binding ===
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
) {
this.sloUrlPost = meta.singleLogoutService.location;
}
this.sloUrlRedirect = this.getPropValue(
meta.singleLogoutService,
BINDING_REDIRECT
);
this.sloUrlPost = this.getPropValue(
meta.singleLogoutService,
BINDING_POST
);
}
if (meta.nameIDFormat) {
this.nameIdFormat = meta.nameIDFormat;
if (Array.isArray(meta.nameIDFormat)) {
let formats = meta.nameIDFormat.filter(function (format) {
return this.includePropertyValue(SSO_NAME_ID_FORMAT, format);
});
if (formats.length) {
this.nameIdFormat = formats[0];
}
} else {
if (includePropertyValue(SSO_NAME_ID_FORMAT, meta.nameIDFormat)) {
this.nameIdFormat = meta.nameIDFormat;
}
}
}
if (meta.certificate) {

View File

@ -58,7 +58,7 @@ const LoginForm: React.FC<ILoginFormProps> = ({
const inputRef = useRef<HTMLInputElement>(null);
const { t } = useTranslation(["Login", "Common"]);
const { t, ready } = useTranslation(["Login", "Common"]);
const { message, confirmedEmail } = match || {
message: "",
@ -107,7 +107,7 @@ const LoginForm: React.FC<ILoginFormProps> = ({
const text = `${messageEmailConfirmed} ${messageAuthorize}`;
confirmedEmail && toastr.success(text);
confirmedEmail && ready && toastr.success(text);
focusInput();