From fbc8fb115497ad1abaa76df914f52f7672ec2a83 Mon Sep 17 00:00:00 2001 From: Sarah Sporck Date: Fri, 2 Dec 2022 12:16:49 +0100 Subject: [PATCH] 535: log failed login requests --- .vscode/tasks.json | 98 +++++++++++++++---- .../schema/SignInMutationService.kt | 15 ++- .../common/webservice/GraphQLContext.kt | 1 + .../common/webservice/GraphQLHandler.kt | 16 ++- 4 files changed, 107 insertions(+), 23 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index bce2dfd9b..2152d9cb7 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,8 +7,14 @@ "label": "import", "type": "shell", "command": "${workspaceFolder}/backend/gradlew", - "options": { "cwd": "${workspaceFolder}/backend" }, - "args": ["run", "--args", "import"], + "options": { + "cwd": "${workspaceFolder}/backend" + }, + "args": [ + "run", + "--args", + "import" + ], "problemMatcher": [ "$gradle" ] @@ -17,8 +23,17 @@ "label": "Run Backend", "type": "shell", "command": "${workspaceFolder}/backend/gradlew", - "options": { "cwd": "${workspaceFolder}/backend", "env": { "JWT_SECRET": "Hello World!"} }, - "args": ["run", "--args", "execute"], + "options": { + "cwd": "${workspaceFolder}/backend", + "env": { + "JWT_SECRET": "Hello World!" + } + }, + "args": [ + "run", + "--args", + "execute" + ], "problemMatcher": [ "$gradle" ] @@ -27,8 +42,14 @@ "label": "Run Frontend", "type": "shell", "command": "fvm", - "options": { "cwd": "${workspaceFolder}/frontend" }, - "args": ["flutter", "run", "--dart-define=environment=local"], + "options": { + "cwd": "${workspaceFolder}/frontend" + }, + "args": [ + "flutter", + "run", + "--dart-define=environment=local" + ], "problemMatcher": [ "$gradle" ] @@ -37,8 +58,13 @@ "label": "Create Admin Account", "type": "shell", "command": "${workspaceFolder}/backend/gradlew", - "options": { "cwd": "${workspaceFolder}/backend" }, - "args": ["run", "--args=\"create-admin nuernberg.sozialpass.app REGION_MANAGER region_n@example.com Administrator! 9\""], + "options": { + "cwd": "${workspaceFolder}/backend" + }, + "args": [ + "run", + "--args=\"create-admin nuernberg.sozialpass.app REGION_MANAGER region_n@example.com Administrator! 9\"" + ], "problemMatcher": [ "$gradle" ] @@ -47,8 +73,13 @@ "label": "Generate React GraphQL Client", "type": "shell", "command": "npm", - "options": { "cwd": "${workspaceFolder}/administration" }, - "args": ["run", "generate-graphql"], + "options": { + "cwd": "${workspaceFolder}/administration" + }, + "args": [ + "run", + "generate-graphql" + ], "problemMatcher": [ "$gradle" ] @@ -57,8 +88,13 @@ "label": "GraphQL Schema Export", "type": "shell", "command": "${workspaceFolder}/backend/gradlew", - "options": { "cwd": "${workspaceFolder}/backend" }, - "args": ["run", "--args=\"graphql-export ../specs/backend-api.graphql\""], + "options": { + "cwd": "${workspaceFolder}/backend" + }, + "args": [ + "run", + "--args=\"graphql-export ../specs/backend-api.graphql\"" + ], "problemMatcher": [ "$gradle" ] @@ -67,22 +103,48 @@ "label": "Format", "type": "shell", "command": "fvm", - "options": { "cwd": "${workspaceFolder}/frontend" }, - "args": ["flutter", "format", "-l", "120", "."], + "options": { + "cwd": "${workspaceFolder}/frontend" + }, + "args": [ + "flutter", + "format", + "-l", + "120", + "." + ] }, { "label": "Select bayern", "type": "shell", "command": "fvm", - "options": { "cwd": "${workspaceFolder}/frontend" }, - "args": ["flutter", "pub", "run", "build_runner", "build", "--delete-conflicting-outputs", "--define", "\"df_build_config=name=bayern\""], + "options": { + "cwd": "${workspaceFolder}/frontend" + }, + "args": [ + "flutter", + "pub", + "run", + "build_runner", + "build", + "--delete-conflicting-outputs", + "--define", + "\"df_build_config=name=bayern\"" + ] }, { "label": "Format backend", "type": "shell", "command": "${workspaceFolder}/backend/gradlew", - "options": { "cwd": "${workspaceFolder}/backend" }, - "args": ["ktlintformat"] + "options": { + "cwd": "${workspaceFolder}/backend" + }, + "args": [ + "ktlintformat" + ], + "problemMatcher": [ + "$gradle" + ] } ] } \ No newline at end of file diff --git a/backend/src/main/kotlin/app/ehrenamtskarte/backend/auth/webservice/schema/SignInMutationService.kt b/backend/src/main/kotlin/app/ehrenamtskarte/backend/auth/webservice/schema/SignInMutationService.kt index ef8bc745b..722c1b793 100644 --- a/backend/src/main/kotlin/app/ehrenamtskarte/backend/auth/webservice/schema/SignInMutationService.kt +++ b/backend/src/main/kotlin/app/ehrenamtskarte/backend/auth/webservice/schema/SignInMutationService.kt @@ -6,17 +6,28 @@ import app.ehrenamtskarte.backend.auth.webservice.schema.types.Administrator import app.ehrenamtskarte.backend.auth.webservice.schema.types.AuthData import app.ehrenamtskarte.backend.auth.webservice.schema.types.Role import app.ehrenamtskarte.backend.auth.webservice.schema.types.SignInPayload +import app.ehrenamtskarte.backend.common.webservice.GraphQLContext import com.expediagroup.graphql.generator.annotations.GraphQLDescription import com.expediagroup.graphql.generator.exceptions.GraphQLKotlinException +import graphql.schema.DataFetchingEnvironment import org.jetbrains.exposed.sql.transactions.transaction +import org.slf4j.LoggerFactory @Suppress("unused") class SignInMutationService { @GraphQLDescription("Signs in an administrator") - fun signIn(project: String, authData: AuthData): SignInPayload { + fun signIn(project: String, authData: AuthData, dfe: DataFetchingEnvironment): SignInPayload { + val logger = LoggerFactory.getLogger(SignInMutationService::class.java) + val administratorEntity = transaction { AdministratorsRepository.findByAuthData(project, authData.email, authData.password) - } ?: throw GraphQLKotlinException("Invalid credentials") + } + if (administratorEntity == null) { + val context = dfe.getContext() + logger.info("${context.remoteIp} ${authData.email} failed to log in") + throw GraphQLKotlinException("Invalid credentials") + } + val role = Role.fromDbValue(administratorEntity.role) ?: throw GraphQLKotlinException("Invalid role.") val administrator = Administrator( administratorEntity.id.value, diff --git a/backend/src/main/kotlin/app/ehrenamtskarte/backend/common/webservice/GraphQLContext.kt b/backend/src/main/kotlin/app/ehrenamtskarte/backend/common/webservice/GraphQLContext.kt index 8042c811c..33da7700b 100644 --- a/backend/src/main/kotlin/app/ehrenamtskarte/backend/common/webservice/GraphQLContext.kt +++ b/backend/src/main/kotlin/app/ehrenamtskarte/backend/common/webservice/GraphQLContext.kt @@ -10,6 +10,7 @@ data class GraphQLContext( val applicationData: File, val jwtPayload: JwtPayload?, val files: List, + val remoteIp: String, val backendConfiguration: BackendConfiguration ) : GraphQLContext { diff --git a/backend/src/main/kotlin/app/ehrenamtskarte/backend/common/webservice/GraphQLHandler.kt b/backend/src/main/kotlin/app/ehrenamtskarte/backend/common/webservice/GraphQLHandler.kt index 354694af5..27ef7e580 100644 --- a/backend/src/main/kotlin/app/ehrenamtskarte/backend/common/webservice/GraphQLHandler.kt +++ b/backend/src/main/kotlin/app/ehrenamtskarte/backend/common/webservice/GraphQLHandler.kt @@ -77,6 +77,14 @@ class GraphQLHandler( } } + private fun getIpAdress(context: Context): String { + val xRealIp = context.header("X-Real-IP") + val xForwardedFor = context.header("X-Forwarded-For") + val remoteAddress = context.req().remoteAddr + + return listOf(xRealIp, xForwardedFor, remoteAddress).firstNotNullOf { it } + } + /** * Get any errors and data from [executionResult]. */ @@ -109,9 +117,9 @@ class GraphQLHandler( return result } - private fun getGraphQLContext(context: Context, files: List, applicationData: File) = + private fun getGraphQLContext(context: Context, files: List, remoteIp: String, applicationData: File) = try { - GraphQLContext(applicationData, JwtService.verifyRequest(context), files, backendConfiguration) + GraphQLContext(applicationData, JwtService.verifyRequest(context), files, remoteIp, backendConfiguration) } catch (e: Exception) { when (e) { is JWTDecodeException, is AlgorithmMismatchException, is SignatureVerificationException, @@ -119,6 +127,7 @@ class GraphQLHandler( applicationData, null, files, + remoteIp, backendConfiguration ) @@ -133,7 +142,8 @@ class GraphQLHandler( // Execute the query against the schema try { val (payload, files) = getPayload(context) - val graphQLContext = getGraphQLContext(context, files, applicationData) + val remoteIp = getIpAdress(context) + val graphQLContext = getGraphQLContext(context, files, remoteIp, applicationData) val variables = payload.getOrDefault("variables", emptyMap()) as Map? val executionInput =