Merge pull request #13601 from Tainan404/refactor-authentication
Client authentication refactoring
This commit is contained in:
commit
7551efaa9b
@ -37,7 +37,6 @@ export default function handleValidateAuthToken({ body }, meetingId) {
|
||||
check(reasonCode, String);
|
||||
|
||||
const pendingAuths = pendingAuthenticationsStore.take(meetingId, userId, authToken);
|
||||
|
||||
Logger.info(`PendingAuths length [${pendingAuths.length}]`);
|
||||
if (pendingAuths.length === 0) return;
|
||||
|
||||
|
@ -2,32 +2,77 @@ import { Meteor } from 'meteor/meteor';
|
||||
import RedisPubSub from '/imports/startup/server/redis';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import upsertValidationState from '/imports/api/auth-token-validation/server/modifiers/upsertValidationState';
|
||||
import { ValidationStates } from '/imports/api/auth-token-validation';
|
||||
import AuthTokenValidation, { ValidationStates } from '/imports/api/auth-token-validation';
|
||||
import pendingAuthenticationsStore from '../store/pendingAuthentications';
|
||||
|
||||
export default function validateAuthToken(meetingId, requesterUserId, requesterToken, externalId) {
|
||||
try {
|
||||
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||
const EVENT_NAME = 'ValidateAuthTokenReqMsg';
|
||||
const AUTH_TIMEOUT = 120000;
|
||||
|
||||
Logger.debug('ValidateAuthToken method called', { meetingId, requesterUserId, requesterToken, externalId });
|
||||
|
||||
if (!meetingId) return false;
|
||||
|
||||
// Store reference of methodInvocationObject ( to postpone the connection userId definition )
|
||||
pendingAuthenticationsStore.add(meetingId, requesterUserId, requesterToken, this);
|
||||
upsertValidationState(meetingId, requesterUserId, ValidationStates.VALIDATING, this.connection.id);
|
||||
|
||||
const payload = {
|
||||
userId: requesterUserId,
|
||||
authToken: requesterToken,
|
||||
async function validateAuthToken(meetingId, requesterUserId, requesterToken, externalId) {
|
||||
let setTimeoutRef = null;
|
||||
const userValidation = await new Promise((res, rej) => {
|
||||
const observeFunc = (obj) => {
|
||||
if (obj.validationStatus === ValidationStates.VALIDATED) {
|
||||
clearTimeout(setTimeoutRef);
|
||||
return res(obj);
|
||||
}
|
||||
if (obj.validationStatus === ValidationStates.INVALID) {
|
||||
clearTimeout(setTimeoutRef);
|
||||
return res(obj);
|
||||
}
|
||||
};
|
||||
const authTokenValidationObserver = AuthTokenValidation.find({
|
||||
connectionId: this.connection.id,
|
||||
}).observe({
|
||||
added: observeFunc,
|
||||
changed: observeFunc,
|
||||
});
|
||||
|
||||
Logger.info(`User '${requesterUserId}' is trying to validate auth token for meeting '${meetingId}' from connection '${this.connection.id}'`);
|
||||
setTimeoutRef = setTimeout(() => {
|
||||
observeFunc.stop();
|
||||
rej();
|
||||
}, AUTH_TIMEOUT);
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
} catch (err) {
|
||||
Logger.error(`Exception while invoking method validateAuthToken ${err.stack}`);
|
||||
}
|
||||
try {
|
||||
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||
const EVENT_NAME = 'ValidateAuthTokenReqMsg';
|
||||
|
||||
Logger.debug('ValidateAuthToken method called', { meetingId, requesterUserId, requesterToken, externalId });
|
||||
|
||||
if (!meetingId) return false;
|
||||
|
||||
// Store reference of methodInvocationObject ( to postpone the connection userId definition )
|
||||
pendingAuthenticationsStore.add(meetingId, requesterUserId, requesterToken, this);
|
||||
upsertValidationState(
|
||||
meetingId,
|
||||
requesterUserId,
|
||||
ValidationStates.VALIDATING,
|
||||
this.connection.id,
|
||||
);
|
||||
|
||||
const payload = {
|
||||
userId: requesterUserId,
|
||||
authToken: requesterToken,
|
||||
};
|
||||
|
||||
Logger.info(`User '${requesterUserId}' is trying to validate auth token for meeting '${meetingId}' from connection '${this.connection.id}'`);
|
||||
|
||||
return RedisPubSub.publishUserMessage(
|
||||
CHANNEL,
|
||||
EVENT_NAME,
|
||||
meetingId,
|
||||
requesterUserId,
|
||||
payload,
|
||||
);
|
||||
} catch (err) {
|
||||
const errMsg = `Exception while invoking method validateAuthToken ${err}`;
|
||||
Logger.error(errMsg);
|
||||
rej(errMsg);
|
||||
clearTimeout(setTimeoutRef);
|
||||
authTokenValidationObserver.stop();
|
||||
}
|
||||
});
|
||||
return userValidation;
|
||||
}
|
||||
|
||||
export default validateAuthToken;
|
||||
|
@ -35,7 +35,6 @@ class PendingAuthentitcations {
|
||||
|
||||
// find matches
|
||||
const matches = this.store.filter(e => e.key === key);
|
||||
|
||||
// remove matches (if any)
|
||||
if (matches.length) {
|
||||
this.store = this.store.filter(e => e.key !== key);
|
||||
|
@ -3,7 +3,6 @@ import { withTracker } from 'meteor/react-meteor-data';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import AuthTokenValidation from '/imports/api/auth-token-validation';
|
||||
import Users from '/imports/ui/local-collections/users-collection/users';
|
||||
import Meetings from '/imports/ui/local-collections/meetings-collection/meetings';
|
||||
import { notify } from '/imports/ui/services/notification';
|
||||
@ -120,9 +119,7 @@ const currentUserEmoji = (currentUser) => (currentUser
|
||||
);
|
||||
|
||||
export default injectIntl(withModalMounter(withTracker(({ intl, baseControls }) => {
|
||||
const authTokenValidation = AuthTokenValidation.findOne({}, { sort: { updatedAt: -1 } });
|
||||
|
||||
if (authTokenValidation.connectionId !== Meteor.connection._lastSessionId) {
|
||||
if (Auth.connectionID !== Meteor.connection._lastSessionId) {
|
||||
endMeeting('403');
|
||||
}
|
||||
|
||||
|
@ -94,5 +94,4 @@ class AuthenticatedHandler extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default AuthenticatedHandler;
|
||||
|
@ -33,6 +33,7 @@ class Auth {
|
||||
this._confname = Storage.getItem('confname');
|
||||
this._externUserID = Storage.getItem('externUserID');
|
||||
this._fullname = Storage.getItem('fullname');
|
||||
this._connectionID = Storage.getItem('connectionID');
|
||||
}
|
||||
|
||||
get meetingID() {
|
||||
@ -142,6 +143,15 @@ class Auth {
|
||||
};
|
||||
}
|
||||
|
||||
set _connectionID(connectionId) {
|
||||
this._connectionID = connectionId;
|
||||
Storage.setItem('sessionToken', this._connectionID);
|
||||
}
|
||||
|
||||
get sessionToken() {
|
||||
return this._sessionToken;
|
||||
}
|
||||
|
||||
set(
|
||||
meetingId,
|
||||
requesterUserId,
|
||||
@ -213,53 +223,30 @@ class Auth {
|
||||
}
|
||||
|
||||
validateAuthToken() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let computation = null;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
SubscriptionRegistry.createSubscription('current-user');
|
||||
const validationTimeout = setTimeout(() => {
|
||||
computation.stop();
|
||||
reject({
|
||||
error: 408,
|
||||
description: 'Authentication timeout',
|
||||
});
|
||||
}, CONNECTION_TIMEOUT);
|
||||
|
||||
makeCall('validateAuthToken', this.meetingID, this.userID, this.token, this.externUserID);
|
||||
|
||||
const authTokenSubscription = SubscriptionRegistry.createSubscription('auth-token-validation', {}, { meetingId: this.meetingID, userId: this.userID });
|
||||
SubscriptionRegistry.createSubscription('current-user');
|
||||
|
||||
Tracker.autorun((c) => {
|
||||
computation = c;
|
||||
|
||||
if (!authTokenSubscription.ready()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selector = {
|
||||
connectionId: Meteor.connection._lastSessionId,
|
||||
};
|
||||
|
||||
const authenticationTokenValidation = AuthTokenValidation.findOne(selector);
|
||||
|
||||
Meteor.call('validateAuthToken', this.meetingID, this.userID, this.token, this.externUserID, (err, result) => {
|
||||
const authenticationTokenValidation = result;
|
||||
if (!authenticationTokenValidation) return;
|
||||
|
||||
switch (authenticationTokenValidation.validationStatus) {
|
||||
case ValidationStates.INVALID:
|
||||
c.stop();
|
||||
reject({ error: 403, description: authenticationTokenValidation.reason });
|
||||
break;
|
||||
case ValidationStates.VALIDATED:
|
||||
initCursorStreamListener();
|
||||
initAnnotationsStreamListener();
|
||||
c.stop();
|
||||
clearTimeout(validationTimeout);
|
||||
this.connectionID = authenticationTokenValidation.connectionId;
|
||||
setTimeout(() => resolve(true), 100);
|
||||
break;
|
||||
case ValidationStates.VALIDATING:
|
||||
break;
|
||||
case ValidationStates.NOT_VALIDATED:
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user