Security Fixes

pull/20931/head^2
Diego Sampaio 5 years ago committed by Diego Sampaio
parent 1d963bf491
commit e429e59476
No known key found for this signature in database
GPG Key ID: E060152B30502562
  1. 7
      .github/history-manual.json
  2. 5
      app/authorization/server/functions/hasRole.js
  3. 8
      app/lib/server/functions/setUserAvatar.js
  4. 16
      app/meteor-accounts-saml/server/lib/SAML.ts
  5. 2
      app/meteor-accounts-saml/server/loginHandler.ts
  6. 6
      app/models/server/raw/Roles.js
  7. 2
      packages/rocketchat-mongo-config/server/index.js
  8. 84
      server/methods/addAllUserToRoom.js

@ -56,5 +56,12 @@
"contributors": [
"sampaiodiego"
]
}],
"3.12.0": [{
"title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)",
"userLogin": "sampaiodiego",
"contributors": [
"sampaiodiego"
]
}]
}

@ -1,7 +1,10 @@
import { Roles } from '../../../models/server/raw';
export const hasRoleAsync = async (userId, roleNames, scope) => {
roleNames = [].concat(roleNames);
if (!userId || userId === '') {
return false;
}
return Roles.isUserInRoles(userId, roleNames, scope);
};

@ -18,13 +18,13 @@ export const setUserAvatar = function(user, dataURI, contentType, service) {
try {
result = HTTP.get(dataURI, { npmRequestOptions: { encoding: 'binary', rejectUnauthorized: false } });
if (!result) {
console.log(`Not a valid response, from the avatar url: ${ dataURI }`);
throw new Meteor.Error('error-avatar-invalid-url', `Invalid avatar URL: ${ dataURI }`, { function: 'setUserAvatar', url: dataURI });
console.log(`Not a valid response, from the avatar url: ${ encodeURI(dataURI) }`);
throw new Meteor.Error('error-avatar-invalid-url', `Invalid avatar URL: ${ encodeURI(dataURI) }`, { function: 'setUserAvatar', url: dataURI });
}
} catch (error) {
if (!error.response || error.response.statusCode !== 404) {
console.log(`Error while handling the setting of the avatar from a url (${ dataURI }) for ${ user.username }:`, error);
throw new Meteor.Error('error-avatar-url-handling', `Error while handling avatar setting from a URL (${ dataURI }) for ${ user.username }`, { function: 'RocketChat.setUserAvatar', url: dataURI, username: user.username });
console.log(`Error while handling the setting of the avatar from a url (${ encodeURI(dataURI) }) for ${ user.username }:`, error);
throw new Meteor.Error('error-avatar-url-handling', `Error while handling avatar setting from a URL (${ encodeURI(dataURI) }) for ${ user.username }`, { function: 'RocketChat.setUserAvatar', url: dataURI, username: user.username });
}
}

@ -390,21 +390,15 @@ export class SAML {
throw new Error('No user data collected from IdP response.');
}
let credentialToken = (profile.inResponseToId && profile.inResponseToId.value) || profile.inResponseToId || profile.InResponseTo || samlObject.credentialToken;
// create a random token to store the login result
// to test an IdP initiated login on localhost, use the following URL (assuming SimpleSAMLPHP on localhost:8080):
// http://localhost:8080/simplesaml/saml2/idp/SSOService.php?spentityid=http://localhost:3000/_saml/metadata/test-sp
const credentialToken = Random.id();
const loginResult = {
profile,
};
if (!credentialToken) {
// If the login was initiated by the IDP, then we don't have a credentialToken as there was no AuthorizeRequest on our side
// so we create a random token now to use the same url to end the login
//
// to test an IdP initiated login on localhost, use the following URL (assuming SimpleSAMLPHP on localhost:8080):
// http://localhost:8080/simplesaml/saml2/idp/SSOService.php?spentityid=http://localhost:3000/_saml/metadata/test-sp
credentialToken = Random.id();
SAMLUtils.log('[SAML] Using random credentialToken: ', credentialToken);
}
this.storeCredential(credentialToken, loginResult);
const url = `${ Meteor.absoluteUrl('home') }?saml_idp_credentialToken=${ credentialToken }`;
res.writeHead(302, {

@ -11,7 +11,7 @@ const makeError = (message: string): Record<string, any> => ({
});
Accounts.registerLoginHandler('saml', function(loginRequest) {
if (!loginRequest.saml || !loginRequest.credentialToken) {
if (!loginRequest.saml || !loginRequest.credentialToken || typeof loginRequest.credentialToken !== 'string') {
return undefined;
}

@ -8,13 +8,15 @@ export class RolesRaw extends BaseRaw {
}
async isUserInRoles(userId, roles, scope) {
roles = [].concat(roles);
if (!Array.isArray(roles)) {
roles = [roles];
}
for (let i = 0, total = roles.length; i < total; i++) {
const roleName = roles[i];
// eslint-disable-next-line no-await-in-loop
const role = await this.findOne({ _id: roleName });
const role = await this.findOne({ _id: roleName }, { scope: 1 });
const roleScope = (role && role.scope) || 'Users';
const model = this.models[roleScope];

@ -30,12 +30,12 @@ tls.DEFAULT_ECDH_CURVE = 'auto';
const mongoConnectionOptions = {
// add retryWrites=false if not present in MONGO_URL
...!process.env.MONGO_URL.includes('retryWrites') && { retryWrites: false },
ignoreUndefined: false,
};
const mongoOptionStr = process.env.MONGO_OPTIONS;
if (typeof mongoOptionStr !== 'undefined') {
const mongoOptions = JSON.parse(mongoOptionStr);
Object.assign(mongoConnectionOptions, mongoOptions);
}

@ -11,52 +11,54 @@ Meteor.methods({
check(rid, String);
check(activeUsersOnly, Boolean);
if (hasRole(this.userId, 'admin') === true) {
const userCount = Users.find().count();
if (userCount > settings.get('API_User_Limit')) {
throw new Meteor.Error('error-user-limit-exceeded', 'User Limit Exceeded', {
method: 'addAllToRoom',
});
}
if (!hasRole(this.userId, 'admin')) {
throw new Meteor.Error(403, 'Access to Method Forbidden', {
method: 'addAllToRoom',
});
}
const room = Rooms.findOneById(rid);
if (room == null) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', {
method: 'addAllToRoom',
});
}
const userFilter = {};
if (activeUsersOnly === true) {
userFilter.active = true;
}
const userFilter = {};
if (activeUsersOnly === true) {
userFilter.active = true;
}
const userCursor = Users.find(userFilter);
const usersCount = userCursor.count();
if (usersCount > settings.get('API_User_Limit')) {
throw new Meteor.Error('error-user-limit-exceeded', 'User Limit Exceeded', {
method: 'addAllToRoom',
});
}
const users = Users.find(userFilter).fetch();
const now = new Date();
users.forEach(function(user) {
const subscription = Subscriptions.findOneByRoomIdAndUserId(rid, user._id);
if (subscription != null) {
return;
}
callbacks.run('beforeJoinRoom', user, room);
Subscriptions.createWithRoomAndUser(room, user, {
ts: now,
open: true,
alert: true,
unread: 1,
userMentions: 1,
groupMentions: 0,
});
Messages.createUserJoinWithRoomIdAndUser(rid, user, {
ts: now,
});
Meteor.defer(function() {});
return callbacks.run('afterJoinRoom', user, room);
const room = Rooms.findOneById(rid);
if (!room) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', {
method: 'addAllToRoom',
});
return true;
}
throw new Meteor.Error(403, 'Access to Method Forbidden', {
method: 'addAllToRoom',
const users = userCursor.fetch();
const now = new Date();
users.forEach(function(user) {
const subscription = Subscriptions.findOneByRoomIdAndUserId(rid, user._id);
if (subscription != null) {
return;
}
callbacks.run('beforeJoinRoom', user, room);
Subscriptions.createWithRoomAndUser(room, user, {
ts: now,
open: true,
alert: true,
unread: 1,
userMentions: 1,
groupMentions: 0,
});
Messages.createUserJoinWithRoomIdAndUser(rid, user, {
ts: now,
});
Meteor.defer(function() {});
return callbacks.run('afterJoinRoom', user, room);
});
return true;
},
});

Loading…
Cancel
Save