[next] Admin Configure (#2076)

* feat: Add RadioButton and CheckBox

* feat: configure facebook and google auth

* feat: configure sso, localAuth and displayName + some tests

* test: add integration tests for configure auth

* test: more integration tests

* feat: add oidc support

* test: add oidc integration test

* feat: generate sso key initially

* fix: import fetchQuery from correct package

* fix: admin url

* fix: set timezone to utc when testing

* refactor: improve route config

* fix: remove obsolete line

* fix: clientMutationId increment

* fix: oidc only create when enabled

* fix: copy

* test: update snapshots

* feat: fixed graphql logging extension

* Update src/locales/en-US/admin.ftl

Co-Authored-By: cvle <vinh@wikiwi.io>

* Apply suggestions from code review

Co-Authored-By: cvle <vinh@wikiwi.io>

* test: update snapshots

* fix: change Local Auth to Email Authentication

* fix: copy updates
This commit is contained in:
Kiwi
2018-11-19 22:47:32 +00:00
committed by Wyatt Johnson
parent 3f949b3712
commit 05350d651f
215 changed files with 7774 additions and 939 deletions
@@ -1,6 +1,16 @@
import { formatApolloErrors } from "apollo-server-errors";
import { GraphQLError } from "graphql";
import { GraphQLExtension, GraphQLResponse } from "graphql-extensions";
import {
DocumentNode,
ExecutionArgs,
GraphQLError,
OperationDefinitionNode,
} from "graphql";
import {
EndHandler,
GraphQLExtension,
GraphQLResponse,
} from "graphql-extensions";
import now from "performance-now";
import CommonContext from "talk-server/graph/common/context";
@@ -15,11 +25,49 @@ export class LoggerExtension implements GraphQLExtension<CommonContext> {
return err;
};
public requestDidStart(o: {
operationName?: string;
context: CommonContext;
}) {
o.context.logger.debug({ operationName: o.operationName }, "graphql query");
private getOperationMetadata(doc: DocumentNode) {
if (doc.kind === "Document") {
const operationDefinition = doc.definitions.find(
({ kind }) => kind === "OperationDefinition"
) as OperationDefinitionNode | undefined;
if (operationDefinition) {
let operationName: string | undefined;
if (operationDefinition.name) {
operationName = operationDefinition.name.value;
}
return {
operationName,
operation: operationDefinition.operation,
};
}
}
return {};
}
public executionDidStart(o: {
executionArgs: ExecutionArgs;
}): EndHandler | void {
// Only try to log things if the context is provided.
if (o.executionArgs.contextValue) {
// Grab the start time so we can calculate the time it takes to execute
// the graph query.
const startTime = now();
return () => {
// Compute the end time.
const responseTime = Math.round(now() - startTime);
// Log out the details of the request.
o.executionArgs.contextValue.logger.debug(
{
responseTime,
...this.getOperationMetadata(o.executionArgs.document),
},
"graphql query"
);
};
}
}
public willSendResponse(o: {
@@ -0,0 +1,26 @@
import { constructTenantURL, reconstructURL } from "talk-server/app/url";
import {
GQLFacebookAuthIntegration,
GQLFacebookAuthIntegrationTypeResolver,
} from "talk-server/graph/tenant/schema/__generated__/types";
const FacebookAuthIntegration: GQLFacebookAuthIntegrationTypeResolver<
GQLFacebookAuthIntegration
> = {
callbackURL: (integration, args, ctx) => {
const path = `/api/tenant/auth/facebook/callback`;
// If the request is available, then prefer it over building from the tenant
// as the tenant does not include the port number. This should only really
// be a problem if the graph API is called internally.
if (ctx.req) {
return reconstructURL(ctx.req, path);
}
// Note that when constructing the callback url with the tenant, the port
// information is lost.
return constructTenantURL(ctx.config, ctx.tenant, path);
},
};
export default FacebookAuthIntegration;
@@ -0,0 +1,26 @@
import { constructTenantURL, reconstructURL } from "talk-server/app/url";
import {
GQLGoogleAuthIntegration,
GQLGoogleAuthIntegrationTypeResolver,
} from "talk-server/graph/tenant/schema/__generated__/types";
const GoogleAuthIntegration: GQLGoogleAuthIntegrationTypeResolver<
GQLGoogleAuthIntegration
> = {
callbackURL: (integration, args, ctx) => {
const path = `/api/tenant/auth/google/callback`;
// If the request is available, then prefer it over building from the tenant
// as the tenant does not include the port number. This should only really
// be a problem if the graph API is called internally.
if (ctx.req) {
return reconstructURL(ctx.req, path);
}
// Note that when constructing the callback url with the tenant, the port
// information is lost.
return constructTenantURL(ctx.config, ctx.tenant, path);
},
};
export default GoogleAuthIntegration;
@@ -6,6 +6,8 @@ import { GQLResolver } from "talk-server/graph/tenant/schema/__generated__/types
import AuthIntegrations from "./auth_integrations";
import Comment from "./comment";
import CommentCounts from "./comment_counts";
import FacebookAuthIntegration from "./facebook_auth_integration";
import GoogleAuthIntegration from "./google_auth_integration";
import Mutation from "./mutation";
import OIDCAuthIntegration from "./oidc_auth_integration";
import Profile from "./profile";
@@ -20,6 +22,8 @@ const Resolvers: GQLResolver = {
Cursor,
Mutation,
OIDCAuthIntegration,
FacebookAuthIntegration,
GoogleAuthIntegration,
Profile,
Query,
Time,
@@ -275,7 +275,7 @@ type LocalAuthIntegration {
displayed. If the value of targetFilter is null, then the authentication
integration should be displayed in all targets.
"""
targetFilter: AuthenticationTargetFilter
targetFilter: AuthenticationTargetFilter!
}
##########################
@@ -301,7 +301,7 @@ type SSOAuthIntegration {
displayed. If the value of targetFilter is null, then the authentication
integration should be displayed in all targets.
"""
targetFilter: AuthenticationTargetFilter
targetFilter: AuthenticationTargetFilter!
"""
key is the secret that is used to sign tokens.
@@ -385,7 +385,7 @@ type OIDCAuthIntegration {
displayed. If the value of targetFilter is null, then the authentication
integration should be displayed in all targets.
"""
targetFilter: AuthenticationTargetFilter
targetFilter: AuthenticationTargetFilter!
"""
name is the label assigned to reference the provider of the OIDC integration,
@@ -462,10 +462,17 @@ type GoogleAuthIntegration {
displayed. If the value of targetFilter is null, then the authentication
integration should be displayed in all targets.
"""
targetFilter: AuthenticationTargetFilter
targetFilter: AuthenticationTargetFilter!
clientID: String @auth(roles: [ADMIN])
clientSecret: String @auth(roles: [ADMIN])
"""
callbackURL is the URL that the user should be redirected to in order to start
the authentication flow. This field is not stored, and is instead computed from
the Tenant.
"""
callbackURL: String!
}
##########################
@@ -486,10 +493,17 @@ type FacebookAuthIntegration {
displayed. If the value of targetFilter is null, then the authentication
integration should be displayed in all targets.
"""
targetFilter: AuthenticationTargetFilter
targetFilter: AuthenticationTargetFilter!
clientID: String @auth(roles: [ADMIN])
clientSecret: String @auth(roles: [ADMIN])
"""
callbackURL is the URL that the user should be redirected to in order to start
the authentication flow. This field is not stored, and is instead computed from
the Tenant.
"""
callbackURL: String!
}
##########################
@@ -530,7 +544,7 @@ type Auth {
displayName contains configuration related to the use of Display Names across
AuthIntegrations.
"""
displayName: AuthDisplayNameConfiguration @auth(roles: [ADMIN])
displayName: AuthDisplayNameConfiguration! @auth(roles: [ADMIN])
}
################################################################################
@@ -1598,11 +1612,25 @@ input SettingsAuthIntegrationsInput {
facebook: SettingsFacebookAuthIntegrationInput
}
input SettingsAuthDisplayNameInput {
"""
enabled when true will allow the display name to be used by other
AuthIntegrations.
"""
enabled: Boolean!
}
"""
Auth contains all the settings related to authentication and
authorization.
"""
input SettingsAuthInput {
"""
"
displayName allows configuration related to Display Names.
"""
displayName: SettingsAuthDisplayNameInput
"""
integrations are the set of configurations for the variations of
authentication solutions.
@@ -2090,6 +2118,24 @@ type RegenerateSSOKeyPayload {
##################
input CreateOIDCAuthIntegrationConfigurationInput {
"""
enabled, when true, allows the integration to be enabled.
"""
enabled: Boolean
"""
allowRegistration when true will allow users that have not signed up
before with this authentication integration to sign up.
"""
allowRegistration: Boolean
"""
targetFilter will restrict where the authentication integration should be
displayed. If the value of targetFilter is null, then the authentication
integration should be displayed in all targets.
"""
targetFilter: SettingsAuthenticationTargetFilterInput
"""
name is the label assigned to reference the provider of the OIDC integration,
and will be used in situations where the name of the provider needs to be