mirror of
https://git.lapiole.org/dani/ansible-roles.git
synced 2025-04-11 15:53:21 +02:00
Update to 2024-07-22 10:00
This commit is contained in:
parent
457d41ccf9
commit
f5421b17f0
@ -14,7 +14,7 @@ jitsi_jigasi_git_url: https://github.com/jitsi/jigasi.git
|
||||
jitsi_meet_git_url: https://github.com/jitsi/jitsi-meet.git
|
||||
|
||||
# Should ansible handle upgrades, or only initial install ?
|
||||
jitsi_manage_upgrade: True
|
||||
jitsi_manage_upgrade: true
|
||||
|
||||
# XMPP server to connect to. Default is the same machine
|
||||
jitsi_xmpp_server: "{{ inventory_hostname }}"
|
||||
@ -33,14 +33,26 @@ jitsi_stun_servers: []
|
||||
jitsi_turn_secret: "{{ turnserver_auth_secret | default('p@ssw0rd') }}"
|
||||
|
||||
# Authentication. Can be set to
|
||||
# * False : no authentication at all (can also be None)
|
||||
# * false : no authentication at all (can also be None)
|
||||
# * sso : In this case, you have to protect /login with your SSO system (through a reverse proxy)
|
||||
# And once authenticated, send the HTTP headers mail and displayName with the appropriate values
|
||||
# Note that jitsi Android client does not support sso authentication, so mobile users will be able
|
||||
# to join an existing conf, but not create one easily
|
||||
# * token : to use JWT Tokens
|
||||
# * ldap : Will use an LDAP server for authentication. Works on mobile, but is a bit less convinient
|
||||
# than sso for desktop users. See all the jitsi_ldap_xxxx settings
|
||||
jitsi_auth: False
|
||||
jitsi_auth: false
|
||||
|
||||
# If using token
|
||||
jitsi_token_app_id: jitsi
|
||||
|
||||
# Either jitsi_token_app_secret or jitsi_token_asap_key_server must be set
|
||||
# jitsi_token_app_secret: XXXX
|
||||
# jitsi_token_asap_key_server: https://sso.example.org/jitsi/asap
|
||||
|
||||
jitsi_token_iss: https://sso.example.org
|
||||
jitsi_token_aud: "{{ jitsi_token_app_id }}"
|
||||
jitsi_token_auth_url: https://sso.example.org/jitsi/login?room={room}
|
||||
|
||||
jitsi_jicofo_xmpp_user: focus
|
||||
jitsi_jicofo_xmpp_domain: "{{ jitsi_auth_domain }}"
|
||||
@ -52,7 +64,7 @@ jitsi_auth_domain: auth.{{ jitsi_domain }}
|
||||
|
||||
# Can be either true, in which case a cert will be automatically obtained using letsencrypt
|
||||
# or can be a name, in which case you have to configure letsencrypt to obtain the cert yourself
|
||||
# jitsi_letsencrypt_cert: True
|
||||
# jitsi_letsencrypt_cert: true
|
||||
# or
|
||||
# jitsi_letsencrypt_cert: jitsi.example.com
|
||||
#
|
||||
@ -71,33 +83,32 @@ jitsi_meet_conf_base:
|
||||
websocket: wss://{{ jitsi_domain }}/xmpp-websocket
|
||||
clientNode: http://jitsi.org/jitsimeet
|
||||
focusUserJid: "{{ jitsi_jicofo_xmpp_user }}@{{ jitsi_auth_domain }}"
|
||||
enableNoAudioDetection: True
|
||||
enableNoisyMicDetection: True
|
||||
enableNoAudioDetection: true
|
||||
enableNoisyMicDetection: true
|
||||
startAudioMuted: 10
|
||||
startVideoMuted: 10
|
||||
enableOpusRed: True
|
||||
desktopSharingFrameRate:
|
||||
min: 5
|
||||
max: 30
|
||||
channelLastN: 25
|
||||
enableLayerSuspension: True
|
||||
enableUnifiedOnChrome: True
|
||||
requireDisplayName: False
|
||||
enableOpusRed: true
|
||||
#desktopSharingFrameRate:
|
||||
# min: 5
|
||||
# max: 30
|
||||
requireDisplayName: true
|
||||
prejoinConfig:
|
||||
enabled: True
|
||||
enableInsecureRoomNameWarning: False
|
||||
disableThirdPartyRequests: True
|
||||
enabled: true
|
||||
enableInsecureRoomNameWarning: false
|
||||
disableThirdPartyRequests: true
|
||||
welcomePage:
|
||||
disabled: False
|
||||
disabled: false
|
||||
lobby:
|
||||
enableChat: true
|
||||
localRecording:
|
||||
notifyAllParticipants: True
|
||||
notifyAllParticipants: true
|
||||
recordingService:
|
||||
enabled: "{{ (jitsi_jibri_recordings_base_url is defined) | ternary(True, False) }}"
|
||||
enabled: "{{ (jitsi_jibri_recordings_base_url is defined) | ternary(true, false) }}"
|
||||
p2p:
|
||||
enabled: False
|
||||
enableUnifiedOnChrome: True
|
||||
enabled: false
|
||||
enableUnifiedOnChrome: true
|
||||
analytics:
|
||||
disabled: True
|
||||
disabled: true
|
||||
toolbarButtons:
|
||||
- camera
|
||||
- chat
|
||||
@ -129,18 +140,22 @@ jitsi_meet_conf_base:
|
||||
dialInNumbersUrl: https://{{ jitsi_domain }}/phoneNumberList
|
||||
dialInConfCodeUrl: https://{{ jitsi_domain }}/conferenceMapper
|
||||
screenshotCapture:
|
||||
enabled: True
|
||||
enabled: true
|
||||
transcription:
|
||||
enabled: False
|
||||
useTurnUdp: True
|
||||
enabled: false
|
||||
useTurnUdp: true
|
||||
defaultLanguage: fr
|
||||
gravatar:
|
||||
disabled: True
|
||||
disabled: true
|
||||
giphy:
|
||||
enabled: True
|
||||
enabled: true
|
||||
breakoutRooms:
|
||||
hideAddRoomButton: false
|
||||
hideAutoAssignButton: true
|
||||
hideJoinRoomButton: false
|
||||
|
||||
jitsi_meet_conf_extra: {}
|
||||
jitsi_meet_conf: "{{ jitsi_meet_conf_base | combine(jitsi_meet_conf_extra, recursive=True) }}"
|
||||
jitsi_meet_conf: "{{ jitsi_meet_conf_base | combine(jitsi_meet_conf_extra, recursive=true) }}"
|
||||
|
||||
# Meet interface configuration. Will be converted to JSON
|
||||
# See https://github.com/jitsi/jitsi-meet/blob/master/interface_config.js for available settings and their meaning
|
||||
@ -150,29 +165,29 @@ jitsi_meet_interface_conf_base:
|
||||
AUDIO_LEVEL_SECONDARY_COLOR: 'rgba(255,255,255,0.2)'
|
||||
AUTO_PIN_LATEST_SCREEN_SHARE: remote-only
|
||||
BRAND_WATERMARK_LINK: https://www.ehtrace.com
|
||||
CLOSE_PAGE_GUEST_HINT: False
|
||||
CLOSE_PAGE_GUEST_HINT: false
|
||||
DEFAULT_BACKGROUND: '#040404'
|
||||
DEFAULT_WELCOME_PAGE_LOGO_URL: 'images/watermark.svg'
|
||||
DISABLE_DOMINANT_SPEAKER_INDICATOR: False
|
||||
DISABLE_JOIN_LEAVE_NOTIFICATIONS: False
|
||||
DISABLE_PRESENCE_STATUS: False
|
||||
DISABLE_RINGING: False
|
||||
DISABLE_TRANSCRIPTION_SUBTITLES: True
|
||||
DISABLE_VIDEO_BACKGROUND: False
|
||||
DISPLAY_WELCOME_FOOTER: True
|
||||
DISPLAY_WELCOME_PAGE_ADDITIONAL_CARD: False
|
||||
DISPLAY_WELCOME_PAGE_CONTENT: False
|
||||
DISPLAY_WELCOME_PAGE_TOOLBAR_ADDITIONAL_CONTENT: False
|
||||
ENABLE_DIAL_OUT: "{{ (jitsi_jigasi_sip_server is defined) | ternary(True, False) }}"
|
||||
ENABLE_FEEDBACK_ANIMATION: False
|
||||
DISABLE_DOMINANT_SPEAKER_INDICATOR: false
|
||||
DISABLE_JOIN_LEAVE_NOTIFICATIONS: false
|
||||
DISABLE_PRESENCE_STATUS: false
|
||||
DISABLE_RINGING: false
|
||||
DISABLE_TRANSCRIPTION_SUBTITLES: true
|
||||
DISABLE_VIDEO_BACKGROUND: false
|
||||
DISPLAY_WELCOME_FOOTER: true
|
||||
DISPLAY_WELCOME_PAGE_ADDITIONAL_CARD: false
|
||||
DISPLAY_WELCOME_PAGE_CONTENT: false
|
||||
DISPLAY_WELCOME_PAGE_TOOLBAR_ADDITIONAL_CONTENT: false
|
||||
ENABLE_DIAL_OUT: "{{ (jitsi_jigasi_sip_server is defined) | ternary(true, false) }}"
|
||||
ENABLE_FEEDBACK_ANIMATION: false
|
||||
FILM_STRIP_MAX_HEIGHT: 120
|
||||
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: True
|
||||
HIDE_INVITE_MORE_HEADER: False
|
||||
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true
|
||||
HIDE_INVITE_MORE_HEADER: false
|
||||
JITSI_WATERMARK_LINK: https://www.ehtrace.com
|
||||
LANG_DETECTION: True
|
||||
LANG_DETECTION: true
|
||||
LOCAL_THUMBNAIL_RATIO: 16 / 9
|
||||
MAXIMUM_ZOOMING_COEFFICIENT: 1.3
|
||||
MOBILE_APP_PROMO: True
|
||||
MOBILE_APP_PROMO: true
|
||||
OPTIMAL_BROWSERS:
|
||||
- chrome
|
||||
- chromium
|
||||
@ -182,7 +197,7 @@ jitsi_meet_interface_conf_base:
|
||||
- safari
|
||||
POLICY_LOGO: null
|
||||
PROVIDER_NAME: Ehtrace
|
||||
RECENT_LIST_ENABLED: True
|
||||
RECENT_LIST_ENABLED: true
|
||||
REMOTE_THUMBNAIL_RATIO: 1
|
||||
SETTINGS_SECTIONS:
|
||||
- devices
|
||||
@ -191,19 +206,19 @@ jitsi_meet_interface_conf_base:
|
||||
- profile
|
||||
- sounds
|
||||
- more
|
||||
SHOW_BRAND_WATERMARK: False
|
||||
SHOW_CHROME_EXTENSION_BANNER: False
|
||||
SHOW_JITSI_WATERMARK: False
|
||||
SHOW_POWERED_BY: False
|
||||
SHOW_PROMOTIONAL_CLOSE_PAGE: False
|
||||
SHOW_BRAND_WATERMARK: false
|
||||
SHOW_CHROME_EXTENSION_BANNER: false
|
||||
SHOW_JITSI_WATERMARK: false
|
||||
SHOW_POWERED_BY: false
|
||||
SHOW_PROMOTIONAL_CLOSE_PAGE: false
|
||||
SUPPORT_URL: 'mailto:support@ehtrace.com'
|
||||
UNSUPPORTED_BROWSERS: []
|
||||
VERTICAL_FILMSTRIP: True
|
||||
VERTICAL_FILMSTRIP: true
|
||||
VIDEO_LAYOUT_FIT: both
|
||||
VIDEO_QUALITY_LABEL_DISABLED: False
|
||||
VIDEO_QUALITY_LABEL_DISABLED: false
|
||||
|
||||
jitsi_meet_interface_conf_extra: {}
|
||||
jitsi_meet_interface_conf: "{{ jitsi_meet_interface_conf_base | combine(jitsi_meet_interface_conf_extra, recursive=True) }}"
|
||||
jitsi_meet_interface_conf: "{{ jitsi_meet_interface_conf_base | combine(jitsi_meet_interface_conf_extra, recursive=true) }}"
|
||||
|
||||
# You can customize strings here (lang/main-XX.json)
|
||||
jitsi_meet_custom_lang: {}
|
||||
@ -221,12 +236,12 @@ jitsi_meet_custom_lang: {}
|
||||
|
||||
# If jitsi_auth is ldap
|
||||
# We inherit values from prosody if available, or we try to get values from ad_auth or ldap_auth
|
||||
jitsi_ldap_base: "{{ prosody_ldap_base | default(ad_auth | default(False) | ternary((ad_ldap_user_search_base is defined) | ternary(ad_ldap_user_search_base,'DC=' + ad_realm | default(samba_realm) | default(ansible_domain) | regex_replace('\\.',',DC=')), ldap_user_base | default('ou=Users') + ',' + ldap_base | default(ansible_domain | regex_replace('\\.','dc=')))) }}"
|
||||
jitsi_ldap_servers: "{{ prosody_ldap_server | default(ad_ldap_servers | default([ad_auth | default(False) | ternary(ad_realm | default(samba_realm) | default(ansible_domain) | lower, ldap_uri | default('ldap://' + ansible_domain) | urlsplit('hostname'))]))}}"
|
||||
jitsi_ldap_base: "{{ prosody_ldap_base | default(ad_auth | default(false) | ternary((ad_ldap_user_search_base is defined) | ternary(ad_ldap_user_search_base,'DC=' + ad_realm | default(samba_realm) | default(ansible_domain) | regex_replace('\\.',',DC=')), ldap_user_base | default('ou=Users') + ',' + ldap_base | default(ansible_domain | regex_replace('\\.','dc=')))) }}"
|
||||
jitsi_ldap_servers: "{{ prosody_ldap_server | default(ad_ldap_servers | default([ad_auth | default(false) | ternary(ad_realm | default(samba_realm) | default(ansible_domain) | lower, ldap_uri | default('ldap://' + ansible_domain) | urlsplit('hostname'))]))}}"
|
||||
jitsi_ldap_bind_dn: "{{ prosody_ldap_bind_dn | default(None) }}"
|
||||
jitsi_ldap_bind_pass: "{{ prosody_ldap_bind_pass | default(None) }}"
|
||||
jitsi_ldap_filter: "{{ prosody_ldap_filter | default(ad_auth | default(False) | ternary('(&(objectClass=user)(sAMAccountName=%s))','(&(objectClass=inetOrgPerson)(uid=%s))')) }}"
|
||||
jitsi_ldap_starttls: "{{ prosody_ldap_starttls | default(True) }}"
|
||||
jitsi_ldap_filter: "{{ prosody_ldap_filter | default(ad_auth | default(false) | ternary('(&(objectClass=user)(sAMAccountName=%s))','(&(objectClass=inetOrgPerson)(uid=%s))')) }}"
|
||||
jitsi_ldap_starttls: "{{ prosody_ldap_starttls | default(true) }}"
|
||||
|
||||
# Jigasi settings
|
||||
|
||||
@ -267,7 +282,7 @@ jitsi_jigasi_sip_extra_conf: {}
|
||||
# ENCRYPTION_PROTOCOL_STATUS.ZRTP: 'false'
|
||||
# IS_PRESENCE_ENABLED: 'true'
|
||||
# SDES_CIPHER_SUITES: AES_CM_128_HMAC_SHA1_80,AES_CM_128_HMAC_SHA1_32
|
||||
jitsi_jigasi_sip_conf: "{{ jitsi_jigasi_sip_base_conf | combine(jitsi_jigasi_sip_extra_conf, recursive=True) }}"
|
||||
jitsi_jigasi_sip_conf: "{{ jitsi_jigasi_sip_base_conf | combine(jitsi_jigasi_sip_extra_conf, recursive=true) }}"
|
||||
|
||||
jitsi_jigasi_xmpp_user: jigasi
|
||||
jitsi_jigasi_xmpp_domain: "{{ jitsi_auth_domain }}"
|
||||
@ -291,7 +306,7 @@ jitsi_confmapper_conf_base:
|
||||
id_max_length: 4
|
||||
db_file: "{{ jitsi_root_dir }}/data/confmapper/confmapper.sqlite"
|
||||
jitsi_confmapper_conf_extra: {}
|
||||
jitsi_confmapper_conf: "{{ jitsi_confmapper_conf_base | combine(jitsi_confmapper_conf_extra, recursive=True) }}"
|
||||
jitsi_confmapper_conf: "{{ jitsi_confmapper_conf_base | combine(jitsi_confmapper_conf_extra, recursive=true) }}"
|
||||
|
||||
# This is for Jibri integration
|
||||
jitsi_jibri_xmpp_user: jibri
|
||||
|
@ -73,10 +73,19 @@
|
||||
- set_fact:
|
||||
jitsi_anonymousdomain:
|
||||
hosts:
|
||||
anonymousdomain: guest.{{ jitsi_domain }}
|
||||
- set_fact: jitsi_meet_conf={{ jitsi_anonymousdomain | combine(jitsi_meet_conf, recursive=True) }}
|
||||
when: jitsi_auth == 'ldap'
|
||||
tags: jisti
|
||||
anonymousdomain: guest.{{ jitsi_domain }}
|
||||
- set_fact: jitsi_meet_conf={{ jitsi_meet_conf | combine(jitsi_anonymousdomain, recursive=True) }}
|
||||
when: jitsi_auth == 'ldap' or jitsi_auth == 'token'
|
||||
tags: jitsi
|
||||
|
||||
- name: Set authentication url for jitsi meet
|
||||
block:
|
||||
- set_fact:
|
||||
jitsi_authurl:
|
||||
tokenAuthUrl: '{{ jitsi_token_auth_url }}'
|
||||
- set_fact: jitsi_meet_conf={{ jitsi_meet_conf | combine(jitsi_authurl, recursive=True) }}
|
||||
when: jitsi_auth == 'token'
|
||||
tags: jitsi
|
||||
|
||||
- name: Check if cert file exist
|
||||
stat: path={{ jitsi_cert_path }}
|
||||
|
@ -2,8 +2,17 @@
|
||||
jicofo {
|
||||
|
||||
authentication {
|
||||
enabled = {{ (jitsi_auth == 'sso' or jitsi_auth == 'ldap') | ternary('true', 'false') }}
|
||||
type = {{ (jitsi_auth == 'ldap') | ternary('XMPP', 'SHIBBOLETH') }}
|
||||
{% if jitsi_auth == 'sso' %}
|
||||
enabled = true
|
||||
type = SHIBBOLETH
|
||||
{% elif jitsi_auth == 'ldap' %}
|
||||
enabled = true
|
||||
type = XMPP
|
||||
{% elif jitsi_auth == 'token' %}
|
||||
enabled = true
|
||||
type = JWT
|
||||
login-url = {{ jitsi_domain }}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
bridge {
|
||||
@ -28,5 +37,6 @@ jicofo {
|
||||
password = "{{ jitsi_jicofo_xmpp_pass }}"
|
||||
client-proxy = focus.{{ jitsi_domain }}
|
||||
}
|
||||
trusted-domains = ["{{ jitsi_jibri_xmpp_domain | default('recorder.' ~ jitsi_jibri_domain) }}"]
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,10 @@ external_services = {
|
||||
{% for stun in jitsi_stun_servers %}
|
||||
{
|
||||
type = "{{ stun | urlsplit('scheme') }}",
|
||||
host = "{{ stun | regex_replace('(turns?|stun):([^:]+)(:\d+)?.*', '\\2') }}{% if stun | regex_replace('(turns?|stun):.+:(\d+)?.*', '\\2') | int > 0 and stun | regex_replace('(turns?|stun):.+:(\d+)?.*', '\\2') | int < 65535 %}:{{ stun | regex_replace('(turns?|stun):.+:(\d+)?.*', '\\2') }}{% endif %}",
|
||||
host = "{{ stun | regex_replace('(turns?|stun):([^:]+)(:\d+)?.*', '\\2') }}",
|
||||
{% if stun | regex_replace('(turns?|stun):.+:(\d+)?.*', '\\2') | int > 0 and stun | regex_replace('(turns?|stun):.+:(\d+)?.*', '\\2') | int < 65535 %}
|
||||
port = {{ stun | regex_replace('(turns?|stun):.+:(\d+)?.*', '\\2') }},
|
||||
{% endif %}
|
||||
{% if stun | urlsplit('query') is search('transport=') %}
|
||||
transport = "{{ stun | urlsplit('query') | regex_replace('.*transport=(udp|tcp).*', '\\1') }}",
|
||||
{% endif %}
|
||||
@ -24,13 +27,13 @@ external_services = {
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
cross_domain_bosh = false;
|
||||
-- cross_domain_bosh = false;
|
||||
cross_domain_websocket = true;
|
||||
consider_bosh_secure = true;
|
||||
|
||||
unlimited_jids = {
|
||||
"{{ jitsi_jicofo_xmpp_user }}@{{ jitsi_auth_domain }}",
|
||||
"{{ jitsi_videobridge_xmpp_user }}@{{ jitsi_videobridge_xmpp_domain }}"
|
||||
"{{ jitsi_jicofo_xmpp_user }}@{{ jitsi_auth_domain }}",
|
||||
"{{ jitsi_videobridge_xmpp_user }}@{{ jitsi_videobridge_xmpp_domain }}"
|
||||
}
|
||||
|
||||
VirtualHost "{{ jitsi_domain }}"
|
||||
@ -45,40 +48,59 @@ VirtualHost "{{ jitsi_domain }}"
|
||||
ldap_filter = "{{ jitsi_ldap_filter }}"
|
||||
ldap_scope = "subtree"
|
||||
ldap_tls = {{ jitsi_ldap_starttls | ternary('true','false') }}
|
||||
{% elif jitsi_auth == 'token' %}
|
||||
authentication = "token"
|
||||
app_id = "{{ jitsi_token_app_id }}";
|
||||
asap_accepted_issuers = "{{ jitsi_token_iss }}";
|
||||
asap_accepted_audiences = "{{ jitsi_token_aud }}";
|
||||
{% if jitsi_token_app_secret is defined %}
|
||||
app_secret = "{{ jitsi_token_app_secret }}";
|
||||
{% elif jitsi_token_asap_key_server is defined %}
|
||||
asap_key_server = "{{ jitsi_token_asap_key_server }}";
|
||||
{% endif %}
|
||||
allow_empty_token = false;
|
||||
{% else %}
|
||||
authentication = "anonymous"
|
||||
authentication = "jitsi-anonymous"
|
||||
{% endif %}
|
||||
ssl = {
|
||||
key = "{{ jitsi_key_path }}";
|
||||
certificate = "{{ jitsi_cert_path }}";
|
||||
}
|
||||
|
||||
c2s_require_encryption = false
|
||||
allow_unencrypted_plain_auth = true
|
||||
av_moderation_component = "avmoderation.{{ jitsi_domain }}"
|
||||
speakerstats_component = "speakerstats.{{ jitsi_domain }}"
|
||||
end_conference_component = "endconference.{{ jitsi_domain }}"
|
||||
|
||||
modules_enabled = {
|
||||
"bosh";
|
||||
"pubsub";
|
||||
"ping";
|
||||
"websocket";
|
||||
"external_services";
|
||||
"ping";
|
||||
"speakerstats";
|
||||
"external_services";
|
||||
"conference_duration";
|
||||
"end_conference";
|
||||
"muc_lobby_rooms";
|
||||
"participant_metadata";
|
||||
"muc_breakout_rooms";
|
||||
"av_moderation";
|
||||
"room_metadata";
|
||||
"participant_metadata";
|
||||
"presence_identity";
|
||||
}
|
||||
c2s_require_encryption = false
|
||||
allow_unencrypted_plain_auth = true
|
||||
speakerstats_component = "speakerstats.{{ jitsi_domain }}"
|
||||
|
||||
conference_duration_component = "conferenceduration.{{ jitsi_domain }}"
|
||||
lobby_muc = "lobby.{{ jitsi_domain }}"
|
||||
breakout_rooms_muc = "breakout.{{ jitsi_domain }}"
|
||||
room_metadata_component = "metadata.{{ jitsi_domain }}"
|
||||
main_muc = "conference.{{ jitsi_domain }}"
|
||||
muc_lobby_whitelist = { "recorder.{{ jitsi_domain }}" }
|
||||
|
||||
{% if jitsi_auth == 'ldap' %}
|
||||
{% if jitsi_auth == 'ldap' or jitsi_auth == 'token' %}
|
||||
-- Guest virtual domain
|
||||
VirtualHost "guest.{{ jitsi_domain }}"
|
||||
authentication = "anonymous"
|
||||
authentication = "jitsi-anonymous"
|
||||
c2s_require_encryption = false
|
||||
modules_enabled = {
|
||||
"participant_metadata";
|
||||
@ -101,10 +123,12 @@ VirtualHost "recorder.{{ jitsi_domain }}"
|
||||
c2s_require_encryption = false
|
||||
|
||||
Component "conference.{{ jitsi_domain }}" "muc"
|
||||
restrict_room_creation = true
|
||||
storage = "memory"
|
||||
modules_enabled = {
|
||||
"ping";
|
||||
"jibri_bypass_pwd";
|
||||
"muc_hide_all";
|
||||
"muc_meeting_id";
|
||||
"muc_domain_mapper";
|
||||
"polls";
|
||||
@ -113,11 +137,19 @@ Component "conference.{{ jitsi_domain }}" "muc"
|
||||
admins = { "{{ jitsi_jicofo_xmpp_user }}@{{ jitsi_auth_domain }}" }
|
||||
muc_room_locking = false
|
||||
muc_room_default_public_jids = true
|
||||
muc_password_whitelist = {
|
||||
"{{ jitsi_jicofo_xmpp_user }}@{{ jitsi_auth_domain }}"
|
||||
}
|
||||
|
||||
Component "internal.{{ jitsi_auth_domain }}" "muc"
|
||||
storage = "memory"
|
||||
modules_enabled = { "ping"; }
|
||||
muc_room_cache_size = 1000
|
||||
modules_enabled = {
|
||||
"muc_hide_all";
|
||||
"ping";
|
||||
}
|
||||
admins = { "{{ jitsi_jicofo_xmpp_user }}@{{ jitsi_auth_domain }}" }
|
||||
muc_room_locking = false
|
||||
muc_room_default_public_jids = true
|
||||
|
||||
Component "focus.{{ jitsi_domain }}" "client_proxy"
|
||||
target_address = "{{ jitsi_jicofo_xmpp_user }}@{{ jitsi_auth_domain }}"
|
||||
@ -128,6 +160,9 @@ Component "speakerstats.{{ jitsi_domain }}" "speakerstats_component"
|
||||
Component "conferenceduration.{{ jitsi_domain }}" "conference_duration_component"
|
||||
muc_component = "conference.{{ jitsi_domain }}"
|
||||
|
||||
Component "endconference.{{ jitsi_domain }}" "end_conference"
|
||||
muc_component = "conference.{{ jitsi_domain }}"
|
||||
|
||||
Component "avmoderation.{{ jitsi_domain }}" "av_moderation_component"
|
||||
muc_component = "conference.{{ jitsi_domain }}"
|
||||
|
||||
@ -137,16 +172,24 @@ Component "lobby.{{ jitsi_domain }}" "muc"
|
||||
muc_room_locking = false
|
||||
muc_room_default_public_jids = true
|
||||
modules_enabled = {
|
||||
"muc_hide_all";
|
||||
"muc_rate_limit";
|
||||
"polls";
|
||||
}
|
||||
|
||||
Component "metadata.{{ jitsi_domain }}" "room_metadata_component"
|
||||
muc_component = "conference.{{ jitsi_domain }}"
|
||||
breakout_rooms_component = "breakout.{{ jitsi_domain }}"
|
||||
|
||||
Component "breakout.{{ jitsi_domain }}" "muc"
|
||||
restrict_room_creation = true
|
||||
storage = "memory"
|
||||
modules_enabled = {
|
||||
"muc_hide_all";
|
||||
"muc_meeting_id";
|
||||
"muc_domain_mapper";
|
||||
"muc_rate_limit";
|
||||
"polls";
|
||||
}
|
||||
admins = { "{{ jitsi_jicofo_xmpp_user }}@{{ jitsi_auth_domain }}" }
|
||||
muc_room_locking = false
|
||||
|
@ -19,6 +19,24 @@ prosody_base_modules:
|
||||
- name: mod_auth_ldap
|
||||
- name: util.lib
|
||||
url: https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/util.lib.lua
|
||||
- name: mod_auth_jitsi-anonymous
|
||||
url: https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/mod_auth_jitsi-anonymous.lua
|
||||
- name: mod_end_conference
|
||||
url: https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/mod_end_conference.lua
|
||||
- name: mod_room_metadata
|
||||
url: https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/mod_room_metadata.lua
|
||||
- name: mod_room_metadata_component
|
||||
url: https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/mod_room_metadata_component.lua
|
||||
- name: mod_muc_hide_all
|
||||
url: https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/mod_muc_hide_all.lua
|
||||
- name: mod_room_destroy
|
||||
url: https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/mod_room_destroy.lua
|
||||
- name: mod_presence_identity
|
||||
url: https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/mod_presence_identity.lua
|
||||
- name: luajwtjitsi.lib
|
||||
url: https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/luajwtjitsi.lib.lua
|
||||
- name: mod_auth_token
|
||||
url: https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/mod_auth_token.lua
|
||||
- name: mod_speakerstats
|
||||
url: https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/mod_speakerstats.lua
|
||||
- name: mod_speakerstats_component
|
||||
|
11
roles/prosody/files/prosody-ansible.te
Normal file
11
roles/prosody/files/prosody-ansible.te
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
module prosody-ansible 1.0;
|
||||
|
||||
require {
|
||||
type unlabeled_t;
|
||||
type prosody_t;
|
||||
class dir search;
|
||||
}
|
||||
|
||||
#============= prosody_t ==============
|
||||
allow prosody_t unlabeled_t:dir search;
|
539
roles/prosody/files/token/util.lib.lua
Normal file
539
roles/prosody/files/token/util.lib.lua
Normal file
@ -0,0 +1,539 @@
|
||||
-- Token authentication
|
||||
-- Copyright (C) 2021-present 8x8, Inc.
|
||||
|
||||
local basexx = require "basexx";
|
||||
local have_async, async = pcall(require, "util.async");
|
||||
local hex = require "util.hex";
|
||||
local jwt = module:require "luajwtjitsi";
|
||||
local jid = require "util.jid";
|
||||
local json_safe = require "cjson.safe";
|
||||
local path = require "util.paths";
|
||||
local sha256 = require "util.hashes".sha256;
|
||||
local main_util = module:require "util";
|
||||
local ends_with = main_util.ends_with;
|
||||
local http_get_with_retry = main_util.http_get_with_retry;
|
||||
local extract_subdomain = main_util.extract_subdomain;
|
||||
local starts_with = main_util.starts_with;
|
||||
local table_shallow_copy = main_util.table_shallow_copy;
|
||||
local cjson_safe = require 'cjson.safe'
|
||||
local timer = require "util.timer";
|
||||
local async = require "util.async";
|
||||
-- local inspect = require 'inspect';
|
||||
|
||||
local nr_retries = 3;
|
||||
local ssl = require "ssl";
|
||||
|
||||
-- TODO: Figure out a less arbitrary default cache size.
|
||||
local cacheSize = module:get_option_number("jwt_pubkey_cache_size", 128);
|
||||
|
||||
-- the cache for generated asap jwt tokens
|
||||
local jwtKeyCache = require 'util.cache'.new(cacheSize);
|
||||
|
||||
local ASAPTTL_THRESHOLD = module:get_option_number('asap_ttl_threshold', 600);
|
||||
local ASAPTTL = module:get_option_number('asap_ttl', 3600);
|
||||
local ASAPIssuer = module:get_option_string('asap_issuer', 'jitsi');
|
||||
local ASAPAudience = module:get_option_string('asap_audience', 'jitsi');
|
||||
local ASAPKeyId = module:get_option_string('asap_key_id', 'jitsi');
|
||||
local ASAPKeyPath = module:get_option_string('asap_key_path', '/etc/prosody/certs/asap.key');
|
||||
|
||||
local ASAPKey;
|
||||
local f = io.open(ASAPKeyPath, 'r');
|
||||
|
||||
if f then
|
||||
ASAPKey = f:read('*all');
|
||||
f:close();
|
||||
end
|
||||
|
||||
local Util = {}
|
||||
Util.__index = Util
|
||||
|
||||
--- Constructs util class for token verifications.
|
||||
-- Constructor that uses the passed module to extract all the
|
||||
-- needed configurations.
|
||||
-- If configuration is missing returns nil
|
||||
-- @param module the module in which options to check for configs.
|
||||
-- @return the new instance or nil
|
||||
function Util.new(module)
|
||||
local self = setmetatable({}, Util)
|
||||
|
||||
self.appId = module:get_option_string("app_id");
|
||||
self.appSecret = module:get_option_string("app_secret");
|
||||
self.asapKeyServer = module:get_option_string("asap_key_server");
|
||||
-- A URL that will return json file with a mapping between kids and public keys
|
||||
-- If the response Cache-Control header we will respect it and refresh it
|
||||
self.cacheKeysUrl = module:get_option_string("cache_keys_url");
|
||||
self.signatureAlgorithm = module:get_option_string("signature_algorithm");
|
||||
self.allowEmptyToken = module:get_option_boolean("allow_empty_token");
|
||||
|
||||
self.cache = require"util.cache".new(cacheSize);
|
||||
|
||||
--[[
|
||||
Multidomain can be supported in some deployments. In these deployments
|
||||
there is a virtual conference muc, which address contains the subdomain
|
||||
to use. Those deployments are accessible
|
||||
by URL https://domain/subdomain.
|
||||
Then the address of the room will be:
|
||||
roomName@conference.subdomain.domain. This is like a virtual address
|
||||
where there is only one muc configured by default with address:
|
||||
conference.domain and the actual presentation of the room in that muc
|
||||
component is [subdomain]roomName@conference.domain.
|
||||
These setups relay on configuration 'muc_domain_base' which holds
|
||||
the main domain and we use it to subtract subdomains from the
|
||||
virtual addresses.
|
||||
The following confgurations are for multidomain setups and domain name
|
||||
verification:
|
||||
--]]
|
||||
|
||||
-- optional parameter for custom muc component prefix,
|
||||
-- defaults to "conference"
|
||||
self.muc_domain_prefix = module:get_option_string(
|
||||
"muc_mapper_domain_prefix", "conference");
|
||||
-- domain base, which is the main domain used in the deployment,
|
||||
-- the main VirtualHost for the deployment
|
||||
self.muc_domain_base = module:get_option_string("muc_mapper_domain_base");
|
||||
-- The "real" MUC domain that we are proxying to
|
||||
if self.muc_domain_base then
|
||||
self.muc_domain = module:get_option_string(
|
||||
"muc_mapper_domain",
|
||||
self.muc_domain_prefix.."."..self.muc_domain_base);
|
||||
end
|
||||
-- whether domain name verification is enabled, by default it is enabled
|
||||
-- when disabled checking domain name and tenant if available will be skipped, we will check only room name.
|
||||
self.enableDomainVerification = module:get_option_boolean('enable_domain_verification', true);
|
||||
|
||||
if self.allowEmptyToken == true then
|
||||
module:log("warn", "WARNING - empty tokens allowed");
|
||||
end
|
||||
|
||||
if self.appId == nil then
|
||||
module:log("error", "'app_id' must not be empty");
|
||||
return nil;
|
||||
end
|
||||
|
||||
if self.appSecret == nil and self.asapKeyServer == nil then
|
||||
module:log("error", "'app_secret' or 'asap_key_server' must be specified");
|
||||
return nil;
|
||||
end
|
||||
|
||||
-- Set defaults for signature algorithm
|
||||
if self.signatureAlgorithm == nil then
|
||||
if self.asapKeyServer ~= nil then
|
||||
self.signatureAlgorithm = "RS256"
|
||||
elseif self.appSecret ~= nil then
|
||||
self.signatureAlgorithm = "HS256"
|
||||
end
|
||||
end
|
||||
|
||||
--array of accepted issuers: by default only includes our appId
|
||||
self.acceptedIssuers = module:get_option_array('asap_accepted_issuers',{self.appId})
|
||||
|
||||
--array of accepted audiences: by default only includes our appId
|
||||
self.acceptedAudiences = module:get_option_array('asap_accepted_audiences',{'*'})
|
||||
|
||||
self.requireRoomClaim = module:get_option_boolean('asap_require_room_claim', true);
|
||||
|
||||
if self.asapKeyServer and not have_async then
|
||||
module:log("error", "requires a version of Prosody with util.async");
|
||||
return nil;
|
||||
end
|
||||
|
||||
if self.cacheKeysUrl then
|
||||
self.cachedKeys = {};
|
||||
local update_keys_cache;
|
||||
update_keys_cache = async.runner(function (name)
|
||||
local content, code, cache_for;
|
||||
content, code, cache_for = http_get_with_retry(self.cacheKeysUrl, nr_retries);
|
||||
if content ~= nil then
|
||||
local keys_to_delete = table_shallow_copy(self.cachedKeys);
|
||||
-- Let's convert any certificate to public key
|
||||
for k, v in pairs(cjson_safe.decode(content)) do
|
||||
if starts_with(v, '-----BEGIN CERTIFICATE-----') then
|
||||
self.cachedKeys[k] = ssl.loadcertificate(v):pubkey();
|
||||
-- do not clean this key if it already exists
|
||||
keys_to_delete[k] = nil;
|
||||
end
|
||||
end
|
||||
-- let's schedule the clean in an hour and a half, current tokens will be valid for an hour
|
||||
timer.add_task(90*60, function ()
|
||||
for k, _ in pairs(keys_to_delete) do
|
||||
self.cachedKeys[k] = nil;
|
||||
end
|
||||
end);
|
||||
|
||||
if cache_for then
|
||||
cache_for = tonumber(cache_for);
|
||||
-- let's schedule new update 60 seconds before the cache expiring
|
||||
if cache_for > 60 then
|
||||
cache_for = cache_for - 60;
|
||||
end
|
||||
timer.add_task(cache_for, function ()
|
||||
update_keys_cache:run("update_keys_cache");
|
||||
end);
|
||||
else
|
||||
-- no cache header let's consider updating in 6hours
|
||||
timer.add_task(6*60*60, function ()
|
||||
update_keys_cache:run("update_keys_cache");
|
||||
end);
|
||||
end
|
||||
else
|
||||
module:log('warn', 'Failed to retrieve cached public keys code:%s', code);
|
||||
-- failed let's retry in 30 seconds
|
||||
timer.add_task(30, function ()
|
||||
update_keys_cache:run("update_keys_cache");
|
||||
end);
|
||||
end
|
||||
end);
|
||||
update_keys_cache:run("update_keys_cache");
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function Util:set_asap_key_server(asapKeyServer)
|
||||
self.asapKeyServer = asapKeyServer;
|
||||
end
|
||||
|
||||
function Util:set_asap_accepted_issuers(acceptedIssuers)
|
||||
self.acceptedIssuers = acceptedIssuers;
|
||||
end
|
||||
|
||||
function Util:set_asap_accepted_audiences(acceptedAudiences)
|
||||
self.acceptedAudiences = acceptedAudiences;
|
||||
end
|
||||
|
||||
function Util:set_asap_require_room_claim(checkRoom)
|
||||
self.requireRoomClaim = checkRoom;
|
||||
end
|
||||
|
||||
function Util:clear_asap_cache()
|
||||
self.cache = require"util.cache".new(cacheSize);
|
||||
end
|
||||
|
||||
--- Returns the public key by keyID
|
||||
-- @param keyId the key ID to request
|
||||
-- @return the public key (the content of requested resource) or nil
|
||||
function Util:get_public_key(keyId)
|
||||
local content = self.cache:get(keyId);
|
||||
local code;
|
||||
if content == nil then
|
||||
-- If the key is not found in the cache.
|
||||
-- module:log("debug", "Cache miss for key: %s", keyId);
|
||||
local keyurl = path.join(self.asapKeyServer, hex.to(sha256(keyId))..'.pem');
|
||||
-- module:log("debug", "Fetching public key from: %s", keyurl);
|
||||
content, code = http_get_with_retry(keyurl, nr_retries);
|
||||
if content ~= nil then
|
||||
self.cache:set(keyId, content);
|
||||
else
|
||||
if code == nil then
|
||||
-- this is timout after nr_retries retries
|
||||
module:log('warn', 'Timeout retrieving %s from %s', keyId, keyurl);
|
||||
end
|
||||
end
|
||||
return content;
|
||||
else
|
||||
-- If the key is in the cache, use it.
|
||||
-- module:log("debug", "Cache hit for key: %s", keyId);
|
||||
return content;
|
||||
end
|
||||
end
|
||||
|
||||
--- Verifies token and process needed values to be stored in the session.
|
||||
-- Token is obtained from session.auth_token.
|
||||
-- Stores in session the following values:
|
||||
-- session.jitsi_meet_room - the room name value from the token
|
||||
-- session.jitsi_meet_domain - the domain name value from the token
|
||||
-- session.jitsi_meet_context_user - the user details from the token
|
||||
-- session.jitsi_meet_context_room - the room details from the token
|
||||
-- session.jitsi_meet_context_group - the group value from the token
|
||||
-- session.jitsi_meet_context_features - the features value from the token
|
||||
-- @param session the current session
|
||||
-- @return false and error
|
||||
function Util:process_and_verify_token(session)
|
||||
if session.auth_token == nil then
|
||||
if self.allowEmptyToken then
|
||||
return true;
|
||||
else
|
||||
return false, "not-allowed", "token required";
|
||||
end
|
||||
end
|
||||
|
||||
local key;
|
||||
if session.public_key then
|
||||
-- We're using an public key stored in the session
|
||||
-- module:log("debug","Public key was found on the session");
|
||||
key = session.public_key;
|
||||
elseif self.asapKeyServer and session.auth_token ~= nil then
|
||||
-- We're fetching an public key from an ASAP server
|
||||
local dotFirst = session.auth_token:find("%.");
|
||||
if not dotFirst then return false, "not-allowed", "Invalid token" end
|
||||
local header, err = json_safe.decode(basexx.from_url64(session.auth_token:sub(1,dotFirst-1)));
|
||||
if err then
|
||||
return false, "not-allowed", "bad token format";
|
||||
end
|
||||
local kid = header["kid"];
|
||||
if kid == nil then
|
||||
return false, "not-allowed", "'kid' claim is missing";
|
||||
end
|
||||
local alg = header["alg"];
|
||||
if alg == nil then
|
||||
return false, "not-allowed", "'alg' claim is missing";
|
||||
end
|
||||
if alg.sub(alg,1,2) ~= "RS" then
|
||||
return false, "not-allowed", "'kid' claim only support with RS family";
|
||||
end
|
||||
|
||||
if self.cachedKeys and self.cachedKeys[kid] then
|
||||
key = self.cachedKeys[kid];
|
||||
else
|
||||
key = self:get_public_key(kid);
|
||||
end
|
||||
|
||||
if key == nil then
|
||||
return false, "not-allowed", "could not obtain public key";
|
||||
end
|
||||
elseif self.appSecret ~= nil then
|
||||
-- We're using a symmetric secret
|
||||
key = self.appSecret
|
||||
end
|
||||
|
||||
if key == nil then
|
||||
return false, "not-allowed", "signature verification key is missing";
|
||||
end
|
||||
|
||||
-- now verify the whole token
|
||||
local claims, msg = jwt.verify(
|
||||
session.auth_token,
|
||||
self.signatureAlgorithm,
|
||||
key,
|
||||
self.acceptedIssuers,
|
||||
self.acceptedAudiences
|
||||
)
|
||||
if claims ~= nil then
|
||||
if self.requireRoomClaim then
|
||||
local roomClaim = claims["room"];
|
||||
if roomClaim == nil then
|
||||
return false, "'room' claim is missing";
|
||||
end
|
||||
end
|
||||
|
||||
-- Binds room name to the session which is later checked on MUC join
|
||||
session.jitsi_meet_room = claims["room"];
|
||||
-- Binds domain name to the session
|
||||
session.jitsi_meet_domain = claims["sub"];
|
||||
|
||||
-- Binds the user details to the session if available
|
||||
if claims["context"] ~= nil then
|
||||
session.jitsi_meet_str_tenant = claims["context"]["tenant"];
|
||||
|
||||
if claims["context"]["user"] ~= nil then
|
||||
session.jitsi_meet_context_user = claims["context"]["user"];
|
||||
end
|
||||
|
||||
if claims["context"]["group"] ~= nil then
|
||||
-- Binds any group details to the session
|
||||
session.jitsi_meet_context_group = claims["context"]["group"];
|
||||
end
|
||||
|
||||
if claims["context"]["features"] ~= nil then
|
||||
-- Binds any features details to the session
|
||||
session.jitsi_meet_context_features = claims["context"]["features"];
|
||||
end
|
||||
if claims["context"]["room"] ~= nil then
|
||||
session.jitsi_meet_context_room = claims["context"]["room"]
|
||||
end
|
||||
elseif claims["user_id"] then
|
||||
session.jitsi_meet_context_user = {};
|
||||
session.jitsi_meet_context_user.id = claims["user_id"];
|
||||
end
|
||||
|
||||
-- fire event that token has been verified and pass the session and the decoded token
|
||||
prosody.events.fire_event('jitsi-authentication-token-verified', {
|
||||
session = session;
|
||||
claims = claims;
|
||||
});
|
||||
|
||||
if session.contextRequired and claims["context"] == nil then
|
||||
return false, "not-allowed", 'jwt missing required context claim';
|
||||
end
|
||||
|
||||
return true;
|
||||
else
|
||||
return false, "not-allowed", msg;
|
||||
end
|
||||
end
|
||||
|
||||
--- Verifies room name and domain if necessary.
|
||||
-- Checks configs and if necessary checks the room name extracted from
|
||||
-- room_address against the one saved in the session when token was verified.
|
||||
-- Also verifies domain name from token against the domain in the room_address,
|
||||
-- if enableDomainVerification is enabled.
|
||||
-- @param session the current session
|
||||
-- @param room_address the whole room address as received
|
||||
-- @return returns true in case room was verified or there is no need to verify
|
||||
-- it and returns false in case verification was processed
|
||||
-- and was not successful
|
||||
function Util:verify_room(session, room_address)
|
||||
if self.allowEmptyToken and session.auth_token == nil then
|
||||
--module:log("debug", "Skipped room token verification - empty tokens are allowed");
|
||||
return true;
|
||||
end
|
||||
|
||||
-- extract room name using all chars, except the not allowed ones
|
||||
local room,_,_ = jid.split(room_address);
|
||||
if room == nil then
|
||||
log("error",
|
||||
"Unable to get name of the MUC room ? to: %s", room_address);
|
||||
return true;
|
||||
end
|
||||
|
||||
local auth_room = session.jitsi_meet_room;
|
||||
if auth_room then
|
||||
if type(auth_room) == 'string' then
|
||||
auth_room = string.lower(auth_room);
|
||||
else
|
||||
module:log('warn', 'session.jitsi_meet_room not string: %s', auth_room);
|
||||
end
|
||||
end
|
||||
if not self.enableDomainVerification then
|
||||
-- if auth_room is missing, this means user is anonymous (no token for
|
||||
-- its domain) we let it through, jicofo is verifying creation domain
|
||||
if auth_room and (room ~= auth_room and not ends_with(room, ']'..auth_room)) and auth_room ~= '*' then
|
||||
return false;
|
||||
end
|
||||
|
||||
return true;
|
||||
end
|
||||
|
||||
local room_address_to_verify = jid.bare(room_address);
|
||||
local room_node = jid.node(room_address);
|
||||
-- parses bare room address, for multidomain expected format is:
|
||||
-- [subdomain]roomName@conference.domain
|
||||
local target_subdomain, target_room = extract_subdomain(room_node);
|
||||
|
||||
-- if we have '*' as room name in token, this means all rooms are allowed
|
||||
-- so we will use the actual name of the room when constructing strings
|
||||
-- to verify subdomains and domains to simplify checks
|
||||
local room_to_check;
|
||||
if auth_room == '*' then
|
||||
-- authorized for accessing any room assign to room_to_check the actual
|
||||
-- room name
|
||||
if target_room ~= nil then
|
||||
-- we are in multidomain mode and we were able to extract room name
|
||||
room_to_check = target_room;
|
||||
else
|
||||
-- no target_room, room_address_to_verify does not contain subdomain
|
||||
-- so we get just the node which is the room name
|
||||
room_to_check = room_node;
|
||||
end
|
||||
else
|
||||
-- no wildcard, so check room against authorized room from the token
|
||||
if session.jitsi_meet_context_room and (session.jitsi_meet_context_room["regex"] == true or session.jitsi_meet_context_room["regex"] == "true") then
|
||||
if target_room ~= nil then
|
||||
-- room with subdomain
|
||||
room_to_check = target_room:match(auth_room);
|
||||
else
|
||||
room_to_check = room_node:match(auth_room);
|
||||
end
|
||||
else
|
||||
-- not a regex
|
||||
room_to_check = auth_room;
|
||||
end
|
||||
-- module:log("debug", "room to check: %s", room_to_check)
|
||||
if not room_to_check then
|
||||
if not self.requireRoomClaim then
|
||||
-- if we do not require to have the room claim, and it is missing
|
||||
-- there is no point of continue and verifying the roomName and the tenant
|
||||
return true;
|
||||
end
|
||||
|
||||
return false;
|
||||
end
|
||||
end
|
||||
|
||||
if session.jitsi_meet_str_tenant
|
||||
and string.lower(session.jitsi_meet_str_tenant) ~= session.jitsi_web_query_prefix then
|
||||
module:log('warn', 'Tenant differs for user:%s group:%s url_tenant:%s token_tenant:%s',
|
||||
session.jitsi_meet_context_user and session.jitsi_meet_context_user.id or '',
|
||||
session.jitsi_meet_context_group,
|
||||
session.jitsi_web_query_prefix, session.jitsi_meet_str_tenant);
|
||||
session.jitsi_meet_tenant_mismatch = true;
|
||||
end
|
||||
|
||||
local auth_domain = string.lower(session.jitsi_meet_domain);
|
||||
local subdomain_to_check;
|
||||
if target_subdomain then
|
||||
if auth_domain == '*' then
|
||||
-- check for wildcard in JWT claim, allow access if found
|
||||
subdomain_to_check = target_subdomain;
|
||||
else
|
||||
-- no wildcard in JWT claim, so check subdomain against sub in token
|
||||
subdomain_to_check = auth_domain;
|
||||
end
|
||||
-- from this point we depend on muc_domain_base,
|
||||
-- deny access if option is missing
|
||||
if not self.muc_domain_base then
|
||||
module:log("warn", "No 'muc_domain_base' option set, denying access!");
|
||||
return false;
|
||||
end
|
||||
|
||||
return room_address_to_verify == jid.join(
|
||||
"["..subdomain_to_check.."]"..room_to_check, self.muc_domain);
|
||||
else
|
||||
if auth_domain == '*' then
|
||||
-- check for wildcard in JWT claim, allow access if found
|
||||
subdomain_to_check = self.muc_domain;
|
||||
else
|
||||
-- no wildcard in JWT claim, so check subdomain against sub in token
|
||||
subdomain_to_check = self.muc_domain_prefix.."."..auth_domain;
|
||||
end
|
||||
-- we do not have a domain part (multidomain is not enabled)
|
||||
-- verify with info from the token
|
||||
return room_address_to_verify == jid.join(room_to_check, subdomain_to_check);
|
||||
end
|
||||
end
|
||||
|
||||
function Util:generateAsapToken(audience)
|
||||
if not ASAPKey then
|
||||
module:log('warn', 'No ASAP Key read, asap key generation is disabled');
|
||||
return ''
|
||||
end
|
||||
|
||||
audience = audience or ASAPAudience
|
||||
local t = os.time()
|
||||
local err
|
||||
local exp_key = 'asap_exp.'..audience
|
||||
local token_key = 'asap_token.'..audience
|
||||
local exp = jwtKeyCache:get(exp_key)
|
||||
local token = jwtKeyCache:get(token_key)
|
||||
|
||||
--if we find a token and it isn't too far from expiry, then use it
|
||||
if token ~= nil and exp ~= nil then
|
||||
exp = tonumber(exp)
|
||||
if (exp - t) > ASAPTTL_THRESHOLD then
|
||||
return token
|
||||
end
|
||||
end
|
||||
|
||||
--expiry is the current time plus TTL
|
||||
exp = t + ASAPTTL
|
||||
local payload = {
|
||||
iss = ASAPIssuer,
|
||||
aud = audience,
|
||||
nbf = t,
|
||||
exp = exp,
|
||||
}
|
||||
|
||||
-- encode
|
||||
local alg = 'RS256'
|
||||
token, err = jwt.encode(payload, ASAPKey, alg, { kid = ASAPKeyId })
|
||||
if not err then
|
||||
token = 'Bearer '..token
|
||||
jwtKeyCache:set(exp_key, exp)
|
||||
jwtKeyCache:set(token_key, token)
|
||||
return token
|
||||
else
|
||||
return ''
|
||||
end
|
||||
end
|
||||
|
||||
return Util;
|
@ -1,18 +1,22 @@
|
||||
---
|
||||
|
||||
- name: Install prosody
|
||||
yum:
|
||||
package:
|
||||
name:
|
||||
- prosody
|
||||
- lua-ldap
|
||||
- lua-cyrussasl
|
||||
- lua-cjson
|
||||
- lua-basexx
|
||||
- lua-luaossl
|
||||
- libjwt
|
||||
tags: prosody
|
||||
|
||||
- name: Create systemd unit snippet dir
|
||||
file: path=/etc/systemd/system/prosody.service.d state=directory
|
||||
tags: prosody
|
||||
|
||||
- name: Install modules
|
||||
- name: Install remote modules
|
||||
get_url:
|
||||
url: "{{ item.url | default('https://raw.githubusercontent.com/prosody-modules/' ~ item.name ~ '/master/' ~ item.name ~ '.lua') }}"
|
||||
dest: /opt/prosody/modules/{{ item.name }}.lua
|
||||
@ -20,11 +24,14 @@
|
||||
notify: restart prosody
|
||||
tags: prosody
|
||||
|
||||
- name: Install Participan Metadata module
|
||||
- name: Install additional modules
|
||||
copy:
|
||||
src: mod_participant_metadata.lua
|
||||
src: "{{ item }}"
|
||||
dest: /opt/prosody/modules/
|
||||
notify: restart prosody
|
||||
loop:
|
||||
- mod_participant_metadata.lua
|
||||
- token
|
||||
tags: prosody
|
||||
|
||||
- name: Remove useless unit override
|
||||
|
@ -9,6 +9,10 @@
|
||||
- include_tasks: facts.yml
|
||||
tags: always
|
||||
|
||||
- include_tasks: selinux.yml
|
||||
when: ansible_selinux.status == 'enabled'
|
||||
tags: always
|
||||
|
||||
- include_tasks: conf.yml
|
||||
tags: always
|
||||
|
||||
|
28
roles/prosody/tasks/selinux.yml
Normal file
28
roles/prosody/tasks/selinux.yml
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
|
||||
- name: Set correct SELinux context
|
||||
sefcontext:
|
||||
target: "/opt/prosody(/.*)?"
|
||||
setype: lib_t
|
||||
seuser: system_u
|
||||
state: present
|
||||
tags: prosody
|
||||
|
||||
- name: Restore SELinux context
|
||||
command: restorecon -R /opt/prosody/modules
|
||||
changed_when: false
|
||||
tags: prosody
|
||||
|
||||
- name: Copy SELinux policy
|
||||
copy: src=prosody-ansible.te dest=/etc/selinux/targeted/local/
|
||||
register: prosody_selinux_policy
|
||||
tags: prosody
|
||||
|
||||
- name: Compile and load SELinux policy
|
||||
shell: |
|
||||
cd /etc/selinux/targeted/local/
|
||||
checkmodule -M -m -o prosody-ansible.mod prosody-ansible.te
|
||||
semodule_package -o prosody-ansible.pp -m prosody-ansible.mod
|
||||
semodule -i /etc/selinux/targeted/local/prosody-ansible.pp
|
||||
when: prosody_selinux_policy.changed
|
||||
tags: prosody
|
Loading…
x
Reference in New Issue
Block a user