Merge pull request #152 from ets-cfuhrman-pfe/feat-auth-only-student

Adds (no) authentication requirement to join a room
This commit is contained in:
Gabriel Moisan Matte 2024-10-29 00:05:02 -04:00 committed by GitHub
commit ba77b73899
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 113 additions and 3 deletions

View file

@ -28,6 +28,7 @@ import OAuthCallback from './pages/AuthManager/callback/AuthCallback';
const App: React.FC = () => {
const [isAuthenticated, setIsAuthenticated] = useState(ApiService.isLoggedIn());
const [isTeacherAuthenticated, setIsTeacherAuthenticated] = useState(ApiService.isLoggedInTeacher());
const [isRoomRequireAuthentication, setRoomsRequireAuth] = useState(null);
const location = useLocation();
// Check login status every time the route changes
@ -37,7 +38,13 @@ const App: React.FC = () => {
setIsTeacherAuthenticated(ApiService.isLoggedInTeacher());
};
const fetchAuthenticatedRooms = async () => {
const data = await ApiService.getRoomsRequireAuth();
setRoomsRequireAuth(data);
};
checkLoginStatus();
fetchAuthenticatedRooms();
}, [location]);
const handleLogout = () => {
@ -76,7 +83,7 @@ const App: React.FC = () => {
{/* Pages espace étudiant */}
<Route
path="/student/join-room"
element={isAuthenticated ? <JoinRoom /> : <Navigate to="/login" />}
element={( !isRoomRequireAuthentication || isAuthenticated ) ? <JoinRoom /> : <Navigate to="/login" />}
/>
{/* Pages authentification */}

View file

@ -9,9 +9,11 @@ const OAuthCallback: React.FC = () => {
useEffect(() => {
const searchParams = new URLSearchParams(location.search);
const user = searchParams.get('user');
const username = searchParams.get('username');
if (user) {
apiService.saveToken(user);
apiService.saveUsername(username || "");
navigate('/');
} else {
navigate('/login');

View file

@ -15,9 +15,11 @@ import LoadingButton from '@mui/lab/LoadingButton';
import LoginContainer from '../../../components/LoginContainer/LoginContainer'
import ApiService from '../../../services/ApiService'
const JoinRoom: React.FC = () => {
const [roomName, setRoomName] = useState('');
const [username, setUsername] = useState('');
const [username, setUsername] = useState(ApiService.getUsername());
const [socket, setSocket] = useState<Socket | null>(null);
const [isWaitingForTeacher, setIsWaitingForTeacher] = useState(false);
const [question, setQuestion] = useState<QuestionType>();

View file

@ -105,7 +105,43 @@ class ApiService {
}
}
public saveUsername(username: string): void {
if (!username || username.length === 0) {
return;
}
const object = {
username: username
}
localStorage.setItem("username", JSON.stringify(object));
}
public getUsername(): string {
const objectStr = localStorage.getItem("username");
if (!objectStr) {
return "";
}
const object = JSON.parse(objectStr)
return object.username;
}
// Route to know if rooms need authentication to join
public async getRoomsRequireAuth(): Promise<any> {
const url: string = this.constructRequestUrl(`/auth/getRoomsRequireAuth`);
const result: AxiosResponse = await axios.get(url);
if (result.status == 200) {
return result.data.roomsRequireAuth;
}
return false;
}
public logout(): void {
localStorage.removeItem("username");
return localStorage.removeItem("jwt");
}

View file

@ -30,6 +30,7 @@ services:
SITE_URL: http://localhost
FRONTEND_PORT: 5173
USE_PORTS: false
AUTHENTICATED_ROOMS: false
volumes:
- ./server/auth_config.json:/usr/src/app/serveur/config/auth_config.json
depends_on:

View file

@ -19,3 +19,5 @@ SESSION_Secret='session_secret'
SITE_URL=http://localhost
FRONTEND_PORT=5173
USE_PORTS=false
AUTHENTICATED_ROOMS=false

View file

@ -205,3 +205,40 @@ describe(
});
})
);
describe(
"Rooms requiring authentication", () => {
// Making a copy of env variables to restore them later
const OLD_ENV_VARIABLES = process.env;
let authConfigInstance;
beforeAll(() => {
authConfigInstance = new AuthConfig();
});
// Clearing cache just in case
beforeEach(() => {
jest.resetModules();
process.env = { ...OLD_ENV_VARIABLES };
});
// Resetting the old values
afterAll(() => {
process.env = OLD_ENV_VARIABLES;
});
// tests cases as [environment variable value, expected value]
const cases = [["true", true], ["false", false], ["", false], ["other_than_true_false", false]];
test.each(cases)(
"Given %p as AUTHENTICATED_ROOMS environment variable value, returns %p",
(envVarArg, expectedResult) => {
process.env.AUTHENTICATED_ROOMS = envVarArg;
const isAuthRequired = authConfigInstance.getRoomsRequireAuth();
expect(isAuthRequired).toEqual(expectedResult);
}
);
}
)

View file

@ -44,7 +44,7 @@ class AuthManager{
async login(userInfo,req,res,next){
const tokenToSave = jwt.create(userInfo.email, userInfo._id,userInfo.roles);
res.redirect(`/auth/callback?user=${tokenToSave}`);
res.redirect(`/auth/callback?user=${tokenToSave}&username=${userInfo.name}`);
console.info(`L'utilisateur '${userInfo.name}' vient de se connecter`)
}

View file

@ -175,6 +175,17 @@ class AuthConfig {
}
}
// Check if students must be authenticated to join a room
getRoomsRequireAuth() {
const roomRequireAuth = process.env.AUTHENTICATED_ROOMS;
if (!roomRequireAuth || roomRequireAuth !== "true") {
return false;
}
return true;
}
}

View file

@ -20,6 +20,17 @@ class authController {
}
}
async getRoomsRequireAuth(req, res, next) {
const authC = new AuthConfig();
const roomsRequireAuth = authC.getRoomsRequireAuth();
const response = {
roomsRequireAuth
}
return res.json(response);
}
}
module.exports = new authController;

View file

@ -5,5 +5,6 @@ const jwt = require('../middleware/jwtToken.js');
const authController = require('../controllers/auth.js')
router.get("/getActiveAuth",authController.getActive);
router.get("/getRoomsRequireAuth", authController.getRoomsRequireAuth);
module.exports = router;