diff --git a/application/confidentialClient/.gitignore b/application/confidentialClient/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..549e00a2a96fa9d7c5dbc9859664a78d980158c2 --- /dev/null +++ b/application/confidentialClient/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/application/confidentialClient/.mvn/wrapper/maven-wrapper.jar b/application/confidentialClient/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..bf82ff01c6cdae4a1bb754a6e062954d77ac5c11 Binary files /dev/null and b/application/confidentialClient/.mvn/wrapper/maven-wrapper.jar differ diff --git a/application/confidentialClient/.mvn/wrapper/maven-wrapper.properties b/application/confidentialClient/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..ca5ab4bab121c408ae246f6ef5fae23b58db2d65 --- /dev/null +++ b/application/confidentialClient/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar diff --git a/application/confidentialClient/Dockerfile b/application/confidentialClient/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..b4c5e3648ad8bbd3e87f9dffd665ddb638cfdff7 --- /dev/null +++ b/application/confidentialClient/Dockerfile @@ -0,0 +1,3 @@ +FROM docker.io/library/eclipse-temurin:17-jre-focal +COPY ./target/confidentialClient-0.0.1-SNAPSHOT.jar /app.jar +ENTRYPOINT ["java", "-jar", "/app.jar"] \ No newline at end of file diff --git a/application/confidentialClient/mvnw b/application/confidentialClient/mvnw new file mode 100644 index 0000000000000000000000000000000000000000..8a8fb2282df5b8f7263470a5a2dc0e196f35f35f --- /dev/null +++ b/application/confidentialClient/mvnw @@ -0,0 +1,316 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`\\unset -f command; \\command -v java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/application/confidentialClient/mvnw.cmd b/application/confidentialClient/mvnw.cmd new file mode 100644 index 0000000000000000000000000000000000000000..1d8ab018eaf11d9b3a4a90e7818ace373dfbb380 --- /dev/null +++ b/application/confidentialClient/mvnw.cmd @@ -0,0 +1,188 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/application/confidentialClient/pom.xml b/application/confidentialClient/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..3f2d61e409c031bc503ce4107279e52fe3be257a --- /dev/null +++ b/application/confidentialClient/pom.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.fuseri</groupId> + <artifactId>sprachschulsystem</artifactId> + <version>0.0.1-SNAPSHOT</version> + </parent> + <groupId>org.fuseri</groupId> + <artifactId>confidentialClient</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>confidentialClient</name> + <description>confidentialClient</description> + <properties> + <java.version>17</java.version> + </properties> + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-oauth2-client</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.fuseri</groupId> + <artifactId>models</artifactId> + <version>0.0.1-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webflux</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <configuration> + <skip>false</skip> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/application/confidentialClient/src/main/java/org/fuseri/confidentialclient/AuthClient.java b/application/confidentialClient/src/main/java/org/fuseri/confidentialclient/AuthClient.java new file mode 100644 index 0000000000000000000000000000000000000000..28e51ecfc87a9137169cccb96990160ba1e80948 --- /dev/null +++ b/application/confidentialClient/src/main/java/org/fuseri/confidentialclient/AuthClient.java @@ -0,0 +1,15 @@ +package org.fuseri.confidentialclient; + +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class AuthClient { + + @GetMapping("/token") + public String getToken( @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oauth2Client) { + return oauth2Client.getAccessToken().getTokenValue(); + } +} diff --git a/application/confidentialClient/src/main/java/org/fuseri/confidentialclient/ConfidentialClientApplication.java b/application/confidentialClient/src/main/java/org/fuseri/confidentialclient/ConfidentialClientApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..7634acfea3337bfc789c35a5dfdeeec85931dcdd --- /dev/null +++ b/application/confidentialClient/src/main/java/org/fuseri/confidentialclient/ConfidentialClientApplication.java @@ -0,0 +1,89 @@ +package org.fuseri.confidentialclient; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.fuseri.model.dto.user.UserCreateDto; +import org.fuseri.model.dto.user.UserDto; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.http.MediaType; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.core.oidc.user.OidcUser; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; + +import java.io.IOException; + +@SpringBootApplication +public class ConfidentialClientApplication { + + public static void main(String[] args) { + SpringApplication.run(ConfidentialClientApplication.class, args); + } + + private static String asJsonString(final Object obj) throws JsonProcessingException { + return new ObjectMapper().writeValueAsString(obj); + } + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { + httpSecurity + .authorizeHttpRequests(x -> x + // allow anonymous access to listed URLs + .requestMatchers("/", "/error", "/robots.txt", "/style.css", "/favicon.ico", "/webjars/**").permitAll() + // all other requests must be authenticated + .anyRequest().authenticated() + ) + .oauth2Login(x -> x + // our custom handler for successful logins + .successHandler(authenticationSuccessHandler()) + ) + ; + return httpSecurity.build(); + } + @Bean + public AuthenticationSuccessHandler authenticationSuccessHandler() { + return new SavedRequestAwareAuthenticationSuccessHandler() { + @Override + public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse res, Authentication auth) throws ServletException, IOException { + + + var a= res.getHeaderNames(); + for (var name : a) { + System.out.println(res.getHeader(name)); + } + + System.out.println("got here"); + if (auth instanceof OAuth2AuthenticationToken token + && token.getPrincipal() instanceof OidcUser user) { + var createDto = new UserCreateDto(); + createDto.setLastName(user.getFamilyName()); + createDto.setFirstName(user.getGivenName()); + createDto.setEmail(user.getEmail()); + createDto.setUsername(user.getPreferredUsername()); + + var result = WebClient.builder().baseUrl("http://localhost:8081/users/register").build().post() + .contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(createDto)) + .retrieve(); + + + var out = result.bodyToMono(UserDto.class).block(); + System.out.println(out); + } + super.onAuthenticationSuccess(req, res, auth); + } + }; + } + + + +} diff --git a/application/confidentialClient/src/main/resources/application.yml b/application/confidentialClient/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..d34bc9db2dbf180c4e3a9a817c29d4132d8ddf79 --- /dev/null +++ b/application/confidentialClient/src/main/resources/application.yml @@ -0,0 +1,25 @@ + +server: + port: 8080 + +# OAuth client config +spring: + security: + oauth2: + client: + registration: + muni: + client-id: 7e02a0a9-446a-412d-ad2b-90add47b0fdd + client-secret: 48a2b2e3-4b2b-471e-b7b7-b81a85b6eeef22f347f2-3fc9-4e16-8698-3e2492701a89 + client-name: "MUNI Unified Login" + provider: muni + scope: + - openid + - profile + - email + - test_1 + - test_2 + provider: + muni: + # URL to which .well-know/openid-configuration will be added to download metadata + issuer-uri: https://oidc.muni.cz/oidc/ \ No newline at end of file diff --git a/application/confidentialClient/src/test/java/org/fuseri/confidentialclient/ConfidentialClientApplicationTests.java b/application/confidentialClient/src/test/java/org/fuseri/confidentialclient/ConfidentialClientApplicationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..d6e898248d93b33df378c8d89589773b0075e164 --- /dev/null +++ b/application/confidentialClient/src/test/java/org/fuseri/confidentialclient/ConfidentialClientApplicationTests.java @@ -0,0 +1,13 @@ +package org.fuseri.confidentialclient; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ConfidentialClientApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/application/docker-compose.yml b/application/docker-compose.yml index 6112e2d107b5d9ea41d0ef24b29bdf6843b709c2..0b7473de5989630826f88258c9e81c9e199e8f60 100644 --- a/application/docker-compose.yml +++ b/application/docker-compose.yml @@ -23,7 +23,7 @@ services: container_name: language-school image: xpokorn8/sprachschulsystem:language-school ports: - - "5000:5000" + - "8081:8081" mail: build: ./module-mail @@ -31,6 +31,13 @@ services: image: xpokorn8/sprachschulsystem:mail ports: - "5003:5003" + + confidential-client: + build: ./confidentialClient + container_name: confidential-client + image: xpokorn8/sprachschulsystem:confidential-client + ports: + - "8080:8080" prometheus: image: prom/prometheus:v2.43.0 diff --git a/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateCreateDto.java b/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateCreateDto.java index a6b4f1f7e183d139a19ef838f26ef27d14d5298d..936139a21d3080d5a9c81c1778cd514ab767e0ee 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateCreateDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateCreateDto.java @@ -3,7 +3,9 @@ package org.fuseri.model.dto.certificate; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import org.fuseri.model.dto.course.CourseCertificateDto; import org.fuseri.model.dto.user.UserDto; @@ -45,6 +47,7 @@ import org.fuseri.model.dto.user.UserDto; """) @Getter @Setter +@NoArgsConstructor public class CertificateCreateDto { @NotNull @Valid diff --git a/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateDto.java b/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateDto.java index 6d55d5774ba75ebd158a05b9541c943bd2dbc4ac..f2973ac6544bc247b464b1aab88667366a118882 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateDto.java @@ -3,6 +3,7 @@ package org.fuseri.model.dto.certificate; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import org.fuseri.model.dto.common.DomainObjectDto; @@ -18,6 +19,7 @@ import java.time.Instant; */ @Getter @Setter +@AllArgsConstructor public class CertificateDto extends DomainObjectDto { @NotBlank @NotNull diff --git a/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateFileDto.java b/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateFileDto.java index 35f7b19724688caa13264916194876bd028d962a..7ed5a0e5ffa6aad7cf811ce2889b47d67d59ab2c 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateFileDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateFileDto.java @@ -2,7 +2,9 @@ package org.fuseri.model.dto.certificate; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import org.fuseri.model.dto.common.DomainObjectDto; @@ -14,6 +16,8 @@ import org.fuseri.model.dto.common.DomainObjectDto; */ @Getter @Setter +@NoArgsConstructor +@AllArgsConstructor public class CertificateFileDto extends DomainObjectDto { @NotBlank @NotNull diff --git a/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateSimpleDto.java b/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateSimpleDto.java index 776f6c7baf25c11ea1a4858219914c3e70b1add7..7434a3d82a42ca17ce758b1d620a10d962885767 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateSimpleDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateSimpleDto.java @@ -2,7 +2,9 @@ package org.fuseri.model.dto.certificate; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import org.fuseri.model.dto.common.DomainObjectDto; @@ -15,6 +17,8 @@ import java.time.Instant; */ @Getter @Setter +@AllArgsConstructor +@NoArgsConstructor public class CertificateSimpleDto extends DomainObjectDto { @NotBlank @NotNull diff --git a/application/model/src/main/java/org/fuseri/model/dto/course/CourseCertificateDto.java b/application/model/src/main/java/org/fuseri/model/dto/course/CourseCertificateDto.java index 8a7e5982f48e0b9edbd0e513eec26dafaca26c77..d66e5030cd2c5e6bc2057832dd2c9365e6a84004 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/course/CourseCertificateDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/course/CourseCertificateDto.java @@ -5,8 +5,10 @@ import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import org.fuseri.model.dto.common.DomainObjectDto; @@ -17,6 +19,7 @@ import org.fuseri.model.dto.common.DomainObjectDto; */ @Getter @Setter +@NoArgsConstructor @EqualsAndHashCode(callSuper = false) public class CourseCertificateDto extends DomainObjectDto { diff --git a/application/model/src/main/java/org/fuseri/model/dto/course/CourseCreateDto.java b/application/model/src/main/java/org/fuseri/model/dto/course/CourseCreateDto.java index c7548adb3095a544c5975d69b2f2c94b03081fc3..5a5daaea5d2c7d9597314f1be258d56bd68fb453 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/course/CourseCreateDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/course/CourseCreateDto.java @@ -9,6 +9,7 @@ import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; /** @@ -26,6 +27,7 @@ import lombok.Setter; @Getter @Setter @AllArgsConstructor +@NoArgsConstructor @EqualsAndHashCode(callSuper = false) public class CourseCreateDto { diff --git a/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerCreateDto.java b/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerCreateDto.java index 7b4539a9ab48612adffdc7dce62372939a4dec89..f793a8ecab6b380e3865c8d57892ee529f9b2d20 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerCreateDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerCreateDto.java @@ -5,10 +5,12 @@ import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; @AllArgsConstructor @NoArgsConstructor @Getter + public class AnswerCreateDto { @NotBlank(message = "answer text is required") diff --git a/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerDto.java b/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerDto.java index 2f87806e2c6869602b12473d464d35b96240aa03..24d639cca93e136f263f664c1b6c0830a723bb9c 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerDto.java @@ -5,6 +5,7 @@ import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; import org.fuseri.model.dto.common.DomainObjectDto; @AllArgsConstructor diff --git a/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerInQuestionCreateDto.java b/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerInQuestionCreateDto.java index 8add213c5a60f1b1e332d3fc783dc367bf9f25ce..a2e59f344a8c6d1504b036d70c6316d710bd9bc6 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerInQuestionCreateDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/exercise/AnswerInQuestionCreateDto.java @@ -4,8 +4,11 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; @AllArgsConstructor +@NoArgsConstructor @Getter public class AnswerInQuestionCreateDto { diff --git a/application/model/src/main/java/org/fuseri/model/dto/exercise/QuestionCreateDto.java b/application/model/src/main/java/org/fuseri/model/dto/exercise/QuestionCreateDto.java index fa7c786f55bcd743ab02730cdac9d251c925dd7b..8668b1a580d5c7b287ee1b05f6a78bf073ef237e 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/exercise/QuestionCreateDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/exercise/QuestionCreateDto.java @@ -6,6 +6,7 @@ import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; import java.util.List; diff --git a/application/model/src/main/java/org/fuseri/model/dto/exercise/QuestionUpdateDto.java b/application/model/src/main/java/org/fuseri/model/dto/exercise/QuestionUpdateDto.java index e23b02ec6aa7d28556f5d65232a9cea4098f2a1d..43759238216d50c0c4614761300955f7f232af0a 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/exercise/QuestionUpdateDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/exercise/QuestionUpdateDto.java @@ -2,11 +2,15 @@ package org.fuseri.model.dto.exercise; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; @Getter @Builder +@AllArgsConstructor +@NoArgsConstructor public class QuestionUpdateDto { @NotBlank(message = "question text is required") diff --git a/application/model/src/main/java/org/fuseri/model/dto/lecture/LectureCreateDto.java b/application/model/src/main/java/org/fuseri/model/dto/lecture/LectureCreateDto.java index b54ff0182cc8661d59a8193f95dadf68b1cc3608..ee7149e7dea37afcb26dbe126381cd63cd4d8081 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/lecture/LectureCreateDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/lecture/LectureCreateDto.java @@ -3,6 +3,7 @@ package org.fuseri.model.dto.lecture; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.*; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import java.time.LocalDateTime; @@ -18,6 +19,7 @@ import java.time.LocalDateTime; """) @Getter @Setter +@NoArgsConstructor public class LectureCreateDto { @Future(message = "Lecture start date and time must be in the future") diff --git a/application/model/src/main/java/org/fuseri/model/dto/mail/MailDto.java b/application/model/src/main/java/org/fuseri/model/dto/mail/MailDto.java index 413e15b2276990f965f6c8b8df50822531750e65..f784f20b5aacd2b0e8a5e9727fb8999658de6ebd 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/mail/MailDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/mail/MailDto.java @@ -1,9 +1,13 @@ package org.fuseri.model.dto.mail; import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; +@NoArgsConstructor +@AllArgsConstructor @Getter @Setter public class MailDto { @@ -14,9 +18,4 @@ public class MailDto { @NotBlank public String content; - - public MailDto(String receiver, String content) { - this.receiver = receiver; - this.content = content; - } } diff --git a/application/model/src/main/java/org/fuseri/model/dto/user/AddressDto.java b/application/model/src/main/java/org/fuseri/model/dto/user/AddressDto.java deleted file mode 100644 index 8cc6071b122bf90572c3134039b163842ee7751b..0000000000000000000000000000000000000000 --- a/application/model/src/main/java/org/fuseri/model/dto/user/AddressDto.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.fuseri.model.dto.user; - -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -@EqualsAndHashCode -public class AddressDto { - - @NotBlank - private String country; - - @NotBlank - private String city; - - @NotBlank - private String street; - - @NotBlank - private String houseNumber; - - @NotBlank - private String zip; -} diff --git a/application/model/src/main/java/org/fuseri/model/dto/user/UserAddLanguageDto.java b/application/model/src/main/java/org/fuseri/model/dto/user/UserAddLanguageDto.java index d4456bcd61c008ead27a17c5b6034395c8f19540..4ed9fe551b0fb8ab8a9eeae38577fbdcfb774c54 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/user/UserAddLanguageDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/user/UserAddLanguageDto.java @@ -5,6 +5,7 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import org.fuseri.model.dto.course.LanguageTypeDto; import org.fuseri.model.dto.course.ProficiencyLevelDto; @@ -18,6 +19,7 @@ import org.fuseri.model.dto.course.ProficiencyLevelDto; @Getter @Setter @AllArgsConstructor +@NoArgsConstructor public class UserAddLanguageDto { @NotNull diff --git a/application/model/src/main/java/org/fuseri/model/dto/user/UserCreateDto.java b/application/model/src/main/java/org/fuseri/model/dto/user/UserCreateDto.java index 69dbdba233057db846499fa1a6fc34b86cf59ddc..b0d6fb30472ceca7e2e1cf647eed69a3cb8985ef 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/user/UserCreateDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/user/UserCreateDto.java @@ -1,50 +1,22 @@ package org.fuseri.model.dto.user; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; -import org.fuseri.model.dto.course.LanguageTypeDto; -import org.fuseri.model.dto.course.ProficiencyLevelDto; -import java.util.Map; - -@Schema(example = """ - { - "username": "adelkaxxx", - "password": "123456", - "email": "adelkaxxx@muni.mail.cz", - "firstName": "Adéla", - "lastName": "Pulcová", - "address": { - "country": "Czechia", - "city": "Praha", - "street": "Bubenské nábÅ™ežÃ", - "houseNumber": "306/13", - "zip": "170 00" - }, - "userType": "STUDENT", - "languageProficiency": { - "CZECH": "A2" - } - } - """) @Getter @Setter @AllArgsConstructor +@NoArgsConstructor @EqualsAndHashCode(callSuper = false) public class UserCreateDto { @NotBlank private String username; - @NotBlank - private String password; - @NotBlank private String email; @@ -53,15 +25,4 @@ public class UserCreateDto { @NotBlank private String lastName; - - @NotNull - @Valid - private AddressDto address; - - @NotNull - private UserType userType; - - @NotNull - @Valid - private Map<LanguageTypeDto, ProficiencyLevelDto> languageProficiency; } diff --git a/application/model/src/main/java/org/fuseri/model/dto/user/UserDto.java b/application/model/src/main/java/org/fuseri/model/dto/user/UserDto.java index a5aa263f9de41e0e3c2b6f442926a7bd8463f1c3..77694d6bf75fb45af658b27c7b529eb743389ccb 100644 --- a/application/model/src/main/java/org/fuseri/model/dto/user/UserDto.java +++ b/application/model/src/main/java/org/fuseri/model/dto/user/UserDto.java @@ -18,14 +18,6 @@ import java.util.Map; "email": "adelkaxxx@muni.mail.cz", "firstName": "Adéla", "lastName": "Pulcová", - "address": { - "country": "Czechia", - "city": "Praha", - "street": "Bubenské nábÅ™ežÃ", - "houseNumber": "306/13", - "zip": "170 00" - }, - "userType": "STUDENT", "languageProficiency": { "CZECH": "A2" } @@ -49,34 +41,18 @@ public class UserDto extends DomainObjectDto { @NotBlank private String lastName; - @Valid - private AddressDto address; - - @NotNull - private UserType userType; - @NotNull @Valid private Map<LanguageTypeDto, ProficiencyLevelDto> languageProficiency; - public UserDto(String username, String email, String firstName, String lastName, AddressDto address, UserType userType) { - this.username = username; - this.email = email; - this.firstName = firstName; - this.lastName = lastName; - this.address = address; - this.userType = userType; - } - public UserDto(String username, String email, String firstName, String lastName, AddressDto address, UserType userType,Map<LanguageTypeDto, ProficiencyLevelDto> languageProficiency) { + public UserDto(String username, String email, String firstName, String lastName, Map<LanguageTypeDto, ProficiencyLevelDto> languageProficiency) { setId(0L); this.username = username; this.email = email; this.firstName = firstName; this.lastName = lastName; - this.address = address; - this.userType = userType; this.languageProficiency = languageProficiency; } } diff --git a/application/model/src/main/java/org/fuseri/model/dto/user/UserType.java b/application/model/src/main/java/org/fuseri/model/dto/user/UserType.java deleted file mode 100644 index 1c38db11b25b25eee6c947f37c388724ea8ffdb9..0000000000000000000000000000000000000000 --- a/application/model/src/main/java/org/fuseri/model/dto/user/UserType.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.fuseri.model.dto.user; - -public enum UserType { - ADMIN, - STUDENT, - LECTURER -} diff --git a/application/module-certificate/pom.xml b/application/module-certificate/pom.xml index 9ab80d528d4f1ca8c3487a1df99a9cdf450cba7d..24a29f335c0a67c0ab431ba66c2610892f4b39c0 100644 --- a/application/module-certificate/pom.xml +++ b/application/module-certificate/pom.xml @@ -73,6 +73,11 @@ <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/ModuleCertificateApplication.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/ModuleCertificateApplication.java index 230c9e6eeeb8b3259921eb822f29b7bd3432dea6..a3b0da9fa5c29a68bb16618248a1e1d76dee98e4 100644 --- a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/ModuleCertificateApplication.java +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/ModuleCertificateApplication.java @@ -1,13 +1,32 @@ package org.fuseri.modulecertificate; +import io.swagger.v3.oas.models.security.SecurityScheme; +import org.springdoc.core.customizers.OpenApiCustomizer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; @SpringBootApplication public class ModuleCertificateApplication { + private static final String SECURITY_SCHEME_BEARER = "Bearer"; + public static final String SECURITY_SCHEME_NAME = SECURITY_SCHEME_BEARER; + public static void main(String[] args) { SpringApplication.run(ModuleCertificateApplication.class, args); } + @Bean + public OpenApiCustomizer openAPICustomizer() { + return openApi -> { + openApi.getComponents() + .addSecuritySchemes(SECURITY_SCHEME_BEARER, + new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .description("provide a valid access token") + ); + }; + } + } diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/certificate/CertificateController.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/certificate/CertificateController.java index a057ca3e8794083dec5255e108f8738e454e0b9d..280caf5ed034cce5e51865ff79becb605edfa1ed 100644 --- a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/certificate/CertificateController.java +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/certificate/CertificateController.java @@ -3,11 +3,13 @@ package org.fuseri.modulecertificate.certificate; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import org.fuseri.model.dto.certificate.CertificateCreateDto; import org.fuseri.model.dto.certificate.CertificateGenerateDto; import org.fuseri.model.dto.certificate.CertificateSimpleDto; +import org.fuseri.modulecertificate.ModuleCertificateApplication; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -40,7 +42,8 @@ public class CertificateController { * @param certificateCreateDto Dto with data used for generating certificate * @return CertificateDto with data of generated certificate */ - @Operation(summary = "Generate certificate", + @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Generate certificate", description = "Generates certificate, saves it into database and returns certificate information and certificate file.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Certificate generated successfully."), @@ -58,7 +61,8 @@ public class CertificateController { * @param id ID of certificate to be retrieved * @return CertificateDto with data of previously generated certificate with specified ID */ - @Operation(summary = "Get a certificate by ID", description = "Returns a certificate with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME,scopes = {}), + summary = "Get a certificate by ID", description = "Returns a certificate with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Certificate with the specified ID retrieved successfully."), @ApiResponse(responseCode = "404", description = "Certificate with the specified ID was not found."), @@ -76,7 +80,8 @@ public class CertificateController { * @return List of CertificateDto objects with previously generated certificates * for specified User. */ - @Operation(summary = "Get certificates for user", description = "Returns certificates for given user in list.") + @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME,scopes = {}), + summary = "Get certificates for user", description = "Returns certificates for given user in list.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved certificates"), @ApiResponse(responseCode = "500", description = "Internal server error."), @@ -94,7 +99,8 @@ public class CertificateController { * @return List of CertificateDto objects with previously generated certificates * for specified User and Course. */ - @Operation(summary = "Get certificates for user and course", + @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME,scopes = {}), + summary = "Get certificates for user and course", description = "Returns certificates for given user and course in list.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved certificates"), @@ -111,7 +117,8 @@ public class CertificateController { * * @param id Id of certificate to be deleted. */ - @Operation(summary = "Delete a certificate with specified ID", description = "Deletes a certificate with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME,scopes = {"test_1"}), + summary = "Delete a certificate with specified ID", description = "Deletes a certificate with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Certificate with the specified ID deleted successfully."), @ApiResponse(responseCode = "500", description = "Internal server error."), @@ -128,7 +135,8 @@ public class CertificateController { * * @return a Result object containing a list of CertificateDto objects and pagination information */ - @Operation(summary = "Get certificates in paginated format", description = "Returns certificates in paginated format.") + @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME,scopes = {}), + summary = "Get certificates in paginated format", description = "Returns certificates in paginated format.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved paginated certificates"), @ApiResponse(responseCode = "500", description = "Internal server error.") diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/config/AppSecurityConfig.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/config/AppSecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..a6aa0033f4ededaa98013e3c086cd73b54ec3c8a --- /dev/null +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/config/AppSecurityConfig.java @@ -0,0 +1,30 @@ +package org.fuseri.modulecertificate.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@Configuration +@EnableWebSecurity +@EnableWebMvc +public class AppSecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + httpSecurity.csrf().disable(); + httpSecurity.authorizeHttpRequests(x -> x + .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() + .requestMatchers(HttpMethod.POST, "/certificates/**").hasAuthority("SCOPE_test_1") + .requestMatchers(HttpMethod.DELETE, "/certificates/**").hasAuthority("SCOPE_test_1") + .requestMatchers(HttpMethod.PUT, "/certificates/**").hasAnyAuthority("SCOPE_test_1","SCOPE_test_2") + .anyRequest().authenticated() + ).oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken) + ; + return httpSecurity.build(); + } +} diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/datainitializer/DataInitializerController.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/datainitializer/DataInitializerController.java index 5c3fa9f4143a010a0aa65440de973425bc133317..0473ed7a3a4cc56e14d2ab0749e17690ad0b793d 100644 --- a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/datainitializer/DataInitializerController.java +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/datainitializer/DataInitializerController.java @@ -5,6 +5,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -25,7 +27,7 @@ public class DataInitializerController { @ApiResponse(responseCode = "204", description = "Data initialized successfully."), }) @PostMapping - public ResponseEntity<Void> initialize() { + public ResponseEntity<Void> initialize(@AuthenticationPrincipal OAuth2IntrospectionAuthenticatedPrincipal principal) { dataInitializer.initialize(); return ResponseEntity.noContent().build(); } @@ -35,7 +37,7 @@ public class DataInitializerController { @ApiResponse(responseCode = "204", description = "Data dropped successfully."), }) @DeleteMapping - public ResponseEntity<Void> drop() { + public ResponseEntity<Void> drop(@AuthenticationPrincipal OAuth2IntrospectionAuthenticatedPrincipal principal) { dataInitializer.drop(); return ResponseEntity.noContent().build(); } diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/exceptions/RestResponseEntityExceptionHandler.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/exceptions/RestResponseEntityExceptionHandler.java index 3161f0e18cc5be5e005110b135161879910a6b8b..17ba4421930c436d8a0e60fd9594bd997ce27f85 100644 --- a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/exceptions/RestResponseEntityExceptionHandler.java +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/exceptions/RestResponseEntityExceptionHandler.java @@ -7,6 +7,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.util.UrlPathHelper; diff --git a/application/module-certificate/src/main/resources/application.properties b/application/module-certificate/src/main/resources/application.properties index c773ad9793b9fbac49be18200fd1d55b65839b29..69a2129b2204874fab2a41f416fcbb17d220ee82 100644 --- a/application/module-certificate/src/main/resources/application.properties +++ b/application/module-certificate/src/main/resources/application.properties @@ -12,4 +12,8 @@ spring.datasource.username=SedaQ-app spring.datasource.password=$argon2id$v=19$m=16,t=2,p=1$YmF0bWFuYmF0bWFu$MdHYB359HdivAb9J6CaILw spring.jpa.database-platform=org.hibernate.dialect.H2Dialect # showing SQL is generally good practice for running project locally to check whether there is not an issue with implementation of JPA methods. -spring.jpa.show-sql=true \ No newline at end of file +spring.jpa.show-sql=true + +spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://oidc.muni.cz/oidc/introspect +spring.security.oauth2.resourceserver.opaque-token.client-id=d57b3a8f-156e-46de-9f27-39c4daee05e1 +spring.security.oauth2.resourceserver.opaque-token.client-secret=fa228ebc-4d54-4cda-901e-4d6287f8b1652a9c9c44-73c9-4502-973f-bcdb4a8ec96a diff --git a/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateControllerTests.java b/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateControllerTests.java index 383c89afa08d0b63513c7cbb15ec2b19997e9dc6..5fd9de894603a0d554866d95b24ec60543f5a88e 100644 --- a/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateControllerTests.java +++ b/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateControllerTests.java @@ -7,9 +7,7 @@ import org.fuseri.model.dto.certificate.CertificateSimpleDto; import org.fuseri.model.dto.course.CourseCertificateDto; import org.fuseri.model.dto.course.LanguageTypeDto; import org.fuseri.model.dto.course.ProficiencyLevelDto; -import org.fuseri.model.dto.user.AddressDto; import org.fuseri.model.dto.user.UserDto; -import org.fuseri.model.dto.user.UserType; import org.fuseri.modulecertificate.certificate.CertificateFacade; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; @@ -22,6 +20,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import java.time.Instant; @@ -37,9 +36,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. class CertificateControllerTests { private final UserDto USER = new UserDto("novakovat", - "novakova@gamil.com", "Tereza", "Nováková", - new AddressDto("USA", "New York", "Main Street", "123", "10001"), - UserType.STUDENT, new HashMap<>()); + "novakova@gamil.com", "Tereza", "Nováková",new HashMap<>()); private final CourseCertificateDto COURSE = new CourseCertificateDto("AJ1", 10, LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1); private final CertificateCreateDto certificateCreateDto = new CertificateCreateDto(USER, COURSE); @@ -62,6 +59,7 @@ class CertificateControllerTests { } } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void generateCertificate() throws Exception { Mockito.when(certificateFacade.generate(ArgumentMatchers.any(CertificateCreateDto.class))) @@ -78,6 +76,7 @@ class CertificateControllerTests { .andExpect(jsonPath("$.certificateFileName").value(certificateDto.getCertificateFileName())); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void generateCertificateWithNullUser() throws Exception { mockMvc.perform(post("/certificates") @@ -86,6 +85,7 @@ class CertificateControllerTests { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void generateCertificateWithNullCourse() throws Exception { mockMvc.perform(post("/certificates") @@ -94,6 +94,7 @@ class CertificateControllerTests { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void generateCertificateWithoutParams() throws Exception { mockMvc.perform(post("/certificates") @@ -101,6 +102,7 @@ class CertificateControllerTests { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findCertificate() throws Exception { Mockito.when(certificateFacade.findById(ArgumentMatchers.anyLong())).thenReturn(certificateDto); @@ -110,12 +112,14 @@ class CertificateControllerTests { .andExpect(jsonPath("$.id").value(certificateDto.getId())); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findCertificateWithoutId() throws Exception { mockMvc.perform(get("/certificates/")) .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findCertificatesForUser() throws Exception { Mockito.when(certificateFacade.findByUserId(ArgumentMatchers.anyLong())).thenReturn(List.of(certificateDto)); @@ -126,12 +130,14 @@ class CertificateControllerTests { .andExpect(jsonPath("$").isNotEmpty()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findCertificatesWithoutUserId() throws Exception { mockMvc.perform(get("/certificates/findForUser")) .andExpect(status().is5xxServerError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findCertificateIdForUserAndCourse() throws Exception { Mockito.when(certificateFacade.findByUserIdAndCourseId(ArgumentMatchers.anyLong(), @@ -146,6 +152,7 @@ class CertificateControllerTests { .andExpect(jsonPath("$").isNotEmpty()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findCertificateIdWithoutUserId() throws Exception { mockMvc.perform(get("/certificates/findForUserAndCourse") @@ -153,6 +160,7 @@ class CertificateControllerTests { .andExpect(status().is5xxServerError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findCertificateIdWithoutCourseId() throws Exception { mockMvc.perform(get("/certificates/findForUserAndCourse") @@ -160,12 +168,14 @@ class CertificateControllerTests { .andExpect(status().is5xxServerError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findCertificateIdWithoutParams() throws Exception { mockMvc.perform(get("/certificates/findForUserAndCourse")) .andExpect(status().is5xxServerError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void deleteCertificate() throws Exception { Mockito.doNothing().when(certificateFacade).deleteCertificate(ArgumentMatchers.anyLong()); @@ -174,12 +184,14 @@ class CertificateControllerTests { .andExpect(status().is2xxSuccessful()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void deleteCertificateWithoutParam() throws Exception { mockMvc.perform(delete("/certificates/")) .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findAllCertificates() throws Exception { Mockito.when(certificateFacade.findAll(ArgumentMatchers.any(Pageable.class))) @@ -193,6 +205,7 @@ class CertificateControllerTests { .andExpect(jsonPath("$.content").isEmpty()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findAllCertificatesWithoutParam() throws Exception { Mockito.when(certificateFacade.findAll(ArgumentMatchers.any(Pageable.class))) diff --git a/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateFacadeTests.java b/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateFacadeTests.java index 8f6dcd5be58283ab6ffaf26df1b18d27fb97a8b1..aae9790b3372d04cc59f8171ebb70b8bfee54a83 100644 --- a/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateFacadeTests.java +++ b/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateFacadeTests.java @@ -6,9 +6,7 @@ import org.fuseri.model.dto.certificate.CertificateSimpleDto; import org.fuseri.model.dto.course.CourseCertificateDto; import org.fuseri.model.dto.course.LanguageTypeDto; import org.fuseri.model.dto.course.ProficiencyLevelDto; -import org.fuseri.model.dto.user.AddressDto; import org.fuseri.model.dto.user.UserDto; -import org.fuseri.model.dto.user.UserType; import org.fuseri.modulecertificate.certificate.Certificate; import org.fuseri.modulecertificate.certificate.CertificateFacade; import org.fuseri.modulecertificate.certificate.CertificateMapper; @@ -24,6 +22,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import java.time.Instant; +import java.util.HashMap; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -37,7 +36,7 @@ import static org.mockito.Mockito.when; @AutoConfigureMockMvc final class CertificateFacadeTests { private final UserDto USER = new UserDto("novakovat", - "novakova@gamil.com", "Tereza", "Nováková", new AddressDto(), UserType.STUDENT); + "novakova@gamil.com", "Tereza", "Nováková",new HashMap<>()); private final CourseCertificateDto COURSE = new CourseCertificateDto("AJ1", 10, LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1); private final CertificateCreateDto certificateCreateDto = new CertificateCreateDto(USER, COURSE); diff --git a/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateMapperTests.java b/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateMapperTests.java index 98023c1adb774d52ddd65db26c2c99cb110c05a0..925a62aa134caf30cb87f48a9eb6600703908cf9 100644 --- a/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateMapperTests.java +++ b/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateMapperTests.java @@ -5,9 +5,7 @@ import org.fuseri.model.dto.certificate.CertificateSimpleDto; import org.fuseri.model.dto.course.CourseCertificateDto; import org.fuseri.model.dto.course.LanguageTypeDto; import org.fuseri.model.dto.course.ProficiencyLevelDto; -import org.fuseri.model.dto.user.AddressDto; import org.fuseri.model.dto.user.UserDto; -import org.fuseri.model.dto.user.UserType; import org.fuseri.modulecertificate.certificate.Certificate; import org.fuseri.modulecertificate.certificate.CertificateMapper; import org.junit.jupiter.api.Assertions; @@ -20,13 +18,14 @@ import org.springframework.data.domain.PageRequest; import java.time.Instant; import java.util.Collections; +import java.util.HashMap; import java.util.List; @SpringBootTest final class CertificateMapperTests { private final UserDto USER = new UserDto("novakovat", - "novakova@gamil.com", "Tereza", "Nováková", new AddressDto(), UserType.STUDENT); + "novakova@gamil.com", "Tereza", "Nováková",new HashMap<>()); private final CourseCertificateDto COURSE = new CourseCertificateDto("AJ1", 10, LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1); private final Instant instant = Instant.now(); diff --git a/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateServiceTests.java b/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateServiceTests.java index 948026553c7af7b8218a7c297edfeb910d56d20c..73640c8d6b869b34122f023061a778015be98c6e 100644 --- a/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateServiceTests.java +++ b/application/module-certificate/src/test/java/org/fuseri/modulecertificate/CertificateServiceTests.java @@ -3,9 +3,7 @@ package org.fuseri.modulecertificate; import org.fuseri.model.dto.course.CourseDto; import org.fuseri.model.dto.course.LanguageTypeDto; import org.fuseri.model.dto.course.ProficiencyLevelDto; -import org.fuseri.model.dto.user.AddressDto; import org.fuseri.model.dto.user.UserDto; -import org.fuseri.model.dto.user.UserType; import org.fuseri.modulecertificate.certificate.Certificate; import org.fuseri.modulecertificate.certificate.CertificateRepository; import org.fuseri.modulecertificate.certificate.CertificateService; @@ -22,6 +20,7 @@ import org.springframework.web.server.ResponseStatusException; import java.time.Instant; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Optional; @@ -37,7 +36,7 @@ final class CertificateServiceTests { private CertificateService certificateService; private final UserDto USER = new UserDto("novakovat", - "novakova@gamil.com", "Tereza", "Nováková", new AddressDto(), UserType.STUDENT); + "novakova@gamil.com", "Tereza", "Nováková",new HashMap<>()); private final CourseDto COURSE = new CourseDto("AJ1", 10, LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1); private final Certificate certificate = new Certificate(USER.getId(), diff --git a/application/module-exercise/pom.xml b/application/module-exercise/pom.xml index d42b3eae2bc1ebdeaef9e5caf06e5267d99c6d9f..e22090ae85875f1408e1f25e0418427cef553742 100644 --- a/application/module-exercise/pom.xml +++ b/application/module-exercise/pom.xml @@ -44,6 +44,11 @@ <version>0.0.1-SNAPSHOT</version> <scope>compile</scope> </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/ModuleExerciseApplication.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/ModuleExerciseApplication.java index 10e54ab3b5808b91143c62dd6cf0c8f11682b8f5..33a9f77ef20f758dae50183aee379eb20b267722 100644 --- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/ModuleExerciseApplication.java +++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/ModuleExerciseApplication.java @@ -1,13 +1,31 @@ package org.fuseri.moduleexercise; +import io.swagger.v3.oas.models.security.SecurityScheme; +import org.springdoc.core.customizers.OpenApiCustomizer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; @SpringBootApplication public class ModuleExerciseApplication { + private static final String SECURITY_SCHEME_BEARER = "Bearer"; + public static final String SECURITY_SCHEME_NAME = SECURITY_SCHEME_BEARER; public static void main(String[] args) { SpringApplication.run(ModuleExerciseApplication.class, args); } + @Bean + public OpenApiCustomizer openAPICustomizer() { + return openApi -> { + openApi.getComponents() + .addSecuritySchemes(SECURITY_SCHEME_BEARER, + new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .description("provide a valid access token") + ); + }; + } + } diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerController.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerController.java index 87ac6a7d115550a4053de3a7b47c3eaf77863f3b..8e0bb75958109ad5012b6b4ae77e93166a676355 100644 --- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerController.java +++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerController.java @@ -3,10 +3,12 @@ package org.fuseri.moduleexercise.answer; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import org.fuseri.model.dto.exercise.AnswerCreateDto; import org.fuseri.model.dto.exercise.AnswerDto; +import org.fuseri.moduleexercise.ModuleExerciseApplication; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -41,7 +43,8 @@ public class AnswerController { * @return a ResponseEntity containing an AnswerDto object representing the newly created answer, or a 404 Not Found response * if the question with the specified ID in dto was not found */ - @Operation(summary = "Create new answer for question", description = "Creates new answer for question.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Create new answer for question", description = "Creates new answer for question.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Answers created successfully."), @ApiResponse(responseCode = "400", description = "Invalid input.") @@ -59,7 +62,8 @@ public class AnswerController { * @return A ResponseEntity with an AnswerDto object representing the updated answer on an HTTP status code of 200 if the update was successful. * or a NOT_FOUND response if the answer ID is invalid */ - @Operation(summary = "Update an answer", description = "Updates an answer with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Update an answer", description = "Updates an answer with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Answer with the specified ID updated successfully."), @ApiResponse(responseCode = "400", description = "Invalid input."), @@ -76,7 +80,8 @@ public class AnswerController { * @param id of answer to delete * @throws ResponseStatusException if answer with specified id does not exist */ - @Operation(summary = "Delete an answer with specified ID", description = "Deletes an answer with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Delete an answer with specified ID", description = "Deletes an answer with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Answer with the specified ID deleted successfully."), @ApiResponse(responseCode = "404", description = "Answer with the specified ID was not found.") diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/config/AppSecurityConfig.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/config/AppSecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..1811cda8b666b3a02d06b6a866afe25ab6025a8b --- /dev/null +++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/config/AppSecurityConfig.java @@ -0,0 +1,41 @@ +package org.fuseri.moduleexercise.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@Configuration +@EnableWebSecurity +@EnableWebMvc + + +public class AppSecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + httpSecurity.csrf().disable(); + httpSecurity.authorizeHttpRequests(x -> x + .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() + + .requestMatchers(HttpMethod.POST, "/answers/**").hasAnyAuthority("SCOPE_test_1", "SCOPE_test_2") + .requestMatchers(HttpMethod.DELETE, "/answers/**").hasAnyAuthority("SCOPE_test_1", "SCOPE_test_2") + .requestMatchers(HttpMethod.PUT, "/answers/**").hasAnyAuthority("SCOPE_test_1","SCOPE_test_2") + + .requestMatchers(HttpMethod.POST, "/questions/**").hasAnyAuthority("SCOPE_test_1", "SCOPE_test_2") + .requestMatchers(HttpMethod.DELETE, "/questions/**").hasAnyAuthority("SCOPE_test_1", "SCOPE_test_2") + .requestMatchers(HttpMethod.PUT, "/questions/**").hasAnyAuthority("SCOPE_test_1","SCOPE_test_2") + + .requestMatchers(HttpMethod.POST, "/exercises/**").hasAnyAuthority("SCOPE_test_1", "SCOPE_test_2") + .requestMatchers(HttpMethod.DELETE, "/exercises/**").hasAnyAuthority("SCOPE_test_1", "SCOPE_test_2") + .requestMatchers(HttpMethod.PUT, "/exercises/**").hasAnyAuthority("SCOPE_test_1","SCOPE_test_2") + .anyRequest().authenticated() + + ).oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken) + ; + return httpSecurity.build(); + } +} diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseController.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseController.java index dd437b24997be84a50b5653ca8cc68554ae7ae6a..52130261f44248ccc106215a7646c5ec940a4e3a 100644 --- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseController.java +++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseController.java @@ -3,12 +3,14 @@ package org.fuseri.moduleexercise.exercise; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.PositiveOrZero; import org.fuseri.model.dto.exercise.ExerciseCreateDto; import org.fuseri.model.dto.exercise.ExerciseDto; import org.fuseri.model.dto.exercise.QuestionDto; +import org.fuseri.moduleexercise.ModuleExerciseApplication; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.http.HttpStatus; @@ -49,7 +51,8 @@ public class ExerciseController { * @param dto containing information about the exercise to create * @return a ResponseEntity containing an ExerciseDto object representing the newly created exercise */ - @Operation(summary = "Create an exercise", description = "Creates a new exercise.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Create an exercise", description = "Creates a new exercise.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Exercise created successfully."), @ApiResponse(responseCode = "400", description = "Invalid input.") @@ -67,7 +70,8 @@ public class ExerciseController { * @return a ResponseEntity containing an ExerciseDto object representing the found exercise, or a 404 Not Found response * if the exercise with the specified ID was not found */ - @Operation(summary = "Get an exercise by ID", description = "Returns an exercise with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Get an exercise by ID", description = "Returns an exercise with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Exercise with the specified ID retrieved successfully."), @ApiResponse(responseCode = "404", description = "Exercise with the specified ID was not found.") @@ -83,7 +87,8 @@ public class ExerciseController { * @param page the page number of the exercises to retrieve * @return A ResponseEntity containing paginated ExerciseDTOs. */ - @Operation(summary = "Get exercises in paginated format", description = "Returns exercises in paginated format.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Get exercises in paginated format", description = "Returns exercises in paginated format.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved paginated exercises"), @ApiResponse(responseCode = "400", description = "Invalid page number supplied"), @@ -101,7 +106,8 @@ public class ExerciseController { * @param page the page number of the exercises to retrieve * @return A ResponseEntity containing filtered and paginated ExerciseDTOs */ - @Operation(summary = "Filter exercises per difficulty and per course", description = "Returns exercises which belong to specified course and have specified difficulty.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Filter exercises per difficulty and per course", description = "Returns exercises which belong to specified course and have specified difficulty.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved filtered paginated exercises."), }) @@ -121,7 +127,8 @@ public class ExerciseController { * @return a ResponseEntity containing paginated QuestionDTOs which belong to an exercise with exerciseId * or a NOT_FOUND response if the exercise ID is invalid */ - @Operation(summary = "Find questions belonging to exercise by exercise ID", + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Find questions belonging to exercise by exercise ID", description = "Returns a paginated list of questions for the specified exercise ID.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Questions found and returned successfully."), @@ -142,7 +149,8 @@ public class ExerciseController { * @return A ResponseEntity with an ExerciseDto object representing the updated exercise an HTTP status code of 200 if the update was successful. * or a NOT_FOUND response if the exercise ID is invalid */ - @Operation(summary = "Update a exercise", description = "Updates a exercise with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Update a exercise", description = "Updates a exercise with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Exercise with the specified ID updated successfully."), @ApiResponse(responseCode = "400", description = "Invalid input."), @@ -158,7 +166,8 @@ public class ExerciseController { * * @param id the ID of the exercise to delete */ - @Operation(summary = "Delete a exercise with specified ID", description = "Deletes a exercise with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Delete a exercise with specified ID", description = "Deletes a exercise with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Exercise with the specified ID deleted successfully."), }) diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionController.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionController.java index e494fcb0e7e2f5063d3ae91dd485cbdff9747e0d..33c0c3b1556512b6f9fb0bd987792af12270b2c5 100644 --- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionController.java +++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionController.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import org.fuseri.model.dto.exercise.AnswerDto; @@ -12,6 +13,7 @@ import org.fuseri.model.dto.exercise.AnswerInQuestionCreateDto; import org.fuseri.model.dto.exercise.QuestionCreateDto; import org.fuseri.model.dto.exercise.QuestionDto; import org.fuseri.model.dto.exercise.QuestionUpdateDto; +import org.fuseri.moduleexercise.ModuleExerciseApplication; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -54,7 +56,7 @@ public class QuestionController { * @return a ResponseEntity containing a QuestionDto object representing the found question, or a 404 Not Found response * if the question with the specified ID was not found */ - @Operation(summary = "Get a question by ID", description = "Returns a question with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}),summary = "Get a question by ID", description = "Returns a question with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Question with the specified ID retrieved successfully.", content = @Content(schema = @Schema(implementation = QuestionDto.class))), @@ -72,7 +74,8 @@ public class QuestionController { * @return a ResponseEntity containing a List of AnswerDto objects, or a 404 Not Found response * if the question with the specified ID was not found */ - @Operation(summary = "Retrieve answers for a specific question") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Retrieve answers for a specific question") @ApiResponse(responseCode = "200", description = "Successfully retrieved answers", content = @Content(schema = @Schema(implementation = AnswerDto.class))) @ApiResponse(responseCode = "404", description = "Question not found") @@ -88,7 +91,8 @@ public class QuestionController { * @return a ResponseEntity containing a QuestionDto object representing the posted question, or a 404 Not Found response * if the exercise with the specified ID in dto was not found */ - @Operation(summary = "Add a new question with answers to an exercise", description = "Creates a new question with answers and associates it with the specified exercise.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Add a new question with answers to an exercise", description = "Creates a new question with answers and associates it with the specified exercise.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Question with answers created and added to the exercise successfully.", content = @Content(schema = @Schema(implementation = QuestionDto.class))), @@ -107,7 +111,8 @@ public class QuestionController { * @return a ResponseEntity containing a QuestionUpdateDto object representing the updated question, * or a 404 Not Found response if the question with the specified ID was not found */ - @Operation(summary = "Update a question by ID", description = "Updates a question with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Update a question by ID", description = "Updates a question with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Question with the specified ID updated successfully."), @ApiResponse(responseCode = "404", description = "Question with the specified ID was not found.") @@ -122,7 +127,8 @@ public class QuestionController { * * @param id of question to delete */ - @Operation(summary = "Delete a question with specified ID", description = "Deletes a question with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Delete a question with specified ID", description = "Deletes a question with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Question with the specified ID deleted successfully."), }) @@ -138,7 +144,8 @@ public class QuestionController { * @param id id of question to update * @return the LectureDto representing the updated lecture */ - @Operation(summary = "Add answers to the existing question.") + @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"}), + summary = "Add answers to the existing question.") @PatchMapping("/{id}/answers") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "The question has been successfully updated"), diff --git a/application/module-exercise/src/main/resources/application.properties b/application/module-exercise/src/main/resources/application.properties index dc2e93578e7d67565b95e8cf47bb01b76af85d82..7f00639b2a4f5bb166781c57dc6c9cbf6fabfbd1 100644 --- a/application/module-exercise/src/main/resources/application.properties +++ b/application/module-exercise/src/main/resources/application.properties @@ -6,4 +6,8 @@ management.health.defaults.enabled=true management.endpoint.health.probes.enabled=true spring.h2.console.enabled=true -spring.datasource.url=jdbc:h2:mem:exercices \ No newline at end of file +spring.datasource.url=jdbc:h2:mem:exercices + +spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://oidc.muni.cz/oidc/introspect +spring.security.oauth2.resourceserver.opaque-token.client-id=d57b3a8f-156e-46de-9f27-39c4daee05e1 +spring.security.oauth2.resourceserver.opaque-token.client-secret=fa228ebc-4d54-4cda-901e-4d6287f8b1652a9c9c44-73c9-4502-973f-bcdb4a8ec96a diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerControllerTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerControllerTest.java index 66eaea5afcd6ba64f557df3e63151398ea0bf233..80215be7f640507f1509a241fe37cbe3bfb0092f 100644 --- a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerControllerTest.java +++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerControllerTest.java @@ -16,6 +16,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import java.util.List; @@ -61,6 +62,7 @@ public class AnswerControllerTest { new AnswerInQuestionCreateDto("All of them", true))); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateAnswer() throws Exception { var answerCreateDto = new AnswerCreateDto("BA", true, 1); @@ -75,6 +77,7 @@ public class AnswerControllerTest { .andExpect(jsonPath("$.correct", is(true))); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateAnswerEmptyText() throws Exception { var incorrect1 = new AnswerInQuestionCreateDto("", false); @@ -86,6 +89,7 @@ public class AnswerControllerTest { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateAnswerMissingText() throws Exception { var prompt = """ @@ -106,6 +110,7 @@ public class AnswerControllerTest { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateAnswerMissingCorrect() throws Exception { @@ -126,6 +131,7 @@ public class AnswerControllerTest { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testUpdate() throws Exception { long id = 1L; @@ -140,6 +146,7 @@ public class AnswerControllerTest { .andExpect(jsonPath("$.correct", is(false))); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testUpdateNotFoundAnswer() throws Exception { long id = 1L; @@ -150,6 +157,7 @@ public class AnswerControllerTest { .andExpect(status().isNotFound()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testUpdateEmptyText() throws Exception { var updated = new AnswerCreateDto("", false, 1); @@ -158,6 +166,7 @@ public class AnswerControllerTest { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testUpdateMissingField() throws Exception { var updated = """ @@ -172,6 +181,7 @@ public class AnswerControllerTest { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testDelete() throws Exception { mockMvc.perform(delete("/answers/1")) diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseControllerTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseControllerTest.java index dce5d42843d4279b7813b5a9aa65038c41d245ff..9c15b063bed54b9c49cb44af652d99b0176344b2 100644 --- a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseControllerTest.java +++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseControllerTest.java @@ -13,6 +13,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.data.domain.PageImpl; import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import java.util.ArrayList; @@ -79,6 +80,7 @@ public class ExerciseControllerTest { exerciseCreateDto2 = new ExerciseCreateDto("idioms2", "exercise on basic idioms", 1, 0L); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void getExercise() throws Exception { long id = 1L; @@ -91,12 +93,14 @@ public class ExerciseControllerTest { .andExpect(jsonPath("$.difficulty", is(exerciseCreateDto.getDifficulty()))); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testDelete() throws Exception { mockMvc.perform(delete("/exercises/1")) .andExpect(status().is2xxSuccessful()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void getExercise_notFound() throws Exception { long id = 1L; @@ -105,6 +109,7 @@ public class ExerciseControllerTest { .andExpect(status().isNotFound()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void FindAll() { when(facade.findAll(0)).thenReturn(new PageImpl<>(new ArrayList<>())); @@ -121,6 +126,7 @@ public class ExerciseControllerTest { } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void getFiltered() { when(facade.findByCourseIdAndDifficulty(0, 2, 0)).thenReturn(new PageImpl<>(new ArrayList<>())); @@ -134,6 +140,7 @@ public class ExerciseControllerTest { } } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateExercise() throws Exception { when(facade.create(ArgumentMatchers.isA(ExerciseCreateDto.class))).thenReturn(exerciseDto); @@ -145,6 +152,7 @@ public class ExerciseControllerTest { .andExpect(jsonPath("$.courseId").value("0")).andReturn().getResponse().getContentAsString(); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateExerciseEmptyBody() throws Exception { var postExercise = ""; @@ -153,6 +161,7 @@ public class ExerciseControllerTest { } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateExerciseMissingDesc() throws Exception { var postExercise = """ @@ -167,6 +176,7 @@ public class ExerciseControllerTest { .andExpect(status().is4xxClientError()).andReturn().getResponse().getContentAsString(); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateExerciseMissingName() throws Exception { var postExercise = """ @@ -181,6 +191,7 @@ public class ExerciseControllerTest { .andExpect(status().is4xxClientError()).andReturn().getResponse().getContentAsString(); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateExerciseMissingDifficulty() throws Exception { var postExercise = """ @@ -195,6 +206,7 @@ public class ExerciseControllerTest { .andExpect(status().is4xxClientError()).andReturn().getResponse().getContentAsString(); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateExerciseMissingCourseId() throws Exception { var postExercise = """ @@ -210,6 +222,7 @@ public class ExerciseControllerTest { } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testUpdate() throws Exception { long id = 1L; @@ -223,6 +236,7 @@ public class ExerciseControllerTest { .andExpect(jsonPath("$.description", is(exerciseDto.getDescription()))); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testUpdateNotFound() { long id = 9999L; @@ -238,6 +252,7 @@ public class ExerciseControllerTest { } } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testUpdateIncorrectBody() { long id = 1L; diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionControllerTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionControllerTest.java index 0f5cbfa707c3660a91f6ab7efaf342fc14a88d3b..23f2b6d2d6b3fab0bb5af6f9829a51671a94dfcf 100644 --- a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionControllerTest.java +++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionControllerTest.java @@ -15,6 +15,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import java.util.ArrayList; @@ -55,6 +56,8 @@ public class QuestionControllerTest { } + + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateQuestion() throws Exception { var exerciseId = 1L; @@ -68,6 +71,7 @@ public class QuestionControllerTest { } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateQuestionEmptyQuestions() throws Exception { var prompt = """ @@ -84,6 +88,7 @@ public class QuestionControllerTest { } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateQuestionEmptyField() throws Exception { var exerciseId = 1L; @@ -93,6 +98,7 @@ public class QuestionControllerTest { posted.andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testCreateQuestionMissingField() throws Exception { var prompt = """ @@ -108,6 +114,7 @@ public class QuestionControllerTest { } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void getQuestion() throws Exception { var question = new QuestionDto("this statement is false", 1L, new ArrayList<>()); @@ -116,6 +123,7 @@ public class QuestionControllerTest { gets.andExpect(status().isOk()).andExpect(jsonPath("$.text", is("this statement is false"))); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void getQuestionNotFound() throws Exception { when(facade.find(9999)).thenThrow(new EntityNotFoundException()); @@ -124,6 +132,7 @@ public class QuestionControllerTest { } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void getAnswer() throws Exception { var sss = List.of(new AnswerDto("February", false), new AnswerDto("All of them", true)); @@ -136,6 +145,7 @@ public class QuestionControllerTest { } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void testUpdate() throws Exception { var updated = """ @@ -153,6 +163,7 @@ public class QuestionControllerTest { gets.andExpect(status().isOk()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void deleteExisting() { try { diff --git a/application/module-language-school/pom.xml b/application/module-language-school/pom.xml index d54d174bf358a4ab6e62a74c5f219f2661ab89f4..e0432efb8e77d569ade36d3887e7b248f5583863 100644 --- a/application/module-language-school/pom.xml +++ b/application/module-language-school/pom.xml @@ -69,6 +69,23 @@ <version>1.6.9</version> </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> + </dependency> + + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.fuseri</groupId> + <artifactId>module-mail</artifactId> + <version>0.0.1-SNAPSHOT</version> + </dependency> + </dependencies> <build> diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/ModuleLanguageSchoolApplication.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/ModuleLanguageSchoolApplication.java index b556a86bf1886c1f35c2714a93a2504dd9ffa3af..4bb83f9bf022ff17dc6cf1ebacfc7d14079da582 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/ModuleLanguageSchoolApplication.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/ModuleLanguageSchoolApplication.java @@ -1,13 +1,32 @@ package org.fuseri.modulelanguageschool; +import io.swagger.v3.oas.models.security.SecurityScheme; +import org.springdoc.core.customizers.OpenApiCustomizer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; @SpringBootApplication public class ModuleLanguageSchoolApplication { + + private static final String SECURITY_SCHEME_BEARER = "Bearer"; + public static final String SECURITY_SCHEME_NAME = SECURITY_SCHEME_BEARER; + public static void main(String[] args) { SpringApplication.run(ModuleLanguageSchoolApplication.class, args); } + @Bean + public OpenApiCustomizer openAPICustomizer() { + return openApi -> { + openApi.getComponents() + .addSecuritySchemes(SECURITY_SCHEME_BEARER, + new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .description("provide a valid access token") + ); + }; + } } diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/common/ResourceNotFoundException.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/common/ResourceNotFoundException.java deleted file mode 100644 index 2227c5640bba11c5405bc103d2cc4ddbd9f67c8e..0000000000000000000000000000000000000000 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/common/ResourceNotFoundException.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.fuseri.modulelanguageschool.common; - -public class ResourceNotFoundException extends RuntimeException { - public ResourceNotFoundException() { - } - - public ResourceNotFoundException(String message) { - super(message); - } - - public ResourceNotFoundException(String message, Throwable cause) { - super(message, cause); - } - - public ResourceNotFoundException(Throwable cause) { - super(cause); - } - - public ResourceNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/common/UserWithEmailAlreadyExists.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/common/UserWithEmailAlreadyExists.java new file mode 100644 index 0000000000000000000000000000000000000000..5130ca3c82e6c49ccde9b548bf66b5b2898facc7 --- /dev/null +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/common/UserWithEmailAlreadyExists.java @@ -0,0 +1,22 @@ +package org.fuseri.modulelanguageschool.common; + +public class UserWithEmailAlreadyExists extends RuntimeException { + public UserWithEmailAlreadyExists() { + } + + public UserWithEmailAlreadyExists(String message) { + super(message); + } + + public UserWithEmailAlreadyExists(String message, Throwable cause) { + super(message, cause); + } + + public UserWithEmailAlreadyExists(Throwable cause) { + super(cause); + } + + public UserWithEmailAlreadyExists(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/config/AppSecurityConfig.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/config/AppSecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..26a7e776d44a131d671aef505f2583fdb8960c15 --- /dev/null +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/config/AppSecurityConfig.java @@ -0,0 +1,43 @@ +package org.fuseri.modulelanguageschool.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@Configuration +@EnableWebSecurity +@EnableWebMvc + + +public class AppSecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + httpSecurity.csrf().disable(); + httpSecurity.authorizeHttpRequests(x -> x + .requestMatchers("/swagger-ui/**", "/v3/api-docs/**","/users/register").permitAll() + + .requestMatchers(HttpMethod.POST, "/courses/**").hasAuthority("SCOPE_test_1") + .requestMatchers(HttpMethod.DELETE, "/courses/**").hasAuthority("SCOPE_test_1") + .requestMatchers(HttpMethod.PUT, "/courses/**").hasAnyAuthority("SCOPE_test_1","SCOPE_test_2") + .requestMatchers(HttpMethod.GET, "/courses/**").hasAnyAuthority("SCOPE_test_1", "SCOPE_test_2") + + + .requestMatchers(HttpMethod.POST, "/lectures/**").hasAnyAuthority("SCOPE_test_1", "SCOPE_test_2") + .requestMatchers(HttpMethod.DELETE, "/lectures/**").hasAnyAuthority("SCOPE_test_1", "SCOPE_test_2") + .requestMatchers(HttpMethod.PUT, "/lectures/**").hasAnyAuthority("SCOPE_test_1","SCOPE_test_2") + .requestMatchers(HttpMethod.GET, "/lectures/**").hasAnyAuthority("SCOPE_test_1", "SCOPE_test_2") + + + .requestMatchers(HttpMethod.POST, "/users/**").hasAuthority("SCOPE_test_1") + .requestMatchers(HttpMethod.DELETE, "/users/**").hasAuthority("SCOPE_test_1") + .anyRequest().authenticated() + ).oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken) + ; + return httpSecurity.build(); + } +} diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/course/CourseController.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/course/CourseController.java index 62dba59d4ccd5a1d0c53d0213d57004974243b74..3fa4062ccc8ca8b0a325ee6562b0ef914f272194 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/course/CourseController.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/course/CourseController.java @@ -4,11 +4,14 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.validation.Valid; import org.fuseri.model.dto.course.CourseCreateDto; import org.fuseri.model.dto.course.CourseDto; import org.fuseri.model.dto.course.LanguageTypeDto; import org.fuseri.model.dto.course.ProficiencyLevelDto; +import org.fuseri.modulelanguageschool.ModuleLanguageSchoolApplication; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -41,6 +44,7 @@ public class CourseController { * @param dto the CourseCreateDto containing the course data * @return the newly created CourseDto */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1"})) @ApiOperation(value = "Create a new course") @PostMapping @ApiResponses({ @@ -64,6 +68,7 @@ public class CourseController { @ApiResponse(code = 200, message = "Course found"), @ApiResponse(code = 404, message = "Course not found") }) + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) public ResponseEntity<CourseDto> find(@PathVariable Long id) { CourseDto courseDto = courseFacade.findById(id); return ResponseEntity.ok(courseDto); @@ -75,6 +80,8 @@ public class CourseController { * @param page the page number to retrieve * @return the Result containing the requested page of CourseDtos */ + + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Retrieve a paginated list of courses") @GetMapping("/findAll") @ApiResponses(value = { @@ -92,6 +99,7 @@ public class CourseController { * @param lang the language to find courses of * @return the Result containing the requested page of CourseDtos */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Retrieve a paginated list of courses of a given language") @GetMapping("/findAllByLang") @ApiResponses({ @@ -110,6 +118,7 @@ public class CourseController { * @param prof the proficiency of the language * @return the Result containing the requested page of CourseDtos */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Retrieve a paginated list of courses of a given language and proficiency") @GetMapping("/findAllByLangProf") @ApiResponses({ @@ -129,6 +138,7 @@ public class CourseController { * @param dto the CourseCreateDto containing the updated course data * @return the updated CourseDto */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Update an existing course") @PutMapping("/update/{id}") @ApiResponses({ @@ -152,6 +162,7 @@ public class CourseController { @ApiResponse(code = 204, message = "Course deleted successfully"), @ApiResponse(code = 404, message = "Course not found") }) + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1"})) public ResponseEntity<Void> delete(@PathVariable Long id) { courseFacade.delete(id); return ResponseEntity.noContent().build(); @@ -161,9 +172,10 @@ public class CourseController { * Adds student to the existing course * * @param id id of course to update - * @param student UserDto for the student + * @param studentId UserDto for the student * @return the CourseDto representing the updated course */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Add student to the existing course") @PatchMapping("/enrol/{id}") @ApiResponses(value = { @@ -179,9 +191,10 @@ public class CourseController { * Removes student from the existing course * * @param id id of lecture to update - * @param student UserDto for the student + * @param studentId UserDto for the student * @return the CourseDto representing the updated course */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Remove student from the existing course") @PatchMapping("/expel/{id}") @ApiResponses(value = { @@ -189,6 +202,7 @@ public class CourseController { @ApiResponse(code = 404, message = "Course not found") }) public ResponseEntity<CourseDto> expel(@PathVariable Long id, @RequestParam Long studentId) { + CourseDto updatedCourse = courseFacade.expel(id, studentId); return ResponseEntity.ok(updatedCourse); } diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/course/CourseRepository.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/course/CourseRepository.java index 647d778b5dcb87c271bddaa2ba845e76668c5b3f..e38f745dea8175e6a06887fb477a1cbb6234fda7 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/course/CourseRepository.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/course/CourseRepository.java @@ -10,7 +10,7 @@ import java.util.List; public interface CourseRepository extends JpaRepository<Course, Long> { - @Query("SELECT c FROM Course c left join fetch User u WHERE c.language = ?1 AND u.userType!=\"ADMIN\"") + @Query("SELECT c FROM Course c left join fetch User u WHERE c.language = ?1") Course getById(Long id); @Query("SELECT c FROM Course c WHERE c.language = ?1") diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/datainitializer/DataInitializer.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/datainitializer/DataInitializer.java index b08da68c90f825334ca73c1373c16dec6f19fea1..3d09dc0503435b1d689917e73e0dd1dd839772cc 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/datainitializer/DataInitializer.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/datainitializer/DataInitializer.java @@ -7,10 +7,8 @@ import org.fuseri.modulelanguageschool.course.Language; import org.fuseri.modulelanguageschool.course.ProficiencyLevel; import org.fuseri.modulelanguageschool.lecture.Lecture; import org.fuseri.modulelanguageschool.lecture.LectureRepository; -import org.fuseri.modulelanguageschool.user.Address; import org.fuseri.modulelanguageschool.user.User; import org.fuseri.modulelanguageschool.user.UserRepository; -import org.fuseri.modulelanguageschool.user.UserType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -95,57 +93,39 @@ public class DataInitializer { private void initializeUser() { // admin - var a1 = new User("johndoe", UserType.ADMIN, "password123", "john.doe@example.com", "John", "Doe", - new Address("USA", "New York", "Main Street", "123", "10001")); - var a2 = new User("janesmith", UserType.ADMIN, "password123", "jane.smith@example.com", "Jane", "Smith", - new Address("USA", "Los Angeles", "Broadway", "456", "90012")); + var a1 = new User("johndoe", "john.doe@example.com", "John", "Doe"); + var a2 = new User("janesmith", "jane.smith@example.com", "Jane", "Smith"); // lecturer - englishLecturer = new User("anaken", UserType.LECTURER, "password123", "ana.kentinsky@example.com", "Ana", "Kentinsky", - new Address("USA", "Los Angeles", "Hollywood Blvd", "456", "90028")); - var l4 = new User("michaeljones", UserType.LECTURER, "password123", "michael.jones@example.com", "Michael", "Jones", - new Address("UK", "London", "Baker St", "789", "NW1 6XE")); - var l5 = new User("clairedupont", UserType.LECTURER, "password123", "claire.dupont@example.com", "Claire", "Dupont", - new Address("France", "Paris", "Champs-Élysées", "456", "75008")); - germanLecturer = new User("maxmustermann", UserType.LECTURER, "password123", "max.mustermann@example.com", "Max", "Mustermann", - new Address("Germany", "Berlin", "Friedrichstrasse", "123", "10117")); + englishLecturer = new User("anaken", "ana.kentinsky@example.com", "Ana", "Kentinsky"); + var l4 = new User("michaeljones", "michael.jones@example.com", "Michael", "Jones"); + var l5 = new User("clairedupont", "claire.dupont@example.com", "Claire", "Dupont"); + germanLecturer = new User("maxmustermann", "max.mustermann@example.com", "Max", "Mustermann"); // students - User s7 = new User("samuelsmith", UserType.STUDENT, "password123", "samuel.smith@example.com", "Samuel", "Smith", - new Address("New York", "USA", "Fifth Ave", "100", "10019")); + User s7 = new User("samuelsmith", "samuel.smith@example.com", "Samuel", "Smith"); - User s8 = new User("jessicanguyen", UserType.STUDENT, "password123", "jessica.nguyen@example.com", "Jessica", "Nguyen", - new Address("Los Angeles", "USA", "Sunset Blvd", "789", "90046")); + User s8 = new User("jessicanguyen", "jessica.nguyen@example.com", "Jessica", "Nguyen"); - User s9 = new User("peterhansen", UserType.STUDENT, "password123", "peter.hansen@example.com", "Peter", "Hansen", - new Address("London", "UK", "Oxford St", "234", "W1C 1JG")); + User s9 = new User("peterhansen", "peter.hansen@example.com", "Peter", "Hansen"); - User s10 = new User("luciedupont", UserType.STUDENT, "password123", "lucie.dupont@example.com", "Lucie", "Dupont", - new Address("Paris", "France", "Rue de Rivoli", "15", "75001")); + User s10 = new User("luciedupont", "lucie.dupont@example.com", "Lucie", "Dupont"); - User s11 = new User("hansschmidt", UserType.STUDENT, "password123", "hans.schmidt@example.com", "Hans", "Schmidt", - new Address("Berlin", "Germany", "Unter den Linden", "45", "10117")); + User s11 = new User("hansschmidt", "hans.schmidt@example.com", "Hans", "Schmidt"); - User s12 = new User("emmajones", UserType.STUDENT, "password123", "emma.jones@example.com", "Emma", "Jones", - new Address("New York", "USA", "Broadway", "456", "10003")); + User s12 = new User("emmajones", "emma.jones@example.com", "Emma", "Jones"); - User s13 = new User("oliversmith", UserType.STUDENT, "password123", "oliver.smith@example.com", "Oliver", "Smith", - new Address("London", "UK", "Baker Street", "22", "W1U 3BW")); + User s13 = new User("oliversmith", "oliver.smith@example.com", "Oliver", "Smith"); - User s14 = new User("lauragarcia", UserType.STUDENT, "password123", "laura.garcia@example.com", "Laura", "Garcia", - new Address("Madrid", "Spain", "Calle Mayor", "18", "28013")); + User s14 = new User("lauragarcia", "laura.garcia@example.com", "Laura", "Garcia"); - User s15 = new User("felixmueller", UserType.STUDENT, "password123", "felix.mueller@example.com", "Felix", "Mueller", - new Address("Berlin", "Germany", "Torstrasse", "32", "10119")); + User s15 = new User("felixmueller", "felix.mueller@example.com", "Felix", "Mueller"); - User s16 = new User("emiliedupont", UserType.STUDENT, "password123", "emilie.dupont@example.com", "Emilie", "Dupont", - new Address("Paris", "France", "Rue de Rivoli", "5", "75001")); + User s16 = new User("emiliedupont", "emilie.dupont@example.com", "Emilie", "Dupont"); - User s17 = new User("peterkovac", UserType.STUDENT, "password123", "pkovac@example.com", "Peter", "Kovac", - new Address("Bratislava", "Slovakia", "Main Street", "123", "12345")); + User s17 = new User("peterkovac", "pkovac@example.com", "Peter", "Kovac"); - User s18 = new User("davidprachar", UserType.STUDENT, "password123", "prachar@example.com", "David", "Prachar", - new Address("Brno", "Czechia", "Main Street", "123", "12345")); + User s18 = new User("davidprachar", "prachar@example.com", "David", "Prachar"); // language_proficiency englishLecturer.addLanguageProficiency(Language.ENGLISH, ProficiencyLevel.C2N); diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/datainitializer/DataInitializerController.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/datainitializer/DataInitializerController.java index 40c01e847dfca7a6fda7b8fb4b29cb491ba1c739..0bc4d2f431fb7af305a6fa5b7bdd3ebc5026435c 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/datainitializer/DataInitializerController.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/datainitializer/DataInitializerController.java @@ -3,8 +3,12 @@ package org.fuseri.modulelanguageschool.datainitializer; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import org.fuseri.modulelanguageschool.ModuleLanguageSchoolApplication; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -20,22 +24,24 @@ public class DataInitializerController { this.dataInitializer = dataInitializer; } - @Operation(summary = "Seed language school database", description = "Seeds language school database. Drops all data first") + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1"}) + ,summary = "Seed language school database", description = "Seeds language school database. Drops all data first") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Data initialized successfully."), }) @PostMapping - public ResponseEntity<Void> initialize() { + public ResponseEntity<Void> initialize(@AuthenticationPrincipal OAuth2IntrospectionAuthenticatedPrincipal principal) { dataInitializer.initialize(); return ResponseEntity.noContent().build(); } - @Operation(summary = "Drop language school database", description = "Drops all data from language school database") + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1"}) + ,summary = "Drop language school database", description = "Drops all data from language school database") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Data dropped successfully."), }) @DeleteMapping - public ResponseEntity<Void> drop() { + public ResponseEntity<Void> drop(@AuthenticationPrincipal OAuth2IntrospectionAuthenticatedPrincipal principal) { dataInitializer.drop(); return ResponseEntity.noContent().build(); } diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/exceptions/RestResponseEntityExceptionHandler.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/exceptions/RestResponseEntityExceptionHandler.java index 0c6fb9d71ebbfde07f35e1f0fc94268111f902a3..d0026383765ce69f05499dd79842cda52ef3810d 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/exceptions/RestResponseEntityExceptionHandler.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/exceptions/RestResponseEntityExceptionHandler.java @@ -3,10 +3,12 @@ package org.fuseri.modulelanguageschool.exceptions; import jakarta.persistence.EntityNotFoundException; import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.fuseri.modulelanguageschool.common.UserWithEmailAlreadyExists; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.util.UrlPathHelper; @@ -33,6 +35,22 @@ public class RestResponseEntityExceptionHandler { return buildResponseEntity(error); } + /** + * Handle UserWithEmailAlreadyExists exceptions + * + * @param ex exception + * @param request request + * @return response entity + */ + @ExceptionHandler(value = {UserWithEmailAlreadyExists.class, MissingServletRequestParameterException.class}) + public ResponseEntity<ApiError> handleUserWithEmailAlreadyExistsError(UserWithEmailAlreadyExists ex, HttpServletRequest request) { + ApiError error = new ApiError( + HttpStatus.BAD_REQUEST, + ex, + URL_PATH_HELPER.getRequestUri(request)); + return buildResponseEntity(error); + } + /** * Handle Validation exceptions * diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/lecture/LectureController.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/lecture/LectureController.java index 8ace25211f77c35d3485cd4721d8cb09014454e8..6a62e2e0ab5e16fb1d0e61ad6539fd62913b26df 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/lecture/LectureController.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/lecture/LectureController.java @@ -4,9 +4,12 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.validation.Valid; import org.fuseri.model.dto.lecture.LectureCreateDto; import org.fuseri.model.dto.lecture.LectureDto; +import org.fuseri.modulelanguageschool.ModuleLanguageSchoolApplication; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -54,6 +57,8 @@ public class LectureController { * @param courseId the ID of the lecture to find * @return the LectureDto representing the found lecture */ + + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Retrieve a lecture by its ID") @GetMapping("find/{courseId}") @ApiResponses(value = { @@ -71,6 +76,7 @@ public class LectureController { * @param courseId the course to retrieve lectures from * @return the list of LectureDtos */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Retrieve a list of lectures for the corresponding course") @GetMapping("/findByCourse") @ApiResponses(value = { @@ -87,6 +93,7 @@ public class LectureController { * @param lecture the CourseCreateDto representing the updated lecture * @return the LectureDto representing the updated lecture */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Update an existing lecture") @PutMapping("/update/{id}") @ApiResponses(value = { @@ -103,6 +110,7 @@ public class LectureController { * * @param id the ID of the lecture to delete */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Delete a lecture by its ID") @DeleteMapping("/delete/{id}") @ApiResponses(value = { @@ -122,6 +130,7 @@ public class LectureController { * @param lecturerId UserDto for the course lecturer * @return the LectureDto representing the updated lecture */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Add lecturer to the existing lecture") @PatchMapping("/setLecturer/{id}") @ApiResponses(value = { @@ -140,6 +149,7 @@ public class LectureController { * @param studentId id for the course student * @return the LectureDto representing the updated lecture */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Add student to the existing lecture") @PatchMapping("/enrol/{id}") @ApiResponses(value = { @@ -158,6 +168,7 @@ public class LectureController { * @param studentId id for the course student * @return the LectureDto representing the updated lecture */ + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1","test_2"})) @ApiOperation(value = "Remove student from the existing lecture") @PatchMapping("/expel/{id}") @ApiResponses(value = { diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/Address.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/Address.java deleted file mode 100644 index f9149c09277e3eae763434b6beb8ae203e346540..0000000000000000000000000000000000000000 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/Address.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.fuseri.modulelanguageschool.user; - -import jakarta.persistence.Embeddable; -import lombok.*; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode -@Embeddable -public class Address { - - private String country; - - private String city; - - private String street; - - private String houseNumber; - - private String zip; -} diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/User.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/User.java index 72ad34887f756b1971ed87d60fd763a90d64cc17..cd86d5b3046ea481e93c9959cfc0ef545e020728 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/User.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/User.java @@ -1,7 +1,17 @@ package org.fuseri.modulelanguageschool.user; -import jakarta.persistence.*; -import lombok.*; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import org.fuseri.modulelanguageschool.common.DomainObject; import org.fuseri.modulelanguageschool.course.Course; import org.fuseri.modulelanguageschool.course.Language; @@ -24,20 +34,12 @@ public class User extends DomainObject { private String username; - @Enumerated(EnumType.STRING) - private UserType userType; - - private String password; - private String email; private String firstName; private String lastName; - @Embedded - private Address address; - @ManyToMany @JoinTable(name = "user_course", joinColumns = @JoinColumn(name = "student_id"), @@ -48,15 +50,11 @@ public class User extends DomainObject { @ElementCollection private Map<Language, ProficiencyLevel> languageProficiency; - public User(String username, UserType userType, String password, - String email, String firstName, String lastName, Address address) { + public User(String username, String email, String firstName, String lastName) { this.username = username; - this.userType = userType; - this.password = password; this.email = email; this.firstName = firstName; this.lastName = lastName; - this.address = address; this.courses = new HashSet<>(); this.languageProficiency = new HashMap<>(); } diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserController.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserController.java index b46f7761502683ef3112fd12b61237f11073d6f8..85e4395cdf269ce04d8323e07c52f551e37b11e2 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserController.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserController.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.persistence.EntityNotFoundException; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; @@ -13,13 +14,14 @@ import org.fuseri.model.dto.course.CourseDto; import org.fuseri.model.dto.user.UserAddLanguageDto; import org.fuseri.model.dto.user.UserCreateDto; import org.fuseri.model.dto.user.UserDto; -import org.fuseri.model.dto.user.UserLoginDto; +import org.fuseri.modulelanguageschool.ModuleLanguageSchoolApplication; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal; import org.springframework.web.bind.annotation.*; - import java.util.List; @RestController @@ -33,7 +35,8 @@ public class UserController { this.facade = facade; } - @Operation(summary = "Get a user by Id", description = "Returns a user with specified Id") + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {}) + ,summary = "Get a user by Id", description = "Returns a user with specified Id") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "User with the specified Id is retrieved Successfuly", content = @Content(schema = @Schema(implementation = UserDto.class) @@ -41,7 +44,7 @@ public class UserController { @ApiResponse(responseCode = "404", description = "User with the specified ID was not found.") }) @GetMapping("/{id}") - public ResponseEntity<UserDto> find(@PathVariable @NotNull Long id) { + public ResponseEntity<UserDto> find(@PathVariable @NotNull Long id,@AuthenticationPrincipal OAuth2IntrospectionAuthenticatedPrincipal principal) { try { return ResponseEntity.ok(facade.find(id)); } catch (EntityNotFoundException e) { @@ -49,18 +52,20 @@ public class UserController { } } - @Operation(summary = "Create a User", description = "Creates a new User.") + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1"}) + ,summary = "Create a User", description = "Creates a new User.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "User created successfully."), @ApiResponse(responseCode = "400", description = "Invalid input.") }) @PostMapping - public ResponseEntity<UserDto> create(@Valid @RequestBody UserCreateDto dto) { + public ResponseEntity<UserDto> create(@Valid @RequestBody UserCreateDto dto,@AuthenticationPrincipal OAuth2IntrospectionAuthenticatedPrincipal principal) { UserDto user = facade.create(dto); return ResponseEntity.status(HttpStatus.CREATED).body(user); } - @Operation(summary = "Delete a User with specified ID", description = "Deletes a User with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {"test_1"}) + ,summary = "Delete a User with specified ID", description = "Deletes a User with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "User with the specified ID deleted successfully."), }) @@ -70,7 +75,8 @@ public class UserController { return ResponseEntity.noContent().build(); } - @Operation(summary = "Update a User", description = "Updates a User with the specified ID.") + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {}) + ,summary = "Update a User", description = "Updates a User with the specified ID.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "User with the specified ID updated successfully."), @ApiResponse(responseCode = "400", description = "Invalid input."), @@ -85,7 +91,8 @@ public class UserController { } } - @Operation(summary = "Get Users in paginated format", description = "Returns Users in paginated format.") + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {}), + summary = "Get Users in paginated format", description = "Returns Users in paginated format.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved paginated Users"), @ApiResponse(responseCode = "400", description = "Invalid page number supplied"), @@ -96,19 +103,16 @@ public class UserController { return ResponseEntity.ok(a); } - //TODO: add authentication M3? - @PostMapping("/login") - public ResponseEntity<String> login(@RequestBody @Valid UserLoginDto dto) { - return ResponseEntity.ok(String.format("User %s has spawned", dto.getUsername())); - } - //TODO: add authentication M3? - @PostMapping("/{id}/logout") - public ResponseEntity<String> logout(@PathVariable @NotNull Long id) { - return ResponseEntity.ok("user has logged out"); + @Operation(summary = "Registers a new user", description = "saves a new user into the database.") + @PostMapping("/register") + public ResponseEntity<UserDto> register(@RequestBody @Valid UserCreateDto dto) { + UserDto user = facade.register(dto); + return ResponseEntity.status(HttpStatus.CREATED).body(user); } - @Operation(summary = "get finished courses", description = "retrieves finished courses of user with given Id") + + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {}),summary = "get finished courses", description = "retrieves finished courses of user with given Id") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved finished courses"), @ApiResponse(responseCode = "400", description = "Invalid input") @@ -118,7 +122,8 @@ public class UserController { return ResponseEntity.ok(facade.getFinished(id)); } - @Operation(summary = "get enrolled courses", description = "retrieves currently enrolled courses of user with given Id") + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {}) + ,summary = "get enrolled courses", description = "retrieves currently enrolled courses of user with given Id") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved enrolled courses"), @ApiResponse(responseCode = "400", description = "Invalid input") @@ -128,7 +133,8 @@ public class UserController { return ResponseEntity.ok(facade.getEnrolled(id)); } - @Operation(summary = "adds a language", description = "adds a new language and proficiency to user") + @Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME,scopes = {}), + summary = "adds a language", description = "adds a new language and proficiency to user") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully added a language"), @ApiResponse(responseCode = "404", description = "User with given Id does not exist"), @@ -142,4 +148,5 @@ public class UserController { return ResponseEntity.notFound().build(); } } + } diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserFacade.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserFacade.java index 9d822ff863d163ffb110a88fe96d67297c2ca8a3..3e3f1b33f38f1d83d0cc155ca93827cbba3a6c42 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserFacade.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserFacade.java @@ -15,6 +15,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Optional; @Service @Transactional @@ -35,6 +36,15 @@ public class UserFacade { return mapper.toDto(service.find(id)); } + public UserDto register(UserCreateDto dto) { + Optional<User> optionalUser = service.findUserByEmail(dto.getEmail()); + if (optionalUser.isPresent()) { + return mapper.toDto(optionalUser.get()); + } + var user = mapper.fromCreateDto(dto); + return mapper.toDto(service.create(user)); + } + public UserDto create(UserCreateDto dto) { var user = mapper.fromCreateDto(dto); return mapper.toDto(service.create(user)); diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserRepository.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserRepository.java index 7651bda1996f2475cf8653edc7b24c21573354d1..b22b70fb0ad7c678bbc4713330151648340d5ce3 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserRepository.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserRepository.java @@ -6,10 +6,15 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Optional; @Repository public interface UserRepository extends JpaRepository<User, Long> { + Optional<User> findByEmail(String email); + + Boolean existsByEmail(String email); + @Query("SELECT c FROM Course c Left Join FETCH User d WHERE d.id = :id AND c.finished=FALSE") List<Course> getEnrolled(Long id); diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserService.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserService.java index 72b25dbe4b99b6890114df9ff77ac7de8ca49985..a01d981000e4c0aaea04267e30446495c9fa81e5 100644 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserService.java +++ b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserService.java @@ -3,6 +3,7 @@ package org.fuseri.modulelanguageschool.user; import jakarta.persistence.EntityNotFoundException; import lombok.Getter; import org.fuseri.modulelanguageschool.common.DomainService; +import org.fuseri.modulelanguageschool.common.UserWithEmailAlreadyExists; import org.fuseri.modulelanguageschool.course.Course; import org.fuseri.modulelanguageschool.course.Language; import org.fuseri.modulelanguageschool.course.ProficiencyLevel; @@ -24,10 +25,22 @@ public class UserService extends DomainService<User> { this.repository = repository; } + @Override + public User create(User entity) { + if (repository.existsByEmail(entity.getEmail())) { + throw new UserWithEmailAlreadyExists("User with " + entity.getEmail() + " already exists."); + } + return super.create(entity); + } + @Transactional(readOnly = true) public User find(Long id) { return repository.findById(id) - .orElseThrow(() -> new EntityNotFoundException("User '" + id + "' not found.")); + .orElseThrow(() -> new EntityNotFoundException("User " + id + "' not found.")); + } + + public Optional<User> findUserByEmail(String email) { + return repository.findByEmail(email); } public List<Course> getEnrolled(Long id) { diff --git a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserType.java b/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserType.java deleted file mode 100644 index f01beaf02c9231c78f7fd5dff7baa08222389c32..0000000000000000000000000000000000000000 --- a/application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/user/UserType.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.fuseri.modulelanguageschool.user; - -public enum UserType { - ADMIN, - STUDENT, - LECTURER -} diff --git a/application/module-language-school/src/main/resources/application.properties b/application/module-language-school/src/main/resources/application.properties index aa1b054a6eb4a872473cf01a4a990a9c5334c9c1..07e7843966912ace08e6551ccc4816d582485bd0 100644 --- a/application/module-language-school/src/main/resources/application.properties +++ b/application/module-language-school/src/main/resources/application.properties @@ -1,4 +1,18 @@ -server.port=5000 + +server.port=8081 +#TODO +#server.servlet.context-path=/resource-server +#spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/ +#spring.security.oauth2.resourceserver.jwt.jwk-set-uri:=http://localhost:5000/auth/trying + +spring.h2.console.enabled=true + +spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://oidc.muni.cz/oidc/introspect +spring.security.oauth2.resourceserver.opaque-token.client-id=d57b3a8f-156e-46de-9f27-39c4daee05e1 +spring.security.oauth2.resourceserver.opaque-token.client-secret=fa228ebc-4d54-4cda-901e-4d6287f8b1652a9c9c44-73c9-4502-973f-bcdb4a8ec96a + + +#TODO END management.endpoints.web.exposure.include=health,metrics,prometheus management.endpoint.health.show-details=always @@ -15,4 +29,17 @@ spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.show-sql=true spring.jackson.property-naming-strategy=LOWER_CAMEL_CASE spring.cache.type=NONE -appconfig.enablecache=false \ No newline at end of file +appconfig.enablecache=false + + + +#org.springframework.web.client.RestTemplate: debug +#org.springframework.security: debug +#org.springframework.security.web.DefaultSecurityFilterChain: warn +#org.springframework.security.web.context.HttpSessionSecurityContextRepository: info +#org.springframework.security.web.FilterChainProxy: info +#org.springframework.security.web.authentication.AnonymousAuthenticationFilter: info +#org.springframework.security.config.annotation.authentication.configuration: info +#org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext: warn +#org.springframework.boot.web.embedded.tomcat: warn +#org.apache.catalina.core: warn \ No newline at end of file diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseControllerTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseControllerTest.java index e2ea898bf6b3357b45dc4a914ce541bfed507b73..553edf65f2aa7243d6cb661a6479f9c5799ef223 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseControllerTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseControllerTest.java @@ -5,9 +5,7 @@ import org.fuseri.model.dto.course.CourseCreateDto; import org.fuseri.model.dto.course.CourseDto; import org.fuseri.model.dto.course.LanguageTypeDto; import org.fuseri.model.dto.course.ProficiencyLevelDto; -import org.fuseri.model.dto.user.AddressDto; import org.fuseri.model.dto.user.UserDto; -import org.fuseri.model.dto.user.UserType; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; @@ -18,9 +16,11 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -34,7 +34,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. public class CourseControllerTest { private final CourseCreateDto courseCreateDto = new CourseCreateDto("english b2 course", 10, LanguageTypeDto.ENGLISH, ProficiencyLevelDto.B2); - private final CourseDto courseDto = new CourseDto("english b2 course", 10, LanguageTypeDto.ENGLISH, ProficiencyLevelDto.B2, new ArrayList<>(), false); + private final CourseDto courseDto = new CourseDto("english b2 course", 10, LanguageTypeDto.ENGLISH, ProficiencyLevelDto.B2); @Autowired ObjectMapper objectMapper; @@ -53,6 +53,7 @@ public class CourseControllerTest { } } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void createCourse() throws Exception { Mockito.when(courseFacade.create(ArgumentMatchers.isA(CourseCreateDto.class))).thenReturn(courseDto); @@ -66,6 +67,7 @@ public class CourseControllerTest { .andExpect(jsonPath("$.proficiency").value("B2")); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void createInvalidCourse() throws Exception { CourseCreateDto invalidCourseCreateDto = @@ -76,6 +78,7 @@ public class CourseControllerTest { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void createCourseWithoutParameter() throws Exception { mockMvc.perform(post("/courses")) @@ -83,6 +86,7 @@ public class CourseControllerTest { } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findCourse() throws Exception { Long id = 0L; @@ -96,12 +100,14 @@ public class CourseControllerTest { .andReturn().getResponse().getContentAsString(); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findCourseWithoutId() throws Exception { mockMvc.perform(get("/courses/find/")) .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findAll() throws Exception { Mockito.when(courseFacade.findAll((PageRequest) any())) @@ -111,13 +117,15 @@ public class CourseControllerTest { assertTrue(response.contains("\"content\":[]")); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findAllWithoutPage() throws Exception { mockMvc.perform(get("/courses/findAll")) - .andExpect(status().is5xxServerError()); + .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findAllByLang() throws Exception { int page = 0; @@ -131,12 +139,14 @@ public class CourseControllerTest { assertTrue(response.endsWith("[]")); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findAllByLangWithoutLang() throws Exception { mockMvc.perform(get("/courses/findAllByLang")) - .andExpect(status().is5xxServerError()); + .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findAllByLangProf() throws Exception { LanguageTypeDto lang = LanguageTypeDto.ENGLISH; @@ -150,19 +160,22 @@ public class CourseControllerTest { assertTrue(response.endsWith("[]")); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findAllByLangProfWithoutParameters() throws Exception { mockMvc.perform(get("/courses/findAllByLangProf")) - .andExpect(status().is5xxServerError()); + .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findAllByLangProfWithoutLangProf() throws Exception { String page = "0"; mockMvc.perform(get("/courses/findAllByLangProf").param("page", page)) - .andExpect(status().is5xxServerError()); + .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void updateCourse() throws Exception { Long id = 0L; @@ -181,12 +194,14 @@ public class CourseControllerTest { .andExpect(jsonPath("$.id").value(courseDto.getId())); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void updateCourseWithoutParameter() throws Exception { mockMvc.perform(put("/courses/update")) .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void deleteCourse() throws Exception { Long id = 0L; @@ -196,17 +211,19 @@ public class CourseControllerTest { .andExpect(status().is2xxSuccessful()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void deleteCourseWithoutParameter() throws Exception { mockMvc.perform(delete("/courses/delete/")) .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void enrolCourse() throws Exception { - Long id = 0L; + long id = 0L; UserDto student = new UserDto("novakovat", "novakova@gamil.com", "Tereza", - "Nováková", new AddressDto(), UserType.STUDENT); + "Nováková",new HashMap<>()); student.setId(1L); CourseDto courseDtoWithStudent = new CourseDto("english b2 course", 10, LanguageTypeDto.ENGLISH, ProficiencyLevelDto.B2); @@ -225,16 +242,18 @@ public class CourseControllerTest { .andExpect(jsonPath("$.proficiency").value("B2")); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void enrolCourseWithoutUserParameter() throws Exception { mockMvc.perform(patch("/courses/enrol/" + 0L)) - .andExpect(status().is5xxServerError()); + .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void enrolCourseWithoutCourseIdParameter() throws Exception { UserDto student = new UserDto("novakovat", "novakova@gamil.com", "Tereza", - "Nováková", new AddressDto(), UserType.STUDENT); + "Nováková",new HashMap<>()); mockMvc.perform(patch("/courses/enrol/") .content(asJsonString(student)) @@ -242,6 +261,7 @@ public class CourseControllerTest { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void expelCourse() throws Exception { Long id = 0L; @@ -250,10 +270,10 @@ public class CourseControllerTest { .thenReturn(courseDto); UserDto student = new UserDto("novakovat", "novakova@gamil.com", "Tereza", - "Nováková", new AddressDto(), UserType.STUDENT); - student.setId(0L); + "Nováková",new HashMap<>()); - mockMvc.perform(patch("/courses/expel/" + id + "?studentId=" + student.getId()) + mockMvc.perform(patch("/courses/expel/" + id) + .param("studentId","0") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.name").value("english b2 course")) @@ -263,16 +283,18 @@ public class CourseControllerTest { .andExpect(jsonPath("$.students").isEmpty()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void expelCourseWithoutUserParameter() throws Exception { mockMvc.perform(patch("/courses/expel/" + 0L)) - .andExpect(status().is5xxServerError()); + .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void deleteCourseWithoutCourseIdParameter() throws Exception { UserDto student = new UserDto("novakovat", "novakova@gamil.com", "Tereza", - "Nováková", new AddressDto(), UserType.STUDENT); + "Nováková",new HashMap<>()); mockMvc.perform(patch("/courses/expel/") .content(asJsonString(student)) diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseFacadeTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseFacadeTest.java index c1567d6765b46c33443ab09e94dce5a7c1d46fd6..dd7ee2b8054fae35b64a0c2f92fbd858d15ebe8f 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseFacadeTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseFacadeTest.java @@ -5,7 +5,9 @@ import org.fuseri.model.dto.course.CourseCreateDto; import org.fuseri.model.dto.course.CourseDto; import org.fuseri.model.dto.course.LanguageTypeDto; import org.fuseri.model.dto.course.ProficiencyLevelDto; +import org.fuseri.model.dto.user.UserDto; import org.fuseri.modulelanguageschool.user.User; +import org.fuseri.modulelanguageschool.user.UserMapper; import org.fuseri.modulelanguageschool.user.UserService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -17,7 +19,7 @@ import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -32,8 +34,10 @@ import static org.mockito.Mockito.when; @AutoConfigureMockMvc final class CourseFacadeTest { + private final UserDto USER = new UserDto("novakovat", + "novakova@gamil.com", "Tereza", "Nováková",new HashMap<>()); private final CourseDto courseDto = new CourseDto("AJ1", 10, - LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1, new ArrayList<>(), false); + LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1); private final CourseCreateDto courseCreateDto = new CourseCreateDto("AJ1", 10, LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1); private final Course course = new Course(); @@ -137,14 +141,16 @@ final class CourseFacadeTest { @Test void testExpel() { Long id = 0L; + when(userService.find(anyLong())).thenReturn(user); when(courseMapper.mapToDto(course)).thenReturn(courseDto); - when(userService.find(0L)).thenReturn(user); when(courseService.expel(anyLong(), any(User.class))).thenReturn(course); - CourseDto actualDto = courseFacade.expel(id, 0L); + CourseDto actualDto = courseFacade.expel(id, 1L); assertNotNull(actualDto); assertEquals(courseDto, actualDto); } + + } diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseServiceTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseServiceTest.java index 3d92ba1881bd3d3f1fec8087cd6e01fd04cb51bc..01652d57ce30032f1e000e962ee8a96cf37a48d6 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseServiceTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/course/CourseServiceTest.java @@ -1,8 +1,6 @@ package org.fuseri.modulelanguageschool.course; -import org.fuseri.modulelanguageschool.user.Address; import org.fuseri.modulelanguageschool.user.User; -import org.fuseri.modulelanguageschool.user.UserType; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -21,21 +19,21 @@ import static org.mockito.Mockito.*; @SpringBootTest final class CourseServiceTest { - private final Course course = new Course("AJ1", 10, - Language.ENGLISH, ProficiencyLevel.A1); - private final User user = new User("novakovat", UserType.STUDENT, - "novakova@gamil.com", "password", "Tereza", - "Nováková", new Address(), new HashSet<>(), new HashMap<>()); - private final Course courseWithEnrolledStudent = new Course("AJ1", 10, - Language.ENGLISH, ProficiencyLevel.A1, new ArrayList<>(List.of(user)), false); - private final List<Course> courses = List.of(course, course); - @MockBean private CourseRepository courseRepository; @Autowired private CourseService courseService; + private final Course course = new Course("AJ1", 10, + Language.ENGLISH, ProficiencyLevel.A1, new ArrayList<>(), false); + + private final User user = new User("novakovat", "novakova@gamil.com", "Tereza", + "Nováková", new HashSet<>(), new HashMap<>()); // student + private final Course courseWithEnrolledStudent = new Course("AJ1", 10, + Language.ENGLISH, ProficiencyLevel.A1, new ArrayList<>(List.of(user)), false); + private final List<Course> courses = List.of(course, course); + @Test void save() { when(courseRepository.save(course)).thenReturn(course); diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureControllerTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureControllerTest.java index b20ba4d8f7cbceaf23e3ba827c4c38ca50b2d7bf..5fe719105f43d2669b3e38e7c642c12050e3ef80 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureControllerTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureControllerTest.java @@ -4,10 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.fuseri.model.dto.lecture.LectureCreateDto; import org.fuseri.model.dto.lecture.LectureDto; -import org.fuseri.model.dto.user.AddressDto; import org.fuseri.model.dto.user.UserDto; -import org.fuseri.model.dto.user.UserType; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; @@ -16,12 +13,13 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; -import java.util.List; +import java.util.HashMap; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; @@ -33,15 +31,23 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. public class LectureControllerTest { private final LocalDateTime now = LocalDateTime.now(); + private final LectureCreateDto lectureCreateDto = new LectureCreateDto( + now.plusDays(2), + now.plusDays(2).plusHours(2), + "Learning how to spell deprecated", + 10, 0L); + private final LectureDto lectureDto = new LectureDto( + now.plusDays(2), + now.plusDays(2).plusHours(2), + "Learning how to spell deprecated", + 10, 0L, 0L, Collections.emptyList()); + @Autowired ObjectMapper objectMapper; - private LectureCreateDto lectureCreateDto; - private LectureDto lectureDto; - private LectureDto lectureDtoWithStudent; - private UserDto student; - private UserDto lecturer; + @Autowired private MockMvc mockMvc; + @MockBean private LectureFacade lectureFacade; @@ -55,32 +61,7 @@ public class LectureControllerTest { } } - @BeforeEach - void setup() { - student = new UserDto("novakovat", "novakovat@gamil.com", "Tereza", - "Nováková", new AddressDto(), UserType.STUDENT); - lecturer = new UserDto("novakoval", "novakoval@gamil.com", "Lucka", - "Nováková", new AddressDto(), UserType.LECTURER); - student.setId(1L); - lecturer.setId(2L); - - lectureCreateDto = new LectureCreateDto( - now.plusDays(2), - now.plusDays(2).plusHours(2), - "Learning how to spell deprecated", - 10, 0L); - lectureDto = new LectureDto( - now.plusDays(2), - now.plusDays(2).plusHours(2), - "Learning how to spell deprecated", - 10, lecturer.getId(), 0L, Collections.emptyList()); - lectureDtoWithStudent = new LectureDto( - now.plusDays(2), - now.plusDays(2).plusHours(2), - "Learning how to spell deprecated", - 10, lecturer.getId(), 0L, List.of(student.getId())); - } - + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void createLecture() throws Exception { Mockito.when(lectureFacade.create(ArgumentMatchers.isA(LectureCreateDto.class))).thenReturn(lectureDto); @@ -92,10 +73,11 @@ public class LectureControllerTest { .andExpect(jsonPath("$.lectureTo").isNotEmpty()) .andExpect(jsonPath("$.topic").value("Learning how to spell deprecated")) .andExpect(jsonPath("$.capacity").value("10")) - .andExpect(jsonPath("$.lecturerId").value("2")) + .andExpect(jsonPath("$.lecturerId").value("0")) .andExpect(jsonPath("$.courseId").value("0")); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void createInvalidLecture() throws Exception { LectureCreateDto invalidLectureCreateDto = @@ -106,12 +88,14 @@ public class LectureControllerTest { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void createLectureWithoutParameter() throws Exception { mockMvc.perform(post("/lectures")) .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findLecture() throws Exception { Long id = 0L; @@ -122,16 +106,18 @@ public class LectureControllerTest { .andExpect(jsonPath("$.lectureTo").isNotEmpty()) .andExpect(jsonPath("$.topic").value("Learning how to spell deprecated")) .andExpect(jsonPath("$.capacity").value("10")) - .andExpect(jsonPath("$.lecturerId").value("2")) + .andExpect(jsonPath("$.lecturerId").value("0")) .andExpect(jsonPath("$.courseId").value("0")); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findLectureWithoutId() throws Exception { mockMvc.perform(get("/lectures/find/")) .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findLecturesByCourse() throws Exception { Long id = 0L; @@ -143,12 +129,15 @@ public class LectureControllerTest { assertTrue(response.endsWith("[]")); } + //TODO: FIX NO PARAM BY COURSE + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void findLecturesByCourseWithoutParameter() throws Exception { mockMvc.perform(get("/lectures/findByCourse")) - .andExpect(status().is5xxServerError()); + .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void updateLecture() throws Exception { Long id = 0L; @@ -163,16 +152,18 @@ public class LectureControllerTest { .andExpect(jsonPath("$.lectureTo").isNotEmpty()) .andExpect(jsonPath("$.topic").value("Learning how to spell deprecated")) .andExpect(jsonPath("$.capacity").value("10")) - .andExpect(jsonPath("$.lecturerId").value("2")) + .andExpect(jsonPath("$.lecturerId").value("0")) .andExpect(jsonPath("$.courseId").value("0")); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void updateLectureWithoutParameter() throws Exception { mockMvc.perform(put("/lectures/update")) .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void deleteLecture() throws Exception { Long id = 0L; @@ -181,62 +172,91 @@ public class LectureControllerTest { .andExpect(status().is2xxSuccessful()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void deleteCourseWithoutParameter() throws Exception { mockMvc.perform(delete("/lectures/delete/")) .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void setLecturerForLecture() throws Exception { Long id = 0L; Mockito.when(lectureFacade.setLecturer(ArgumentMatchers.eq(id), ArgumentMatchers.isA(Long.class))) .thenReturn(lectureDto); - student.setId(0L); - mockMvc.perform(patch("/lectures/setLecturer/" + id + "?lecturerId=" + lecturer.getId()) - .content(asJsonString(student.getId())) + UserDto student = new UserDto("novakovat", "novakova@gamil.com", "Tereza", + "Nováková",new HashMap<>()); + mockMvc.perform(patch("/lectures/setLecturer/" + id) + .param("lecturerId","0") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) - .andExpect(jsonPath("$.lecturerId").value("2")); + .andExpect(jsonPath("$.lectureFrom").isNotEmpty()) + .andExpect(jsonPath("$.lectureTo").isNotEmpty()) + .andExpect(jsonPath("$.topic").value("Learning how to spell deprecated")) + .andExpect(jsonPath("$.capacity").value("10")) + .andExpect(jsonPath("$.lecturerId").value("0")) + .andExpect(jsonPath("$.courseId").value("0")); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void setLecturerForLectureWithoutParameters() throws Exception { mockMvc.perform(patch("/lectures/setLecturer")) .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void enrolLecture() throws Exception { Long id = 0L; Mockito.when(lectureFacade.enrol(ArgumentMatchers.eq(id), ArgumentMatchers.isA(Long.class))) - .thenReturn(lectureDtoWithStudent); - mockMvc.perform(patch("/lectures/enrol/" + id + "?studentId=" + student.getId()) + .thenReturn(lectureDto); + UserDto student = new UserDto("novakovat", "novakova@gamil.com", "Tereza", + "Nováková",new HashMap<>()); + mockMvc.perform(patch("/lectures/enrol/{id}", id) + .param("studentId","0") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) - .andExpect(jsonPath("$.students").isNotEmpty()); + .andExpect(jsonPath("$.lectureFrom").isNotEmpty()) + .andExpect(jsonPath("$.lectureTo").isNotEmpty()) + .andExpect(jsonPath("$.topic").value("Learning how to spell deprecated")) + .andExpect(jsonPath("$.capacity").value("10")) + .andExpect(jsonPath("$.lecturerId").value("0")) + .andExpect(jsonPath("$.courseId").value("0")); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void enrolCourseWithoutUserParameters() throws Exception { mockMvc.perform(patch("/lectures/enrol")) .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void expelLecture() throws Exception { Long id = 0L; Mockito.when(lectureFacade.expel(ArgumentMatchers.eq(id), ArgumentMatchers.isA(Long.class))) .thenReturn(lectureDto); - mockMvc.perform(patch("/lectures/expel/" + id + "?studentId=" + student.getId()) + UserDto student = new UserDto("novakovat", "novakova@gamil.com", "Tereza", + "Nováková",new HashMap<>()); + mockMvc.perform(patch("/lectures/expel/" + id) + .param("studentId","0") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) - .andExpect(jsonPath("$.students").isEmpty()); + .andExpect(jsonPath("$.lectureFrom").isNotEmpty()) + .andExpect(jsonPath("$.lectureTo").isNotEmpty()) + .andExpect(jsonPath("$.topic").value("Learning how to spell deprecated")) + .andExpect(jsonPath("$.capacity").value("10")) + .andExpect(jsonPath("$.lecturerId").value("0")) + .andExpect(jsonPath("$.courseId").value("0")); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void expelCourseWithoutUserParameters() throws Exception { mockMvc.perform(patch("/lectures/expel")) diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureFacadeTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureFacadeTest.java index a74977d6576960cb79cf77ffe511d4be21bb0377..13370d1a37ff327fa15bc8cd09ea6365ded706c4 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureFacadeTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureFacadeTest.java @@ -5,9 +5,7 @@ import org.fuseri.model.dto.course.LanguageTypeDto; import org.fuseri.model.dto.course.ProficiencyLevelDto; import org.fuseri.model.dto.lecture.LectureCreateDto; import org.fuseri.model.dto.lecture.LectureDto; -import org.fuseri.model.dto.user.AddressDto; import org.fuseri.model.dto.user.UserDto; -import org.fuseri.model.dto.user.UserType; import org.fuseri.modulelanguageschool.course.CourseService; import org.fuseri.modulelanguageschool.course.Language; import org.fuseri.modulelanguageschool.course.ProficiencyLevel; @@ -22,6 +20,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import java.time.LocalDateTime; import java.util.Collections; +import java.util.HashMap; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -37,7 +36,7 @@ import static org.mockito.Mockito.when; final class LectureFacadeTest { private final UserDto USER = new UserDto("novakovat", - "novakova@gamil.com", "Tereza", "Nováková", new AddressDto(), UserType.STUDENT); + "novakova@gamil.com", "Tereza", "Nováková",new HashMap<>()); private final LectureCreateDto lectureCreateDto = new LectureCreateDto( LocalDateTime.now().plusDays(2), LocalDateTime.now().plusDays(2).plusHours(2), diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureMapperTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureMapperTest.java index 2436becb834430514a1e2cc33d130428fce8b6c9..55f7ccb07517bedd090207e3ca6c66a974cbf49c 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureMapperTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureMapperTest.java @@ -6,10 +6,8 @@ import org.fuseri.modulelanguageschool.course.Course; import org.fuseri.modulelanguageschool.course.CourseService; import org.fuseri.modulelanguageschool.course.Language; import org.fuseri.modulelanguageschool.course.ProficiencyLevel; -import org.fuseri.modulelanguageschool.user.Address; import org.fuseri.modulelanguageschool.user.User; import org.fuseri.modulelanguageschool.user.UserService; -import org.fuseri.modulelanguageschool.user.UserType; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -17,7 +15,11 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import java.time.LocalDateTime; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; @@ -28,12 +30,10 @@ final class LectureMapperTest { private final LocalDateTime now = LocalDateTime.now(); - private final User lecturer = new User("dolezelt", UserType.LECTURER, - "dolezel@gmail.com", "password", "Tomáš", - "Doležel", new Address(), new HashSet<>(), new HashMap<>()); - private final User student = new User("novakovat", UserType.STUDENT, - "novakova@gmail.com", "password", "Tereza", - "Nováková", new Address(), new HashSet<>(), new HashMap<>()); + private final User lecturer = new User("dolezelt", "dolezel@gmail.com", "Tomáš", + "Doležel", new HashSet<>(), new HashMap<>()); + private final User student = new User("novakovat", "novakova@gmail.com", "Tereza", + "Nováková", new HashSet<>(), new HashMap<>()); private final Course course = new Course("AJ1", 10, Language.ENGLISH, ProficiencyLevel.A1); diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureRepositoryTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureRepositoryTest.java index 2991a492c633b26b6f309504be2221ea3dc454db..02aefc23777a65183f0ee2497002cc59cfa20be8 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureRepositoryTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureRepositoryTest.java @@ -3,9 +3,7 @@ package org.fuseri.modulelanguageschool.lecture; import org.fuseri.modulelanguageschool.course.Course; import org.fuseri.modulelanguageschool.course.Language; import org.fuseri.modulelanguageschool.course.ProficiencyLevel; -import org.fuseri.modulelanguageschool.user.Address; import org.fuseri.modulelanguageschool.user.User; -import org.fuseri.modulelanguageschool.user.UserType; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -15,7 +13,11 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import java.time.LocalDateTime; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; @DataJpaTest class LectureRepositoryTest { @@ -29,12 +31,10 @@ class LectureRepositoryTest { private final Course course = new Course("AJ1", 10, Language.ENGLISH, ProficiencyLevel.A1); - private final User student = new User("novakovat", UserType.STUDENT, - "novakova@gmail.com", "password", "Tereza", - "Nováková", new Address(), new HashSet<>(), new HashMap<>()); - private final User lecturer = new User("dolezelt", UserType.LECTURER, - "dolezel@gmail.com", "password", "Tomáš", - "Doležel", new Address(), new HashSet<>(), new HashMap<>()); + private final User student = new User("novakovat", "novakova@gmail.com", "Tereza", + "Nováková", new HashSet<>(), new HashMap<>()); + private final User lecturer = new User("dolezelt", "dolezel@gmail.com", "Tomáš", + "Doležel", new HashSet<>(), new HashMap<>()); private final Lecture lecture = new Lecture( LocalDateTime.now().plusDays(2), LocalDateTime.now().plusDays(2).plusHours(2), @@ -106,6 +106,7 @@ class LectureRepositoryTest { Assertions.assertEquals(1, found.size()); Assertions.assertEquals(found.get(0), lecture); } + @Test void testFindAllLectures() { Lecture lecture1 = new Lecture(); diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureServiceTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureServiceTest.java index 814466963f667f324f1c84ff3ed46f3b4646d6a7..ccfea14acce9c9efbc0154be41ea0bbd95192c13 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureServiceTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/lecture/LectureServiceTest.java @@ -3,9 +3,7 @@ package org.fuseri.modulelanguageschool.lecture; import org.fuseri.modulelanguageschool.course.Course; import org.fuseri.modulelanguageschool.course.Language; import org.fuseri.modulelanguageschool.course.ProficiencyLevel; -import org.fuseri.modulelanguageschool.user.Address; import org.fuseri.modulelanguageschool.user.User; -import org.fuseri.modulelanguageschool.user.UserType; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -14,7 +12,11 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.web.server.ResponseStatusException; import java.time.LocalDateTime; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; import static org.mockito.Mockito.*; @@ -29,12 +31,10 @@ final class LectureServiceTest { private final Course course = new Course("AJ1", 10, Language.ENGLISH, ProficiencyLevel.A1); - private final User student = new User("novakovat", UserType.STUDENT, - "novakova@gmail.com", "password", "Tereza", - "Nováková", new Address(), new HashSet<>(), new HashMap<>()); - private final User lecturer = new User("dolezelt", UserType.LECTURER, - "dolezel@gmail.com", "password", "Tomáš", - "Doležel", new Address(), new HashSet<>(), new HashMap<>()); + private final User student = new User("novakovat", "novakova@gmail.com", "Tereza", + "Nováková", new HashSet<>(), new HashMap<>()); + private final User lecturer = new User("dolezelt", "dolezel@gmail.com", "Tomáš", + "Doležel", new HashSet<>(), new HashMap<>()); private final Lecture lecture = new Lecture( LocalDateTime.now().plusDays(2), LocalDateTime.now().plusDays(2).plusHours(2), @@ -42,9 +42,9 @@ final class LectureServiceTest { 10, course, lecturer, new ArrayList<>(List.of())); - private final User user = new User("novakovat", UserType.STUDENT, - "novakova@gamil.com", "password", "Tereza", - "Nováková", new Address(), new HashSet<>(), new HashMap<>()); + private final User user = new User("novakovat", + "novakova@gamil.com", "Tereza", + "Nováková", new HashSet<>(), new HashMap<>()); private final Lecture lectureWithEnrolledStudent = new Lecture( LocalDateTime.now().plusDays(2), diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserControllerTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserControllerTest.java index 56633ad9bf451c08381d7e0eac0ef4887ba908e1..607b3c43c2d5338c19f28c9cde6d3dcbe07c28a4 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserControllerTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserControllerTest.java @@ -5,12 +5,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.fuseri.model.dto.course.CourseDto; import org.fuseri.model.dto.course.LanguageTypeDto; import org.fuseri.model.dto.course.ProficiencyLevelDto; -import org.fuseri.model.dto.user.AddressDto; +import org.fuseri.model.dto.exercise.QuestionCreateDto; import org.fuseri.model.dto.user.UserAddLanguageDto; import org.fuseri.model.dto.user.UserCreateDto; import org.fuseri.model.dto.user.UserDto; import org.fuseri.model.dto.user.UserLoginDto; -import org.fuseri.model.dto.user.UserType; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -23,9 +22,10 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Stream; @@ -49,83 +49,26 @@ class UserControllerTest { @MockBean private UserFacade userFacade; - private static final AddressDto ADDRESS_TO_CREATE = new AddressDto( - "Czechia", "Brno", "Masarykova", "45", "90033"); - - private static final Map<LanguageTypeDto, ProficiencyLevelDto> languageProficiency = - Map.of(LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1); - - private static final List<AddressDto> INVALID_ADDRESSES = List.of( - new AddressDto("", "Brno", "Masarykova", "45", "90033"), - new AddressDto("Czechia", "", "Masarykova", "45", "90033"), - new AddressDto("Czechia", "Brno", "", "45", "90033"), - new AddressDto("Czechia", "Brno", "Masarykova", "", "90033"), - new AddressDto("Czechia", "Brno", "Masarykova", "45", ""), - new AddressDto(null, "Brno", "Masarykova", "45", "90033"), - new AddressDto("Czechia", null, "Masarykova", "45", "90033"), - new AddressDto("Czechia", "Brno", null, "45", "90033"), - new AddressDto("Czechia", "Brno", "Masarykova", null, "90033") - ); - private final UserCreateDto USER_CREATE_DTO = new UserCreateDto( - "xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", "Peter", "Novak", ADDRESS_TO_CREATE, UserType.STUDENT, languageProficiency); - - private static final UserLoginDto USER_LOGIN_DTO = new UserLoginDto( - "xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af"); + "xnovak", "xnovak@emample.com", "Peter", "Novak"); private final UserDto USER_DTO = new UserDto( - "xnovak", "xnovak@emample.com", "Peter", "Novak", ADDRESS_TO_CREATE, UserType.STUDENT); + "xnovak", "xnovak@emample.com", "Peter", "Novak",new HashMap<>()); private static Stream<UserCreateDto> invalidUsers() { - var invalidUsers = Stream.of( - new UserCreateDto("", "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", "Peter", "Novak", ADDRESS_TO_CREATE, UserType.STUDENT, languageProficiency), - new UserCreateDto("xnovak", "", - "xnovak@emample.com", "Peter", "Novak", ADDRESS_TO_CREATE, UserType.STUDENT, languageProficiency), - new UserCreateDto("xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - "", "Peter", "Novak", ADDRESS_TO_CREATE, UserType.STUDENT, languageProficiency), - new UserCreateDto("xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", "", "Novak", ADDRESS_TO_CREATE, UserType.STUDENT, languageProficiency), - new UserCreateDto("xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", "Peter", "", ADDRESS_TO_CREATE, UserType.STUDENT, languageProficiency), - new UserCreateDto(null, "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", "Peter", "Novak", ADDRESS_TO_CREATE, UserType.STUDENT, languageProficiency), - new UserCreateDto("xnovak", null, - "xnovak@emample.com", "Peter", "Novak", ADDRESS_TO_CREATE, UserType.STUDENT, languageProficiency), - new UserCreateDto("xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - null, "Peter", "Novak", ADDRESS_TO_CREATE, UserType.STUDENT, languageProficiency), - new UserCreateDto("xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", null, "Novak", ADDRESS_TO_CREATE, UserType.STUDENT, languageProficiency), - new UserCreateDto("xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", "Peter", null, ADDRESS_TO_CREATE, UserType.STUDENT, languageProficiency), - new UserCreateDto("xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", "Peter", "Novak", null, UserType.STUDENT, languageProficiency), - new UserCreateDto( - "xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", "Peter", "Novak", ADDRESS_TO_CREATE, null, languageProficiency), - new UserCreateDto( - "xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", "Peter", "Novak", ADDRESS_TO_CREATE, UserType.STUDENT, null) - ); - - var invalidAddressUsers = new ArrayList<UserCreateDto>(); - for (var invalidAddress : INVALID_ADDRESSES) { - invalidAddressUsers.add(new UserCreateDto("xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", "Peter", "Novak", invalidAddress, UserType.STUDENT, languageProficiency)); - } - - return Stream.concat(invalidUsers, invalidAddressUsers.stream()); - } - - private static Stream<UserLoginDto> invalidLoginDtoStream() { return Stream.of( - new UserLoginDto("", "1c1bbf66-6585-4978-886b-b126335ff3af"), - new UserLoginDto("xnovak", ""), - new UserLoginDto(null, "1c1bbf66-6585-4978-886b-b126335ff3af"), - new UserLoginDto("xnovak", null)); + new UserCreateDto("", "xnovak@emample.com", "Peter", "Novak"), + new UserCreateDto("xnovak", "", "Peter", "Novak"), + new UserCreateDto("xnovak", "xnovak@emample.com", "", "Novak"), + new UserCreateDto("xnovak", "xnovak@emample.com", "Peter", ""), + new UserCreateDto(null, "xnovak@emample.com", "Peter", "Novak"), + new UserCreateDto("xnovak", null, "Peter", "Novak"), + new UserCreateDto("xnovak", "xnovak@emample.com", null, "Novak"), + new UserCreateDto("xnovak", "xnovak@emample.com", "Peter", null) + ); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void createUser() throws Exception { Mockito.when(userFacade.create(ArgumentMatchers.isA(UserCreateDto.class))).thenReturn(USER_DTO); @@ -135,6 +78,7 @@ class UserControllerTest { .andExpect(status().isCreated()); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @ParameterizedTest @MethodSource("invalidUsers") void createInvalidUser(UserCreateDto user) throws Exception { @@ -145,6 +89,7 @@ class UserControllerTest { .andExpect(status().is4xxClientError()); } + @WithMockUser(authorities = {}) @Test void findUser() throws Exception { long id = 1; @@ -154,6 +99,7 @@ class UserControllerTest { .andExpect(jsonPath("$.username").value(USER_DTO.getUsername())); } + @WithMockUser(authorities = {}) @Test void findAll() throws Exception { int page = 0; @@ -166,6 +112,7 @@ class UserControllerTest { .andExpect(content().string(objectMapper.writeValueAsString(pageUserDto))); } + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void deleteUser() throws Exception { mockMvc.perform(delete("/users/{id}", 1L) @@ -173,6 +120,7 @@ class UserControllerTest { .andExpect(status().isNoContent()); } + @WithMockUser(authorities = {}) @Test void update() throws Exception { Long id = 1L; @@ -184,29 +132,7 @@ class UserControllerTest { .andExpect(status().isOk()); } - @Test - void login() throws Exception { - mockMvc.perform(post("/users/login") - .content(asJsonString(USER_LOGIN_DTO)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); - } - - @ParameterizedTest - @MethodSource("invalidLoginDtoStream") - void loginInvalidDto(UserLoginDto loginDto) throws Exception { - mockMvc.perform(post("/users/login") - .content(asJsonString(loginDto)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().is4xxClientError()); - } - - @Test - void logout() throws Exception { - mockMvc.perform(post("/users/{id}/logout", 1L)) - .andExpect(status().isOk()); - } - + @WithMockUser(authorities = {}) @Test void getFinishedCourses() throws Exception { Long id = 1L; @@ -221,6 +147,7 @@ class UserControllerTest { .andExpect(jsonPath("$[0].name", equalTo(name))); } + @WithMockUser(authorities = {}) @Test void getEnrolledCourses() throws Exception { Long id = 1L; @@ -235,6 +162,7 @@ class UserControllerTest { .andExpect(jsonPath("$[0].name", equalTo(name))); } + @WithMockUser(authorities = {}) @Test void addLanguage() throws Exception { Long id = 1L; @@ -244,10 +172,10 @@ class UserControllerTest { UserDto userWithLanguages = USER_DTO; userWithLanguages.setLanguageProficiency(Map.of(language, proficiency)); - Mockito.when(userFacade.addLanguageProficiency(id, languageDto)).thenReturn(userWithLanguages); + Mockito.when(userFacade.addLanguageProficiency(ArgumentMatchers.isA(Long.class),ArgumentMatchers.isA(UserAddLanguageDto.class))).thenReturn(userWithLanguages); mockMvc.perform(put("/users/{id}/languages", id) - .content(asJsonString(new UserAddLanguageDto(LanguageTypeDto.ENGLISH, ProficiencyLevelDto.B2))) - .contentType(MediaType.APPLICATION_JSON)) + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(languageDto))) .andExpect(status().isOk()); } diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserFacadeTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserFacadeTest.java index 5fce17087b4217a9d232b0ffb5bf53615ab31b54..3a5e05e6cbcbec1322cef0f1e901717289ee1a73 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserFacadeTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserFacadeTest.java @@ -3,7 +3,6 @@ package org.fuseri.modulelanguageschool.user; import org.fuseri.model.dto.course.CourseDto; import org.fuseri.model.dto.course.LanguageTypeDto; import org.fuseri.model.dto.course.ProficiencyLevelDto; -import org.fuseri.model.dto.user.AddressDto; import org.fuseri.model.dto.user.UserAddLanguageDto; import org.fuseri.model.dto.user.UserCreateDto; import org.fuseri.model.dto.user.UserDto; @@ -21,6 +20,7 @@ import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -49,22 +49,17 @@ final class UserFacadeTest { private static final LanguageTypeDto LANGUAGE_DTO = LanguageTypeDto.ENGLISH; private static final ProficiencyLevelDto PROFICIENCY_DTO = ProficiencyLevelDto.B2; - private static final Map<LanguageTypeDto, ProficiencyLevelDto> LANGUAGE_PROFICIENCY_DTO = - Map.of(LANGUAGE_DTO, PROFICIENCY_DTO); private final static List<CourseDto> COURSE_DTO_LIST = List.of(new CourseDto( "AJ1", 10, LANGUAGE_DTO, PROFICIENCY_DTO)); private static final List<Course> COURSE_LIST = List.of(new Course("AJ1", 10, Language.valueOf(LANGUAGE_DTO.name()), ProficiencyLevel.valueOf(PROFICIENCY_DTO.name()))); - private static final Address ADDRESS = new Address( - "Czechia", "Brno", "Masarykova", "45", "90033"); - private static final AddressDto ADDRESS_DTO = new AddressDto( - "Czechia", "Brno", "Masarykova", "45", "90033"); +// private static final Address ADDRESS = new Address( +// "Czechia", "Brno", "Masarykova", "45", "90033"); private final UserCreateDto USER_CREATE_DTO = new UserCreateDto( - "xnovak", "1c1bbf66-6585-4978-886b-b126335ff3af", - "xnovak@emample.com", "Peter", "Novak", ADDRESS_DTO, org.fuseri.model.dto.user.UserType.STUDENT, LANGUAGE_PROFICIENCY_DTO); - private final UserDto USER_DTO = new UserDto("xnovak", "xnovak@emample.com", "Peter", "Novak", ADDRESS_DTO, org.fuseri.model.dto.user.UserType.STUDENT); + "xnovak", "xnovak@emample.com", "Peter", "Novak"); + private final UserDto USER_DTO = new UserDto("xnovak", "xnovak@emample.com", "Peter", "Novak",new HashMap<>()); private final User USER = new User( - "xnovak", UserType.STUDENT, "1234fak", "xnovak@emample.com", "Peter", "Novak", ADDRESS, Set.of(), Map.of()); + "xnovak", "xnovak@emample.com", "Peter", "Novak", Set.of(), Map.of()); @Test void find() { diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserMapperTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserMapperTest.java index 88eaeabaf0c4b61af264536090004f021f26bc95..198f0587071f04d171d609164a0a1f6c6b097779 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserMapperTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserMapperTest.java @@ -1,9 +1,7 @@ package org.fuseri.modulelanguageschool.user; -import org.fuseri.model.dto.user.AddressDto; import org.fuseri.model.dto.user.UserCreateDto; import org.fuseri.model.dto.user.UserDto; -import org.fuseri.model.dto.user.UserType; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -14,7 +12,6 @@ import org.springframework.data.domain.PageRequest; import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.Map; import static org.junit.jupiter.api.Assertions.*; @@ -25,19 +22,15 @@ class UserMapperTest { private UserMapper userMapper; private final UserDto userDto = new UserDto( - "xnovak", "xnovak@emample.com", "Peter", "Novak", - new AddressDto(), UserType.STUDENT); + "xnovak", "xnovak@emample.com", "Peter", "Novak",new HashMap<>()); private final UserCreateDto userCreateDto = new UserCreateDto( - "xnovak", "akfksobg", - "xnovak@emample.com", "Peter", "Novak", new AddressDto(), UserType.STUDENT, Map.of()); + "xnovak", "xnovak@emample.com", "Peter", "Novak"); private final User userFromCreateDto = new User( - "xnovak", org.fuseri.modulelanguageschool.user.UserType.STUDENT, "akfksobg", - "xnovak@emample.com", "Peter", "Novak", new Address(), null, new HashMap<>()); + "xnovak", "xnovak@emample.com", "Peter", "Novak", null, null); private final User userFromDto = new User( - "xnovak", org.fuseri.modulelanguageschool.user.UserType.STUDENT, null, - "xnovak@emample.com", "Peter", "Novak", new Address(), null, null); + "xnovak", "xnovak@emample.com", "Peter", "Novak", null, new HashMap<>()); @Test void nullFromCreateDto() { diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserRepositoryTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserRepositoryTest.java index 3538aff2c95173f76d0cb2e67c78f86a39b601e5..3ec9559291ffd180778ec9245b133861a69ccaca 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserRepositoryTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserRepositoryTest.java @@ -28,9 +28,7 @@ class UserRepositoryTest { private final Course course = new Course("AJ1", 10, Language.ENGLISH, ProficiencyLevel.B2); private final Set<Course> COURSES = Set.of(course); private final User user = new User( - "xnovak", UserType.STUDENT, - "1234fak", "xnovak@emample.com", "Peter", "Novak", - new Address(), COURSES, Map.of()); + "xnovak", "xnovak@emample.com", "Peter", "Novak", COURSES, Map.of()); @Test void getEnrolled() { diff --git a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserServiceTest.java b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserServiceTest.java index 062bc734f1a3e8778a951432eaf93f9b6b76e3fc..535591c54b51f85d042f3b3930f85b2782e8ce3a 100644 --- a/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserServiceTest.java +++ b/application/module-language-school/src/test/java/org/fuseri/modulelanguageschool/user/UserServiceTest.java @@ -31,11 +31,11 @@ class UserServiceTest { private UserRepository userRepository; private static final User USER = new User( - "xnovak", UserType.STUDENT, "1234fak", "xnovak@emample.com", "Peter", "Novak", new Address(), Set.of(), new HashMap<>()); + "xnovak", "xnovak@emample.com", "Peter", "Novak", Set.of(), new HashMap<>()); private static final Course COURSE = new Course("AJ1", 10, Language.ENGLISH, ProficiencyLevel.B2); private static final List<Course> COURSE_LIST = List.of(COURSE); private static final User USER_WITH_ENROLLED_COURSE = new User( - "xnovak", UserType.STUDENT, "1234fak", "xnovak@emample.com", "Peter", "Novak", new Address(), Set.of(COURSE), Map.of()); + "xnovak", "xnovak@emample.com", "Peter", "Novak", Set.of(COURSE), Map.of()); @Test void find() { diff --git a/application/module-mail/pom.xml b/application/module-mail/pom.xml index 336de3d7d05aab51b46e0d4dfa2167e23aba8565..f412bc2c1bdcddea6ff752dd069f0986f47bf250 100644 --- a/application/module-mail/pom.xml +++ b/application/module-mail/pom.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> @@ -37,7 +37,7 @@ <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> - <version>3.0.4</version> +<!-- <version>3.0.4</version>--> </dependency> <dependency> <groupId>org.fuseri</groupId> @@ -45,6 +45,11 @@ <version>0.0.1-SNAPSHOT</version> <scope>compile</scope> </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> diff --git a/application/module-mail/src/main/java/org/fuseri/modulemail/ModuleMailApplication.java b/application/module-mail/src/main/java/org/fuseri/modulemail/ModuleMailApplication.java index 53bbdb3ae377aa217193c44bd6ca5a470cf18b25..698419071a4540e3f5c703376aed7a2ec5360760 100644 --- a/application/module-mail/src/main/java/org/fuseri/modulemail/ModuleMailApplication.java +++ b/application/module-mail/src/main/java/org/fuseri/modulemail/ModuleMailApplication.java @@ -1,13 +1,31 @@ package org.fuseri.modulemail; +import io.swagger.v3.oas.models.security.SecurityScheme; +import org.springdoc.core.customizers.OpenApiCustomizer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; @SpringBootApplication public class ModuleMailApplication { + private static final String SECURITY_SCHEME_BEARER = "Bearer"; + public static final String SECURITY_SCHEME_NAME = SECURITY_SCHEME_BEARER; public static void main(String[] args) { SpringApplication.run(ModuleMailApplication.class, args); } + @Bean + public OpenApiCustomizer openAPICustomizer() { + return openApi -> { + openApi.getComponents() + .addSecuritySchemes(SECURITY_SCHEME_BEARER, + new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .description("provide a valid access token") + ); + }; + } + } diff --git a/application/module-mail/src/main/java/org/fuseri/modulemail/service/AppSecurityConfig.java b/application/module-mail/src/main/java/org/fuseri/modulemail/service/AppSecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..5f3b84a648ecb8026a46032521bcab416009eab6 --- /dev/null +++ b/application/module-mail/src/main/java/org/fuseri/modulemail/service/AppSecurityConfig.java @@ -0,0 +1,29 @@ +package org.fuseri.modulemail.service; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@Configuration +@EnableWebSecurity +@EnableWebMvc + + +public class AppSecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + httpSecurity.csrf().disable(); + httpSecurity.authorizeHttpRequests(x -> x + .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() + .anyRequest().authenticated() + + ).oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken) + ; + return httpSecurity.build(); + } +} diff --git a/application/module-mail/src/main/java/org/fuseri/modulemail/service/MailController.java b/application/module-mail/src/main/java/org/fuseri/modulemail/service/MailController.java index 58f76ef0df363a1c3f94178239c690454f001f5b..6ea75bb78369615e9f957a8d6ccec7e61d50c21a 100644 --- a/application/module-mail/src/main/java/org/fuseri/modulemail/service/MailController.java +++ b/application/module-mail/src/main/java/org/fuseri/modulemail/service/MailController.java @@ -2,12 +2,9 @@ package org.fuseri.modulemail.service; import jakarta.validation.Valid; -import jakarta.validation.constraints.PositiveOrZero; import org.fuseri.model.dto.mail.MailDto; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -24,19 +21,8 @@ public class MailController { this.service = service; } - - @GetMapping("/{id}") - public String getEmail(@PositiveOrZero @PathVariable("id") Long id) { - return "No mail with that id yet"; - } - - @DeleteMapping("/delete/{id}") - public String deleteMail(@PositiveOrZero @PathVariable("id") Long id) { - return "Nothing to delete Yet"; -} - @PostMapping() - public String sendMail(@Valid @RequestBody MailDto emailDto) { - return service.send(emailDto); + public ResponseEntity<String> sendMail(@Valid @RequestBody MailDto emailDto) { + return ResponseEntity.ok(service.send(emailDto)); } } diff --git a/application/module-mail/src/main/java/org/fuseri/modulemail/service/MailService.java b/application/module-mail/src/main/java/org/fuseri/modulemail/service/MailService.java index 06f5fb822a6b2b8757d8829456c38bdeb6bb0a8d..55831d856f87150afbec94a8ca9166388a5511a3 100644 --- a/application/module-mail/src/main/java/org/fuseri/modulemail/service/MailService.java +++ b/application/module-mail/src/main/java/org/fuseri/modulemail/service/MailService.java @@ -28,12 +28,4 @@ public class MailService { return "Success, you have sent: " + dto.content; } - public MailDto getMail(long id) { - return new MailDto("empty","empty"); // return from database once there is one - } - - public String deleteMail(long id) { - return "No mail with that Id"; - } - } diff --git a/application/module-mail/src/main/resources/application.properties b/application/module-mail/src/main/resources/application.properties index 6a14995dbd0db0d3be07e786d5fa195d7745bdf4..703710762ef1248ff489e0a4c3ff9ef60178b251 100644 --- a/application/module-mail/src/main/resources/application.properties +++ b/application/module-mail/src/main/resources/application.properties @@ -1,13 +1,19 @@ -server.port=5003 +server.port=8084 management.endpoints.web.exposure.include=health,metrics,prometheus management.endpoint.health.show-details=always management.health.defaults.enabled=true management.endpoint.health.probes.enabled=true + + spring.mail.host=smtp.gmail.com spring.mail.port=587 spring.mail.username=sprachschul@gmail.com spring.mail.password=xnyxsknctypmubbb spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true + +spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://oidc.muni.cz/oidc/introspect +spring.security.oauth2.resourceserver.opaque-token.client-id=d57b3a8f-156e-46de-9f27-39c4daee05e1 +spring.security.oauth2.resourceserver.opaque-token.client-secret=fa228ebc-4d54-4cda-901e-4d6287f8b1652a9c9c44-73c9-4502-973f-bcdb4a8ec96a diff --git a/application/module-mail/src/test/java/org/fuseri/modulemail/service/MailControllerTest.java b/application/module-mail/src/test/java/org/fuseri/modulemail/service/MailControllerTest.java index 8ec50ec90575fbb9d97be2f7fc781e13022588b6..1545d6629b6fbd07ffaf364fca1b3df4f32686f9 100644 --- a/application/module-mail/src/test/java/org/fuseri/modulemail/service/MailControllerTest.java +++ b/application/module-mail/src/test/java/org/fuseri/modulemail/service/MailControllerTest.java @@ -3,12 +3,19 @@ package org.fuseri.modulemail.service; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.fuseri.model.dto.mail.MailDto; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.security.test.context.support.WithMockUser; + + +import java.util.regex.Matcher; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -22,23 +29,12 @@ class MailControllerTest { @Autowired private MockMvc mockMvc; - @Test - void getEmail() throws Exception { - mockMvc.perform(get("/mail/{id}", 1)) - .andExpect(status().isOk()); - } - - @Test - void deleteMail() throws Exception { - mockMvc.perform(delete("/mail/delete/{id}", 1)) - .andExpect(status().isOk()); - } - + @WithMockUser(authorities = {"SCOPE_test_1"}) @Test void sendMail() throws Exception { - var mailDto = new MailDto("user@example.com", "Hello"); - MailController mailController = mock(MailController.class); - when(mailController.sendMail(mailDto)).thenReturn("Success, you have sent: " + mailDto.getContent()); + var mailDto = new MailDto("485612@muni.com", "Hello"); + MailService mailController = mock(MailService.class); + when(mailController.send(ArgumentMatchers.isA(MailDto.class))).thenReturn("Success, you have sent: " + mailDto.getContent()); mockMvc.perform(post("/mail") .content(asJsonString(mailDto)) diff --git a/application/pom.xml b/application/pom.xml index dd5ca9947c970ca1c1b83c69a96c30d5e36dd33f..d720ac945d2b4d8c36055a68eace76fc4a7323e7 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -48,6 +48,7 @@ <module>module-mail</module> <module>module-exercise</module> <module>model</module> + <module>confidentialClient</module> </modules> <properties> @@ -72,6 +73,11 @@ <scope>test</scope> </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> + </dependency> + <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId>