Skip to content
Snippets Groups Projects
Commit 67a8ab12 authored by Gabriel Engel's avatar Gabriel Engel
Browse files

Merge pull request #1810 from RocketChat/improvements/oauth-server

Improvements/oauth server
parents a295da42 3be903bc
No related merge requests found
Showing
with 337 additions and 1 deletion
......@@ -34,6 +34,7 @@ session
spacebars
standard-minifiers
tracker
rocketchat:oauth2-server-config
arunoda:streams
rocketchat:lib
......
......@@ -148,6 +148,8 @@ rocketchat:mentions-flextab@0.0.1
rocketchat:message-attachments@0.0.1
rocketchat:message-pin@0.0.1
rocketchat:message-star@0.0.1
rocketchat:oauth2-server@1.1.0
rocketchat:oauth2-server-config@1.0.0
rocketchat:oembed@0.0.1
rocketchat:slashcommands-invite@0.0.1
rocketchat:slashcommands-join@0.0.1
......
......@@ -26,6 +26,7 @@
"Accounts_OAuth_Custom_Enable" : "Enable",
"Accounts_OAuth_Custom_id" : "Id",
"Accounts_OAuth_Custom_Identity_Path" : "Identity Path",
"Accounts_OAuth_Custom_Login_Style" : "Login Style",
"Accounts_OAuth_Custom_Secret" : "Secret",
"Accounts_OAuth_Custom_Token_Path" : "Token Path",
"Accounts_OAuth_Custom_URL" : "URL",
......@@ -67,6 +68,7 @@
"Add_Members" : "Add Members",
"Add_users" : "Add users",
"Administration" : "Administration",
"After_OAuth2_authentication_users_will_be_redirected_to_this_URL" : "After OAuth2 authentication, users will be redirected to this URL",
"Alias" : "Alias",
"All_channels" : "All channels",
"Allow_Invalid_SelfSigned_Certs" : "Allow Invalid Self-Signed Certs",
......@@ -77,6 +79,9 @@
"API_Embed" : "Embed",
"API_EmbedDisabledFor" : "Disable Embed for Users",
"API_EmbedDisabledFor_Description" : "Comma-separated list of usernames",
"Application_added" : "Application added",
"Application_Name" : "Application Name",
"Application_updated" : "Application updated",
"Archive" : "Archive",
"are_also_typing" : "are also typing",
"are_typing" : "are typing",
......@@ -91,6 +96,7 @@
"Away_female" : "Away",
"away_male" : "away",
"Away_male" : "Away",
"Back_to_applications" : "Back to applications",
"Back_to_integrations" : "Back to integrations",
"Back_to_login" : "Back to login",
"bold" : "bold",
......@@ -110,6 +116,8 @@
"Choose_the_alias_that_will_appear_before_the_username_in_messages" : "Choose the alias that will appear before the username in messages.",
"Choose_the_username_that_this_integration_will_post_as" : "Choose the username that this integration will post as.",
"Clear_all_unreads_question" : "Clear all unreads?",
"Client_ID" : "Client ID",
"Client_Secret" : "Client Secret",
"close" : "close",
"coming_soon" : "coming soon",
"Commands" : "Commands",
......@@ -178,6 +186,7 @@
"Get_to_know_the_team" : "Get to know the Rocket.Team",
"github_no_public_email" : "You don't have any email as public email in your GitHub account",
"Give_a_unique_name_for_the_custom_oauth" : "Give a unique name for the custom oauth",
"Give_the_application_a_name_This_will_be_seen_by_your_users" : "Give the application a name. This will be seen by your users.",
"Has_more" : "Has more",
"Have_your_own_chat" : "Have your own web chat. Developed with Meteor.com, the Rocket.Chat is a great solution for developers looking forward to build and evolve their own chat platform.",
"Hide_room" : "Hide room",
......@@ -309,6 +318,7 @@
"Name" : "Name",
"Name_cant_be_empty" : "Name can't be empty",
"Name_optional" : "Name (optional)",
"New_Application" : "New Application",
"New_integration" : "New integration",
"New_messages" : "New messages",
"New_password" : "New password",
......@@ -328,6 +338,8 @@
"Not_found_or_not_allowed" : "Not Found or Not Allowed",
"Nothing_found" : "Nothing found",
"Notify_all_in_this_room" : "Notify all in this room",
"OAuth_Application" : "OAuth Application",
"OAuth_Applications" : "OAuth Applications",
"Old_and_new_password_required" : "You need to provide both old and new password for changing your password.",
"Old_Password" : "Old Password",
"Online" : "Online",
......@@ -378,6 +390,7 @@
"quote" : "quote",
"Recents" : "Recents",
"Record" : "Record",
"Redirect_URI" : "Redirect URI",
"Refresh_your_page_after_install_to_enable_screen_sharing" : "Refresh your page after install to enable screen sharing",
"Register" : "Register a new account",
"Registration_Succeeded" : "Registration Succeeded",
......@@ -482,9 +495,11 @@
"strike" : "strike",
"Submit" : "Submit",
"Success" : "Success",
"The_application_name_is_required" : "Th _application name is required",
"The_channel_name_is_required" : "The channel name is required",
"The_field_is_required" : "The field %s is required.",
"The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server" : "The image resize will not work because we can not detect ImageMagick or GraphicsMagick installed on your server.",
"The_redirectUri_is_required" : "The redirectUri is required",
"The_server_will_restart_in_s_seconds" : "The server will restart in %s seconds",
"The_setting_s_is_configured_to_s_and_you_are_accessing_from_s" : "The setting <strong>%s</strong> is configured to <strong>%s</strong> and you are accessing from <strong>%s</strong>!",
"There_are_no_integrations" : "There are no integrations",
......@@ -561,7 +576,7 @@
"You_should_name_it_to_easily_manage_your_integrations" : "You should name it to easily manage your integrations.",
"You_will_not_be_able_to_recover" : "You will not be able to recover this message!",
"Your_entry_has_been_deleted" : "Your entry has been deleted.",
"Your_Open_Source_solution" : "Your own Open Source chat solution",
"Your_mail_was_sent_to_s" : "Your mail was sent to %s",
"Your_Open_Source_solution" : "Your own Open Source chat solution",
"Your_push_was_sent_to_s_devices" : "Your push was sent to %s devices"
}
......@@ -104,6 +104,9 @@ Meteor.startup ->
{ _id: 'manage-integrations',
roles : ['admin', 'bot']}
{ _id: 'manage-oauth-apps',
roles : ['admin']}
]
#alanning:roles
......
......@@ -15,6 +15,7 @@ Meteor.methods
RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_authorize_path" , '/oauth/authorize', { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Authorize_Path', persistent: true }
RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_id" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_id', persistent: true }
RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_secret" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Secret', persistent: true }
RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_login_style" , 'popup' , { type: 'select' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Login_Style', persistent: true, values: [ { key: 'redirect', i18nLabel: 'Redirect' }, { key: 'popup', i18nLabel: 'Popup' }, { key: '', i18nLabel: 'Default' } ] }
RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_button_label_text" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Button_Label_Text', persistent: true }
RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_button_label_color", '#FFFFFF' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Button_Label_Color', persistent: true }
RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_button_color" , '#13679A' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Button_Color', persistent: true }
......@@ -29,12 +29,14 @@ oAuthServicesUpdate = ->
data.authorizePath = RocketChat.models.Settings.findOneById("#{service._id}_authorize_path")?.value
data.buttonLabelText = RocketChat.models.Settings.findOneById("#{service._id}_button_label_text")?.value
data.buttonLabelColor = RocketChat.models.Settings.findOneById("#{service._id}_button_label_color")?.value
data.loginStyle = RocketChat.models.Settings.findOneById("#{service._id}_login_style")?.value
data.buttonColor = RocketChat.models.Settings.findOneById("#{service._id}_button_color")?.value
new CustomOAuth serviceName.toLowerCase(),
serverURL: data.serverURL
tokenPath: data.tokenPath
identityPath: data.identityPath
authorizePath: data.authorizePath
loginStyle: data.loginStyle
if serviceName is 'Facebook'
data.appId = data.clientId
......
.build*
@ChatOAuthApps = new Meteor.Collection 'rocketchat_oauth_apps'
FlowRouter.route '/admin/oauth-apps',
name: 'admin-oauth-apps'
action: (params) ->
BlazeLayout.render 'main',
center: 'pageSettingsContainer'
pageTitle: t('OAuth_Applications')
pageTemplate: 'oauthApps'
FlowRouter.route '/admin/oauth-app/:id?',
name: 'admin-oauth-app'
action: (params) ->
BlazeLayout.render 'main',
center: 'pageSettingsContainer'
pageTitle: t('OAuth_Application')
pageTemplate: 'oauthApp'
params: params
Meteor.subscribe 'oauthApps'
RocketChat.AdminBox.addOption
href: 'admin-oauth-apps'
i18nLabel: 'OAuth Apps'
permissionGranted: ->
return RocketChat.authz.hasAllPermission('manage-oauth-apps')
Template.oauthApp.onCreated ->
@record = new ReactiveVar {}
Template.oauthApp.helpers
hasPermission: ->
return RocketChat.authz.hasAllPermission 'manage-oauth-apps'
data: ->
params = Template.instance().data.params?()
if params?.id?
data = ChatOAuthApps.findOne({_id: params.id})
if data?
Template.instance().record.set data
return data
return Template.instance().record.curValue
Template.oauthApp.events
"click .submit > .delete": ->
params = Template.instance().data.params()
swal
title: t('Are_you_sure')
text: t('You_will_not_be_able_to_recover')
type: 'warning'
showCancelButton: true
confirmButtonColor: '#DD6B55'
confirmButtonText: t('Yes_delete_it')
cancelButtonText: t('Cancel')
closeOnConfirm: false
html: false
, ->
Meteor.call "deleteOAuthApp", params.id, (err, data) ->
swal
title: t('Deleted')
text: t('Your_entry_has_been_deleted')
type: 'success'
timer: 1000
showConfirmButton: false
FlowRouter.go "admin-oauth-apps"
"click .submit > .save": ->
name = $('[name=name]').val().trim()
redirectUri = $('[name=redirectUri]').val().trim()
if name is ''
return toastr.error TAPi18n.__("The_application_name_is_required")
if redirectUri is ''
return toastr.error TAPi18n.__("The_redirectUri_is_required")
app =
name: name
redirectUri: redirectUri
params = Template.instance().data.params?()
if params?.id?
Meteor.call "updateOAuthApp", params.id, app, (err, data) ->
if err?
return toastr.error TAPi18n.__(err.error)
toastr.success TAPi18n.__("Application_updated")
else
Meteor.call "addOAuthApp", app, (err, data) ->
if err?
return toastr.error TAPi18n.__(err.error)
toastr.success TAPi18n.__("Application_added")
FlowRouter.go "admin-oauth-app", {id: data._id}
<template name="oauthApp">
<div class="permissions-manager">
{{#if hasPermission}}
<a href="{{pathFor "admin-oauth-apps"}}"><i class="icon-angle-left"></i> {{_ "Back_to_applications"}}</a><br><br>
<div class="rocket-form">
<div class="section">
<div class="section-content">
<div class="input-line double-col">
<label>{{_ "Application_Name"}}</label>
<div>
<input type="text" name="name" value="{{data.name}}" placeholder="{{_ 'Optional'}}" />
<div class="settings-description">{{_ "Give_the_application_a_name_This_will_be_seen_by_your_users"}}</div>
</div>
</div>
<div class="input-line double-col">
<label>{{_ "Redirect_URI"}}</label>
<div>
<input type="text" name="redirectUri" value="{{data.redirectUri}}" />
<div class="settings-description">{{_ "After_OAuth2_authentication_users_will_be_redirected_to_this_URL"}}</div>
</div>
</div>
{{#if data.clientId}}
<div class="input-line double-col">
<label>{{_ "Client_ID"}}</label>
<div>
<input type="text" name="clientId" value="{{data.clientId}}" disabled="disabled" />
<div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=clientId]">{{_ "COPY_TO_CLIPBOARD"}}</a></div>
</div>
</div>
<div class="input-line double-col">
<label>{{_ "Client_Secret"}}</label>
<div>
<input type="text" name="clientSecret" value="{{data.clientSecret}}" disabled="disabled" />
<div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=clientSecret]">{{_ "COPY_TO_CLIPBOARD"}}</a></div>
</div>
</div>
{{/if}}
</div>
</div>
<div class="submit">
{{#if data.token}}
<button class="button red delete"><i class="icon-trash"></i><span>{{_ "Delete"}}</span></button>
{{/if}}
<button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button>
</div>
</div>
{{else}}
{{_ "Not_authorized"}}
{{/if}}
</div>
</template>
Template.oauthApps.helpers
hasPermission: ->
return RocketChat.authz.hasAllPermission 'manage-oauth-apps'
applications: ->
return ChatOAuthApps.find()
dateFormated: (date) ->
return moment(date).format('L LT')
<template name="oauthApps">
<div class="permissions-manager">
{{#if hasPermission}}
<a href="{{pathFor "admin-oauth-app"}}" class="button primary new-role">{{_ "New_Application"}}</a>
<div class="rocket-form">
<div class="section">
<div class="admin-integrations-new-panel">
{{#each applications}}
<a href="{{pathFor "admin-oauth-app" id=_id}}">
<div class="admin-integrations-new-item">
<div class="admin-integrations-new-item-body">
<div class="admin-integrations-new-item-title">
{{name}}
</div>
<div class="admin-integrations-new-item-description">
{{{_ "Created_at_s_by_s" (dateFormated _createdAt) _createdBy.username}}}
</div>
</div>
<i class="icon-angle-right"></i>
</div>
</a>
{{else}}
<h1>{{_ "There_are_no_applications"}}</h1>
{{/each}}
</div>
</div>
</div>
{{else}}
{{_ "Not_authorized"}}
{{/if}}
</div>
</template>
Meteor.methods
addOAuthApp: (application) ->
if not RocketChat.authz.hasPermission @userId, 'manage-oauth-apps'
throw new Meteor.Error 'not_authorized'
if not _.isString(application.name)
throw new Meteor.Error 'invalid_name', '[methods] addOAuthApp -> name must be string'
if application.name.trim() is ''
throw new Meteor.Error 'invalid_name', '[methods] addOAuthApp -> name can\'t be empty'
if not _.isString(application.redirectUri)
throw new Meteor.Error 'invalid_redirectUri', '[methods] addOAuthApp -> redirectUri must be string'
if application.redirectUri.trim() is ''
throw new Meteor.Error 'invalid_redirectUri', '[methods] addOAuthApp -> redirectUri can\'t be empty'
application.clientId = Random.id()
application.clientSecret = Random.secret()
application._createdAt = new Date
application._createdBy = RocketChat.models.Users.findOne @userId, {fields: {username: 1}}
application._id = RocketChat.models.OAuthApps.insert application
return application
Meteor.methods
deleteOAuthApp: (applicationId) ->
if not RocketChat.authz.hasPermission @userId, 'manage-oauth-apps'
throw new Meteor.Error 'not_authorized'
application = RocketChat.models.OAuthApps.findOne(applicationId)
if not application?
throw new Meteor.Error 'invalid_application', '[methods] deleteOAuthApp -> application not found'
RocketChat.models.OAuthApps.remove _id: applicationId
return true
Meteor.methods
updateOAuthApp: (applicationId, application) ->
if not RocketChat.authz.hasPermission @userId, 'manage-oauth-apps'
throw new Meteor.Error 'not_authorized'
if not _.isString(application.name)
throw new Meteor.Error 'invalid_name', '[methods] updateOAuthApp -> name must be string'
if application.name.trim() is ''
throw new Meteor.Error 'invalid_name', '[methods] updateOAuthApp -> name can\'t be empty'
if not _.isString(application.redirectUri)
throw new Meteor.Error 'invalid_redirectUri', '[methods] updateOAuthApp -> redirectUri must be string'
if application.redirectUri.trim() is ''
throw new Meteor.Error 'invalid_redirectUri', '[methods] updateOAuthApp -> redirectUri can\'t be empty'
currentApplication = RocketChat.models.OAuthApps.findOne(applicationId)
if not currentApplication?
throw new Meteor.Error 'invalid_application', '[methods] updateOAuthApp -> application not found'
RocketChat.models.OAuthApps.update applicationId,
$set:
name: application.name
redirectUri: application.redirectUri
_updatedAt: new Date
_updatedBy: RocketChat.models.Users.findOne @userId, {fields: {username: 1}}
return RocketChat.models.OAuthApps.findOne(applicationId)
Meteor.publish 'oauthApps', ->
unless @userId
return @ready()
if not RocketChat.authz.hasPermission @userId, 'manage-oauth-apps'
throw new Meteor.Error "not-authorized"
return RocketChat.models.OAuthApps.find()
FlowRouter.route '/oauth/authorize',
action: (params, queryParams) ->
BlazeLayout.render 'main',
center: 'authorize'
modal: true
client_id: queryParams.client_id
redirect_uri: queryParams.redirect_uri
response_type: queryParams.response_type
state: queryParams.state
Template.authorize.onCreated ->
@subscribe 'authorizedOAuth'
Template.authorize.helpers
getToken: ->
return localStorage.getItem('Meteor.loginToken')
Template.authorize.onRendered ->
@autorun (c) =>
if Meteor.user()?.oauth?.athorizedClients?.indexOf(@data.client_id()) > -1
c.stop()
$('button').click()
<template name="authorize">
{{#if currentUser}}
<div class="oauth-panel">
<form method="post" action="" role="form" class="{{#unless Template.subscriptionsReady}}hidden{{/unless}}">
<h2>Authorize?</h2>
<input type="hidden" name="allow" value="yes">
<input type="hidden" name="token" value="{{getToken}}">
<input type="hidden" name="client_id" value="{{client_id}}">
<input type="hidden" name="redirect_uri" value="{{redirect_uri}}">
<input type="hidden" name="response_type" value="code">
<button type="submit" class="button">Authorize</button>
</form>
{{#unless Template.subscriptionsReady}}
loading...
{{/unless}}
</div>
{{else}}
{{> loginButtons}}
{{/if}}
</template>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment