update xmpp sasl

This commit is contained in:
AleaJactaEst 2023-12-18 22:53:26 +01:00
parent 981a05cb14
commit 72ad3bf8e5

View file

@ -39,10 +39,40 @@ enum XMPPState {
WAIT_TLS, # Wait TLS Done
MISSING_TLS, # Missing feature TLS -> wait 30min and retry
STARTED_TLS, # TLS connection is done
SELECT_MECHANISM_AUTHENTICATE,
AUTHENTICATE_STEP_PLAIN, # Select mechanism authenticate PLAIN
AUTHENTICATE_STEP_1, # Launch authenticate
AUTHENTICATE_STEP_2, # Launch authenticate
AUTHENTICATE_STEP_3, # Launch authenticate
AUTHENTICATE_CHECK_RESULT, # Last time check result
AUTHENTICATE_FAILURE,
AUTHENTICATE_SUCCESS,
AUTHENTICATED, # We finished authenticate
NOT_AUTHORIZED, # Not Authorize
ACCOUNT_DISABLED, # Account Disable
}
enum ResultAuthenticate {
NONE, # Authenticate not started
DONE, # Authenticate finished and done
ABORT, # Authenticate finished with error (try other method)
NEXT, # Authenticate need execute other step
}
enum SASLReturn {
SUCCESS,
ABORTED,
ACCOUNT_DISABLED,
CREDENTIALS_EXPIRED,
ENCRYPTION_REQUIRED,
INCORRECT_ENCODING,
INVALID_AUTHZID,
INVALID_MECHANISM,
MALFORMED_REQUEST,
MECHANISM_TOO_WEAK,
NOT_AUTHORIZED,
TEMPORARY_AUTH_FAILURE,
UNKNOWN
}
@export var server_xmpp_name:String = "localhost":
@ -98,6 +128,8 @@ func get_locale() -> String:
const MAX_WAIT_CONNECTING:float = 60.0
const MAX_WAIT_MISSING_TLS:float = 1800.0
const MAX_WAIT_ACCOUNT_DISABLED:float = 900.0
const MAX_WAIT_NOT_AUTHORIZED:float = 18000.0
var try_connect:int = 0
var count_connecting_time:float = MAX_WAIT_CONNECTING
@ -108,6 +140,10 @@ var tgt_peer = null
var status:StreamState = StreamState.END
var xmpp_state = XMPPState.NONE
var authentication_methods = []
var selected_mechanism_authenticate:String = ""
var order_preference_mechanism_authenticate: Array = ['PLAIN']
var banned_mechanism_authenticate:Array = []
func reinit_stream():
if ssl_peer != null:
@ -140,6 +176,16 @@ func _process(delta) -> void:
xmpp_state = XMPPState.NONE
else:
count_connecting_time += delta
elif xmpp_state == XMPPState.NOT_AUTHORIZED:
if count_connecting_time >= MAX_WAIT_NOT_AUTHORIZED:
xmpp_state = XMPPState.NONE
else:
count_connecting_time += delta
elif xmpp_state == XMPPState.ACCOUNT_DISABLED:
if count_connecting_time >= MAX_WAIT_ACCOUNT_DISABLED:
xmpp_state = XMPPState.NONE
else:
count_connecting_time += delta
elif xmpp_state == XMPPState.NONE:
if count_connecting_time >= MAX_WAIT_CONNECTING:
xmpp_state = XMPPState.TRY_CONNECT_SERVER
@ -217,10 +263,14 @@ func _process(delta) -> void:
else:
count_connecting_time = 0
xmpp_state = XMPPState.MISSING_TLS
else:
elif response.begins_with("failure"):
send_msg_error.emit(tr("TlS negotiation failed."))
count_connecting_time = 0
xmpp_state = XMPPState.MISSING_TLS
else:
send_msg_error.emit(tr("TlS negotiation failed. (unknow return)"))
count_connecting_time = 0
xmpp_state = XMPPState.MISSING_TLS
elif xmpp_state == XMPPState.WAIT_TLS:
if tcp_peer.get_status() != StreamPeerTCP.STATUS_CONNECTED:
xmpp_state = XMPPState.NONE
@ -264,18 +314,27 @@ func _process(delta) -> void:
if analyze_feature_mechanisms(response):
if authentication_methods.size() > 0:
count_connecting_time = MAX_WAIT_CONNECTING
xmpp_state = XMPPState.AUTHENTICATE_STEP_1
xmpp_state = XMPPState.SELECT_MECHANISM_AUTHENTICATE
#send_msg_debug.emit("AUTHENTICATE_STEP_1")
# elif response.begins_with("<success"):
# stream_status = self.StreamState.STANZA
if xmpp_state == XMPPState.AUTHENTICATE_STEP_1:
if xmpp_state == XMPPState.SELECT_MECHANISM_AUTHENTICATE:
select_mechanism_authenticate(authentication_methods)
if selected_mechanism_authenticate == "NONE":
send_msg_error.emit("Stream: Impossible to find mechanism to authenticate")
xmpp_state = XMPPState.NONE
count_connecting_time = 0
return
elif selected_mechanism_authenticate == "PLAIN":
xmpp_state = XMPPState.AUTHENTICATE_STEP_PLAIN
if xmpp_state == XMPPState.AUTHENTICATE_STEP_PLAIN:
if tcp_peer.get_status() != StreamPeerTCP.STATUS_CONNECTED:
xmpp_state = XMPPState.NONE
count_connecting_time = 0
return
if count_connecting_time >= MAX_WAIT_CONNECTING:
count_connecting_time = 0
negotiate_ssl_sasl(authentication_methods)
negotiate_ssl_authenticate_plain()
else:
count_connecting_time += delta
if (ssl_peer.has_method("poll")):
@ -284,9 +343,59 @@ func _process(delta) -> void:
var response = ssl_peer.get_string(ssl_peer.get_available_bytes())
send_msg_debug.emit("Stream: response: " + response)
response = remove_stream_header(response)
if response.begins_with("<success"):
var res:SASLReturn = get_result_authenticate(response)
if res == SASLReturn.SUCCESS:
count_connecting_time = 0
xmpp_state = XMPPState.AUTHENTICATED
elif res == SASLReturn.NOT_AUTHORIZED:
count_connecting_time = 0
xmpp_state = XMPPState.NOT_AUTHORIZED
elif res == SASLReturn.ACCOUNT_DISABLED:
count_connecting_time = 0
xmpp_state = XMPPState.ACCOUNT_DISABLED
elif res == SASLReturn.NOT_AUTHORIZED:
count_connecting_time = 0
xmpp_state = XMPPState.SELECT_MECHANISM_AUTHENTICATE
banned_mechanism_authenticate.append(selected_mechanism_authenticate)
elif res == SASLReturn.INVALID_MECHANISM:
count_connecting_time = 0
xmpp_state = XMPPState.SELECT_MECHANISM_AUTHENTICATE
banned_mechanism_authenticate.append(selected_mechanism_authenticate)
else:
count_connecting_time = 0
xmpp_state = XMPPState.SELECT_MECHANISM_AUTHENTICATE
banned_mechanism_authenticate.append(selected_mechanism_authenticate)
func get_result_authenticate(response:String) -> SASLReturn:
response = remove_stream_header(response)
if response.begins_with("<success"):
count_connecting_time = 0
return SASLReturn.SUCCESS
elif response.begins_with("<failure"):
if response.contains("<aborted/>"):
return SASLReturn.ABORTED
elif response.contains("<account-disabled/>"):
return SASLReturn.ACCOUNT_DISABLED
if response.contains("<credentials-expired/>"):
return SASLReturn.CREDENTIALS_EXPIRED
if response.contains("<encryption-required/>"):
return SASLReturn.ENCRYPTION_REQUIRED
if response.contains("<incorrect-encoding/>"):
return SASLReturn.INCORRECT_ENCODING
if response.contains("<invalid-authzid/>"):
return SASLReturn.INVALID_AUTHZID
if response.contains("<invalid-mechanism/>"):
return SASLReturn.INVALID_MECHANISM
if response.contains("<malformed-request/>"):
return SASLReturn.MALFORMED_REQUEST
if response.contains("<mechanism-too-weak/>"):
return SASLReturn.MECHANISM_TOO_WEAK
if response.contains("<not-authorized/>"):
return SASLReturn.NOT_AUTHORIZED
if response.contains("<temporary-auth-failure/>"):
return SASLReturn.TEMPORARY_AUTH_FAILURE
return SASLReturn.UNKNOWN
func analyze_error(response:String) -> bool:
@ -373,6 +482,32 @@ func send_ssl_initialize_xmpp() -> void:
send_ssl_string(message)
func select_mechanism_authenticate(authentication_methods : Array) -> void:
selected_mechanism_authenticate = "NONE"
for item in order_preference_mechanism_authenticate:
if banned_mechanism_authenticate.has(item):
continue
elif authentication_methods.has(item):
selected_mechanism_authenticate = item
break
func negotiate_ssl_authenticate_plain() -> void:
send_msg_debug.emit("Stream: sending request for plain")
var msg:PackedByteArray = PackedByteArray()
msg.push_back(0)
var t = account_name.split("@")[0]
msg += t.to_ascii_buffer()
#msg += conv_string_to_PackedByteArray(account_name.split("@")[0])
msg.push_back(0)
msg += password.to_ascii_buffer()
var auth_account:String = Marshalls.raw_to_base64(msg)
var request_sasl:String = "<auth" + \
" xmlns='urn:ietf:params:xml:ns:xmpp-sasl'" + \
" mechanism='PLAIN'" + \
" >" + auth_account + "</auth>"
send_ssl_string(request_sasl)
func negotiate_ssl_sasl(authentication_methods : Array) -> bool:
if ( authentication_methods.has("PLAIN")):