BACKPORT: FEATURE: consume CIS webhook and refresh profiles
https://github.com/mozilla/discourse/issues/184
This commit is contained in:
Родитель
dfda0ec62a
Коммит
3b0df9af18
|
@ -0,0 +1,30 @@
|
|||
module MozillaIAM
|
||||
class NotificationController < ActionController::Base
|
||||
|
||||
def notification
|
||||
unless ["update", "delete"].include? params[:operation]
|
||||
return render body: "Unsupported operation", status: 200
|
||||
end
|
||||
begin
|
||||
token = request.headers["Authorization"].sub("Bearer ","")
|
||||
JWT.decode(
|
||||
token,
|
||||
aud: SiteSetting.mozilla_iam_notification_aud
|
||||
)
|
||||
rescue => e
|
||||
return render body: "Invalid JWT", status: 400
|
||||
end
|
||||
|
||||
uid = params[:id]
|
||||
profile = Profile.find_by_uid(uid)
|
||||
profile&.force_refresh
|
||||
Rails.logger.info <<~EOF.gsub(/\n/, ", ")
|
||||
Mozilla IAM: Successfully refreshed profile for #{uid}
|
||||
operation: #{params[:operation]}, time: #{params[:time]}
|
||||
refresh time: #{Time.now.to_i}
|
||||
EOF
|
||||
render body: nil, status: 200
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -8,4 +8,5 @@ MozillaIAM::Engine.routes.draw do
|
|||
namespace :admin, constraints: AdminConstraint.new do
|
||||
resources :group_mappings, path: :mappings
|
||||
end
|
||||
post :notification, to: "notification#notification"
|
||||
end
|
||||
|
|
|
@ -15,3 +15,6 @@ mozilla_iam:
|
|||
mozilla_iam_person_api_aud:
|
||||
default: 'https://person-api.sso.mozilla.com'
|
||||
shadowed_by_global: true
|
||||
mozilla_iam_notification_aud:
|
||||
default: "hook.prod.sso.mozilla.com"
|
||||
shadowed_by_global: true
|
||||
|
|
|
@ -25,6 +25,12 @@ module MozillaIAM
|
|||
profile = self.for(user)
|
||||
profile.refresh unless profile.nil?
|
||||
end
|
||||
|
||||
def find_by_uid(uid)
|
||||
user = UserCustomField.where(name: "mozilla_iam_uid", value: uid).last&.user
|
||||
return if user.nil?
|
||||
return Profile.new(user, uid)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(user, uid)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# name: mozilla-iam
|
||||
# about: A plugin to integrate Discourse with Mozilla's Identity and Access Management (IAM) system
|
||||
# version: 1.1.7
|
||||
# version: 1.1.8+cis-webhook
|
||||
# authors: Leo McArdle
|
||||
# url: https://github.com/mozilla/discourse-mozilla-iam
|
||||
|
||||
|
|
|
@ -63,6 +63,20 @@ describe MozillaIAM::Profile do
|
|||
end
|
||||
end
|
||||
|
||||
describe ".find_by_uid" do
|
||||
it "returns a user who has the uid" do
|
||||
profile
|
||||
MozillaIAM::Profile.expects(:new).with(user, "uid").returns(profile)
|
||||
result = described_class.find_by_uid("uid")
|
||||
expect(result).to eq profile
|
||||
end
|
||||
|
||||
it "returns nil if there's no user with that uid" do
|
||||
result = described_class.find_by_uid("uid")
|
||||
expect(result).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context '#initialize' do
|
||||
it "should save a user's uid" do
|
||||
profile
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
require_relative '../../iam_helper'
|
||||
|
||||
describe MozillaIAM::NotificationController, type: :request do
|
||||
describe "#notification" do
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
stub_jwks_request
|
||||
end
|
||||
|
||||
shared_context "no JWT" do
|
||||
let(:headers) do
|
||||
{ "Content-Type": "application/json" }
|
||||
end
|
||||
end
|
||||
|
||||
shared_context "invalid JWT" do
|
||||
let(:jwt) do
|
||||
create_jwt({
|
||||
iss: 'https://auth.mozilla.auth0.com/',
|
||||
aud: 'nope',
|
||||
exp: Time.now.to_i + 7.days,
|
||||
iat: Time.now.to_i,
|
||||
}, {
|
||||
kid: 'the_best_key'
|
||||
})
|
||||
end
|
||||
let(:headers) do
|
||||
{
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer #{jwt}"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
shared_context "valid JWT" do
|
||||
let(:jwt) do
|
||||
create_jwt({
|
||||
iss: 'https://auth.mozilla.auth0.com/',
|
||||
aud: 'hook.prod.sso.mozilla.com',
|
||||
exp: Time.now.to_i + 7.days,
|
||||
iat: Time.now.to_i,
|
||||
}, {
|
||||
kid: 'the_best_key'
|
||||
})
|
||||
end
|
||||
let(:headers) do
|
||||
{
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer #{jwt}"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples "does nothing" do
|
||||
it "does nothing" do
|
||||
MozillaIAM::Profile.any_instance.expects(:force_refresh).never
|
||||
post "/mozilla_iam/notification", params: notification.to_json, headers: headers
|
||||
expect(response.status).to eq 200
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples "error" do
|
||||
context "with no JWT" do
|
||||
include_context "no JWT"
|
||||
|
||||
it "errors out" do
|
||||
post "/mozilla_iam/notification", params: notification.to_json, headers: headers
|
||||
expect(response.status).to eq 400
|
||||
expect(response.body).to eq "Invalid JWT"
|
||||
end
|
||||
end
|
||||
|
||||
context "with an invalid JWT" do
|
||||
include_context "invalid JWT"
|
||||
|
||||
it "errors out" do
|
||||
post "/mozilla_iam/notification", params: notification.to_json, headers: headers
|
||||
expect(response.status).to eq 400
|
||||
expect(response.body).to eq "Invalid JWT"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples "success" do
|
||||
context "with a valid JWT" do
|
||||
include_context "valid JWT"
|
||||
|
||||
context "with a user_id which doesn't exist" do
|
||||
include_examples "does nothing"
|
||||
end
|
||||
|
||||
context "with a user_id which exists" do
|
||||
before do
|
||||
user.custom_fields["mozilla_iam_uid"] = notification[:id]
|
||||
user.save_custom_fields
|
||||
end
|
||||
|
||||
it "refreshes user" do
|
||||
MozillaIAM::Profile.any_instance.expects(:force_refresh)
|
||||
post "/mozilla_iam/notification", params: notification.to_json, headers: headers
|
||||
expect(response.status).to eq 200
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
context "with an update notification" do
|
||||
let(:notification) do
|
||||
{
|
||||
operation: "update",
|
||||
id: "ad|Mozilla-LDAP|dinomcvouch",
|
||||
time: Time.now
|
||||
}
|
||||
end
|
||||
|
||||
include_examples "error"
|
||||
include_examples "success"
|
||||
|
||||
end
|
||||
|
||||
context "with a delete notification" do
|
||||
let(:notification) do
|
||||
{
|
||||
operation: "delete",
|
||||
id: "ad|Mozilla-LDAP|dinomcvouch",
|
||||
time: Time.now
|
||||
}
|
||||
end
|
||||
|
||||
include_examples "error"
|
||||
include_examples "success"
|
||||
|
||||
end
|
||||
|
||||
context "with a create notification" do
|
||||
let(:notification) do
|
||||
{
|
||||
operation: "create",
|
||||
id: "ad|Mozilla-LDAP|dinomcvouch",
|
||||
time: Time.now
|
||||
}
|
||||
end
|
||||
|
||||
context "with no JWT" do
|
||||
include_context "no JWT"
|
||||
include_examples "does nothing"
|
||||
end
|
||||
|
||||
context "with invalid JWT" do
|
||||
include_context "invalid JWT"
|
||||
include_examples "does nothing"
|
||||
end
|
||||
|
||||
context "with valid JWT" do
|
||||
include_context "valid JWT"
|
||||
include_examples "does nothing"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
Загрузка…
Ссылка в новой задаче