Beispiel #1
0
 private static void MakeQueryParameters(out BMemoryQueryParameters _QueryParameters, string _ItemKey)
 {
     _QueryParameters            = new BMemoryQueryParameters();
     _QueryParameters.Domain     = "PODHEALTCHECK";
     _QueryParameters.SubDomain  = "LOCKER";
     _QueryParameters.Identifier = _ItemKey;
 }
Beispiel #2
0
        /// <summary>
        ///
        /// <para>Subscribe:</para>
        ///
        /// <para>Subscribes to given workspace [_QueryParameters.Domain]:[_QueryParameters.SubDomain]:[_QueryParameters.Identifier] topic</para>
        ///
        /// <para>Check <seealso cref="IBPubSubServiceInterface.Subscribe"/> for detailed documentation</para>
        ///
        /// </summary>
        public bool Subscribe(BMemoryQueryParameters _QueryParameters, Action <string, JObject> _OnMessage, Action <string> _ErrorMessageAction = null)
        {
            if (_OnMessage == null)
            {
                return(false);
            }

            string Topic = _QueryParameters.Domain + ":" + _QueryParameters.SubDomain + ":" + _QueryParameters.Identifier;

            return(CustomSubscribe(Topic, (string TopicParameter, string MessageParameter) =>
            {
                JObject AsJson;
                try
                {
                    AsJson = JObject.Parse(MessageParameter);
                }
                catch (Exception e)
                {
                    AsJson = null;
                    _ErrorMessageAction?.Invoke("BPubSubServiceAWS->Subscribe->Callback: " + e.Message + ", Trace: " + e.StackTrace);
                    if (e.InnerException != null && e.InnerException != e)
                    {
                        _ErrorMessageAction?.Invoke("BPubSubServiceAWS->Subscribe->Callback->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                    }
                }

                if (AsJson != null)
                {
                    _OnMessage?.Invoke(TopicParameter, AsJson);
                }
            }, _ErrorMessageAction));
        }
Beispiel #3
0
        /// <summary>
        ///
        /// <para>DeleteTopicGlobally:</para>
        ///
        /// <para>Deletes all messages and the topic of given workspace [_QueryParameters.Domain]:[_QueryParameters.SubDomain] topic</para>
        ///
        /// <para>Check <seealso cref="IBPubSubServiceInterface.DeleteTopicGlobally"/> for detailed documentation</para>
        ///
        /// </summary>
        public void DeleteTopicGlobally(
            BMemoryQueryParameters _QueryParameters,
            Action <string> _ErrorMessageAction = null)
        {
            string Topic = _QueryParameters.Domain + ":" + _QueryParameters.SubDomain + ":" + _QueryParameters.Identifier;

            DeleteCustomTopicGlobally(Topic, _ErrorMessageAction);
        }
Beispiel #4
0
        private bool MakeQueryParameters(out BMemoryQueryParameters _QueryParameters, out string _PasswordMD5_FromAccessToken)
        {
            _QueryParameters = new BMemoryQueryParameters();
            if (!BUtility.CalculateStringMD5(AccessToken_TokenTypeSpacePrepended, out _PasswordMD5_FromAccessToken, ErrorMessageAction))
            {
                return(false);
            }

            _QueryParameters = MakeSSOQueryParameters(_PasswordMD5_FromAccessToken);
            return(true);
        }
Beispiel #5
0
        /// <summary>
        ///
        /// <para>Publish:</para>
        ///
        /// <para>Publishes the given message to given workspace [_QueryParameters.Domain]:[_QueryParameters.SubDomain]:[_QueryParameters.Identifier] topic</para>
        ///
        /// <para>Check <seealso cref="IBPubSubServiceInterface.Publish"/> for detailed documentation</para>
        ///
        /// </summary>
        public bool Publish(BMemoryQueryParameters _QueryParameters, JObject _Message, Action <string> _ErrorMessageAction = null)
        {
            if (_Message == null)
            {
                return(false);
            }

            string Topic   = _QueryParameters.Domain + ":" + _QueryParameters.SubDomain + ":" + _QueryParameters.Identifier;
            string Message = _Message.ToString();

            return(CustomPublish(Topic, Message, _ErrorMessageAction));
        }
Beispiel #6
0
        private BWebServiceResponse OnRequest_Internal_Logic(
            JObject ParsedBody,
            Action <string> _ErrorMessageAction)
        {
            var ForUrlPath    = (string)ParsedBody["forUrlPath"];
            var RequestMethod = (string)ParsedBody["requestMethod"];

            var SSOTokenRefreshStatus    = Controller_SSOAccessToken.EPerformCheckAndRefreshSuccessStatus.None;
            var AccessTokenWithTokenType = (string)ParsedBody["authorization"];

            string Method;

            if (AccessTokenWithTokenType.StartsWith("Basic"))
            {
                var QueryParameters = new BMemoryQueryParameters()
                {
                    Domain     = Resources_DeploymentManager.Get().GetDeploymentBranchNameEscapedLoweredWithDash().ToUpper(),
                    SubDomain  = "SELF_SIGNED_ACCESS_TOKEN_VALIDATION",
                    Identifier = AccessTokenWithTokenType
                };

                var MethodPrimitive = MemoryService.GetKeyValue(QueryParameters, "method", _ErrorMessageAction);
                if (MethodPrimitive == null)
                {
                    return(BWebResponse.Unauthorized("Token is invalid. Please re-login."));
                }
                Method = MethodPrimitive.AsString;
            }
            else
            {
                var AccessTokenManager = new Controller_SSOAccessToken(AccessTokenWithTokenType, DatabaseService, MemoryService, AzureAD_AppID, AzureAD_ClientSecret, SSOSuperAdmins, _ErrorMessageAction);
                if (AccessTokenManager.PerformCheckAndRefresh(
                        out SSOTokenRefreshStatus,
                        out AccessTokenWithTokenType,
                        out _,
                        out string _EmailAddressWithoutPostfix))
                {
                    ParsedBody["authorization"] = AccessTokenWithTokenType;
                }
Beispiel #7
0
        private bool Perform_SecondLeg_Authorization(
            string _AuthorizationCode_From_FirstLeg,
            BMemoryQueryParameters _SSOStateUniqueID_QueryParameters,
            SSOStateMEntry _SSOState,
            out AuthorizationResult _SuccessResponse,
            out BWebServiceResponse _FailureResponse,
            Action <string> _ErrorMessageAction)
        {
            _SuccessResponse = null;
            _FailureResponse = BWebResponse.InternalError("");

            _SSOState.Status = SSOStateMEntry.STATUS_AUTHORIZING;
            MemoryService.SetKeyValue(_SSOStateUniqueID_QueryParameters,
                                      new Tuple <string, BPrimitiveType>[]
            {
                new Tuple <string, BPrimitiveType>(SSOStateMEntry.HASH_KEY, new BPrimitiveType(JsonConvert.SerializeObject(_SSOState)))
            },
                                      _ErrorMessageAction);
            MemoryService.SetKeyExpireTime(_SSOStateUniqueID_QueryParameters, TimeSpan.FromSeconds(120), _ErrorMessageAction);

            var FormUrlEncodedPairs = new List <KeyValuePair <string, string> >()
            {
                new KeyValuePair <string, string>("client_id", AzureAD_AppID),
                new KeyValuePair <string, string>("scope", SSOCommon.SCOPE),
                new KeyValuePair <string, string>("grant_type", "authorization_code"),
                new KeyValuePair <string, string>("code", _AuthorizationCode_From_FirstLeg),
                new KeyValuePair <string, string>("redirect_uri", WebUtility.UrlDecode(_SSOState.ServersideRedirectUrl)),
                new KeyValuePair <string, string>("client_secret", WebUtility.UrlDecode(AzureAD_ClientSecret))
            };

            using var Handler = new HttpClientHandler
                  {
                      SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
                      ServerCertificateCustomValidationCallback = (a, b, c, d) => true
                  };
            using var Client = new HttpClient(Handler);
            Client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");

            string ResponseString = null;

            try
            {
                using var RequestContent = new FormUrlEncodedContent(FormUrlEncodedPairs);
                using var RequestTask    = Client.PostAsync("https://login.microsoftonline.com/common/oauth2/v2.0/token", RequestContent);
                RequestTask.Wait();

                using var Response        = RequestTask.Result;
                using var ResponseContent = Response.Content;

                using var ReadResponseTask = ResponseContent.ReadAsStringAsync();
                ReadResponseTask.Wait();

                ResponseString = ReadResponseTask.Result;

                if (!Response.IsSuccessStatusCode)
                {
                    bool bJsonParseable = true;
                    try { JObject.Parse(ResponseString); } catch (JsonReaderException) { bJsonParseable = false; }

                    _FailureResponse = new BWebServiceResponse(
                        (int)Response.StatusCode,
                        new BStringOrStream(ResponseString),
                        bJsonParseable ? "application/json" : "text/html");
                    return(false);
                }

                var Parsed = JObject.Parse(ResponseString);
                _SuccessResponse = new AuthorizationResult()
                {
                    TokenType        = (string)Parsed["token_type"],
                    AccessToken      = (string)Parsed["access_token"],
                    ExpiresInSeconds = (int)Parsed["expires_in"],
                    RefreshToken     = (string)Parsed["refresh_token"]
                };
            }
            catch (Exception e)
            {
                if (e.InnerException != null && e.InnerException != e)
                {
                    _ErrorMessageAction?.Invoke("Error: SSOLoginCallback->Perform_SecondLeg_Authorization->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                }
                if (e is AggregateException)
                {
                    foreach (var Inner in (e as AggregateException).InnerExceptions)
                    {
                        _ErrorMessageAction?.Invoke("Error: SSOLoginCallback->Perform_SecondLeg_Authorization->Aggregate->Inner: " + Inner.Message + ", Trace: " + Inner.StackTrace);
                    }
                }
                _ErrorMessageAction?.Invoke("Error: SSOLoginCallback->Perform_SecondLeg_Authorization: Authorization request failed. Response: " + ResponseString + ", message: " + e.Message + ", trace: " + e.StackTrace);
                _FailureResponse = BWebResponse.InternalError("Authorization request has failed.");
                return(false);
            }

            MemoryService.DeleteAllKeys(_SSOStateUniqueID_QueryParameters, true, _ErrorMessageAction);

            return(true);
        }
Beispiel #8
0
        private bool Parse_FirstLeg_Authentication_Content(
            string _ResponseContent,
            out string _AuthorizationCode_From_FirstLeg,
            out BMemoryQueryParameters _SSOStateUniqueID_QueryParameters,
            out SSOStateMEntry _SSOState,
            out string _LocalRedirectUrl_From_FirstLeg,
            out string _EmailAddress_From_FirstLeg,
            out string _AzureADUniqueID_From_FirstLeg,
            out BWebServiceResponse _FailureResponse,
            Action <string> _ErrorMessageAction)
        {
            _AuthorizationCode_From_FirstLeg  = null;
            _SSOStateUniqueID_QueryParameters = new BMemoryQueryParameters();
            _SSOState = null;
            _LocalRedirectUrl_From_FirstLeg = null;
            _EmailAddress_From_FirstLeg     = null;
            _AzureADUniqueID_From_FirstLeg  = null;
            _FailureResponse = BWebResponse.InternalError("");

            _ResponseContent = _ResponseContent.Trim();

            //Handle error
            if (_ResponseContent.StartsWith("error="))
            {
                var ErrorResponse = new JObject()
                {
                    ["result"] = "failure"
                };
                try
                {
                    var ErrorFields = _ResponseContent.Split('&');
                    if (ErrorFields != null && ErrorFields.Length >= 2)
                    {
                        ErrorResponse["error"]   = ErrorFields[0].Substring("error=".Length);
                        ErrorResponse["message"] = ErrorFields[1].Substring("error_description=".Length);
                    }
                }
                catch (Exception) { }

                _FailureResponse = BWebResponse.Unauthorized(ErrorResponse.ToString());
                return(false);
            }

            //Normal flow
            var Splitted = _ResponseContent.Split('&');

            if (Splitted == null || Splitted.Length < 3)
            {
                _FailureResponse = BWebResponse.BadRequest("Request body must contain all requested types. Split has failed.");
                return(false);
            }

            string IDToken    = null;
            string StateField = null;

            for (var i = 0; i < Splitted.Length; i++)
            {
                if (Splitted[i].StartsWith("id_token="))
                {
                    IDToken = Splitted[i].Substring("id_token=".Length);
                }
                else if (Splitted[i].StartsWith("code="))
                {
                    _AuthorizationCode_From_FirstLeg = Splitted[i].Substring("code=".Length);
                }
                else if (Splitted[i].StartsWith("state="))
                {
                    StateField = WebUtility.UrlDecode(Splitted[i].Substring("state=".Length));
                }
            }
            if (IDToken == null || _AuthorizationCode_From_FirstLeg == null || StateField == null)
            {
                _FailureResponse = BWebResponse.BadRequest("Request body must contain all requested types.");
                return(false);
            }

            Splitted = StateField.Split('&');
            if (Splitted == null || Splitted.Length < 3)
            {
                _FailureResponse = BWebResponse.BadRequest("State field must contain all mandatory entries. Split has failed.");
                return(false);
            }

            bool   bSSOStateUniqueID_QueryParameters_Set = false;
            string TenantName = null;

            for (var i = 0; i < Splitted.Length; i++)
            {
                if (Splitted[i].StartsWith("redirect_url="))
                {
                    _LocalRedirectUrl_From_FirstLeg = WebUtility.UrlDecode(Splitted[i].Substring("redirect_url=".Length));
                }
                else if (Splitted[i].StartsWith("tenant="))
                {
                    TenantName = Splitted[i].Substring("tenant=".Length);
                }
                else if (Splitted[i].StartsWith("state="))
                {
                    _SSOStateUniqueID_QueryParameters     = SSOStateMEntry.ID_SSO_STATE_MEMORY_SERVICE_KEY(Splitted[i].Substring("state=".Length));
                    bSSOStateUniqueID_QueryParameters_Set = true;
                }
            }
            if (_LocalRedirectUrl_From_FirstLeg == null || TenantName == null || !bSSOStateUniqueID_QueryParameters_Set)
            {
                _FailureResponse = BWebResponse.BadRequest("State field must contain all mandatory entries.");
                return(false);
            }

            var Serialized = MemoryService.GetKeyValue(_SSOStateUniqueID_QueryParameters, SSOStateMEntry.HASH_KEY, _ErrorMessageAction);

            if (Serialized == null)
            {
                _FailureResponse = BWebResponse.Unauthorized("Login prompt session has expired. Please try again.");
                return(false);
            }
            try
            {
                _SSOState = JsonConvert.DeserializeObject <SSOStateMEntry>(Serialized.AsString);
                if (_SSOState == null)
                {
                    throw new NullReferenceException();
                }
            }
            catch (Exception e)
            {
                _ErrorMessageAction?.Invoke("Error: SSOLoginCallback->Parse_FirstLeg_Authentication_Content: Invalid session state. Message: " + e.Message + ", trace: " + e.StackTrace);
                _FailureResponse = BWebResponse.InternalError("Invalid session state. Please try again.");
                return(false);
            }
            if (_SSOState.Status != SSOStateMEntry.STATUS_AUTHENTICATING)
            {
                _FailureResponse = BWebResponse.Unauthorized("Invalid SSO state. Please try again.");
                return(false);
            }
            if (TenantName != _SSOState.TenantName)
            {
                _FailureResponse = BWebResponse.Unauthorized("SSO state - request tenant mismatch. Please try again.");
                return(false);
            }

            var JWTHandler         = new JwtSecurityTokenHandler();
            JwtSecurityToken Token = null;

            try
            {
                Token = JWTHandler.ReadJwtToken(IDToken);
            }
            catch (Exception e)
            {
                _ErrorMessageAction?.Invoke("Error: SSOLoginCallback->Parse_FirstLeg_Authentication_Content: Invalid JWT token. Token: " + IDToken + ", message: " + e.Message + ", trace: " + e.StackTrace);
                _FailureResponse = BWebResponse.BadRequest("Invalid JWT token.");
                return(false);
            }

            if (!Token.Payload.TryGetValue("email", out object EmailObject))
            {
                _FailureResponse = BWebResponse.BadRequest("JWT token does not contain email in the payload.");
                return(false);
            }

            _EmailAddress_From_FirstLeg = ((string)EmailObject).ToLower();

            if (!Token.Payload.TryGetValue("sub", out object AzureADUserUniqueIDObject))
            {
                _FailureResponse = BWebResponse.BadRequest("JWT token does not contain sub in the payload.");
                return(false);
            }
            _AzureADUniqueID_From_FirstLeg = ((string)AzureADUserUniqueIDObject).ToLower();

            return(true);
        }
Beispiel #9
0
 public void SetMemoryService(IBMemoryServiceInterface _MemoryService, BMemoryQueryParameters _QueryParameters)
 {
     MemoryService   = _MemoryService;
     QueryParameters = _QueryParameters;
 }
Beispiel #10
0
        private BWebServiceResponse OnRequest_Internal(HttpListenerContext _Context, Action <string> _ErrorMessageAction = null)
        {
            if (_Context.Request.HttpMethod != "POST")
            {
                _ErrorMessageAction?.Invoke("LoginRequest: POST method is accepted. But received request method:  " + _Context.Request.HttpMethod);
                return(BWebResponse.MethodNotAllowed("POST method is accepted. But received request method: " + _Context.Request.HttpMethod));
            }

            JObject ParsedBody;

            using (var InputStream = _Context.Request.InputStream)
            {
                using (var ResponseReader = new StreamReader(InputStream))
                {
                    try
                    {
                        ParsedBody = JObject.Parse(ResponseReader.ReadToEnd());
                    }
                    catch (Exception e)
                    {
                        _ErrorMessageAction?.Invoke("LoginRequest-> Read request body stage has failed. Exception: " + e.Message + ", Trace: " + e.StackTrace);
                        return(BWebResponse.BadRequest("Malformed request body. Request must be a valid json form."));
                    }
                }
            }

            if (!ParsedBody.ContainsKey(AuthMethod.API_KEY_PROPERTY) &&
                ((!ParsedBody.ContainsKey(AuthMethod.USER_NAME_PROPERTY) && !ParsedBody.ContainsKey(AuthMethod.USER_EMAIL_PROPERTY)) || !ParsedBody.ContainsKey(AuthMethod.PASSWORD_MD5_PROPERTY)))
            {
                _ErrorMessageAction?.Invoke("LoginRequest-> Request does not have required fields.");
                return(BWebResponse.BadRequest("Request does not have required fields."));
            }

            string Method;

            if (ParsedBody.ContainsKey(AuthMethod.API_KEY_PROPERTY))
            {
                var ApiKey = (string)ParsedBody[AuthMethod.API_KEY_PROPERTY];
                Method = ApiKey;
            }
            else
            {
                var PasswordMD5 = ((string)ParsedBody[AuthMethod.PASSWORD_MD5_PROPERTY]).ToLower();

                if (ParsedBody.ContainsKey(UserDBEntry.USER_NAME_PROPERTY))
                {
                    Method = (string)ParsedBody[UserDBEntry.USER_NAME_PROPERTY] + PasswordMD5;
                }
                else
                {
                    Method = ((string)ParsedBody[UserDBEntry.USER_EMAIL_PROPERTY]).ToLower() + PasswordMD5;
                }
            }

            if (!AuthenticationCommon.FetchUserInfoFromMemoryService_ByMethod(MemoryService, Method, out string UserID, out string _, out string _, _ErrorMessageAction))
            {
                if (!AuthenticationCommon.FetchUserInfoFromDatabaseService_ByMethod(DatabaseService, MemoryService, Method, out UserID, out _, out _, out BWebServiceResponse FailureResponse, _ErrorMessageAction))
                {
                    return(FailureResponse);
                }
            }

            if (!BUtility.CalculateStringMD5(BUtility.RandomString(32, true), out string AccessTokenMD5, _ErrorMessageAction))
            {
                return(BWebResponse.InternalError("Hash operation failed."));
            }

            var AccessTokenMD5WithTokenType = "Basic " + AccessTokenMD5;

            var QueryParameters = new BMemoryQueryParameters()
            {
                Domain     = Resources_DeploymentManager.Get().GetDeploymentBranchNameEscapedLoweredWithDash().ToUpper(),
                SubDomain  = "SELF_SIGNED_ACCESS_TOKEN_VALIDATION",
                Identifier = AccessTokenMD5WithTokenType
            };

            MemoryService.SetKeyValue(QueryParameters, new Tuple <string, BPrimitiveType>[]
            {
                new Tuple <string, BPrimitiveType>("method", new BPrimitiveType(Method))
            },
                                      _ErrorMessageAction);

            MemoryService.SetKeyExpireTime(QueryParameters, TimeSpan.FromHours(1), _ErrorMessageAction);

            return(BWebResponse.StatusOK("Login successful.", new JObject()
            {
                ["userId"] = UserID,
                ["token"] = AccessTokenMD5WithTokenType
            }));
        }
Beispiel #11
0
        public static bool IsTokenExpiredOrInvalid(out Dictionary <string, BPrimitiveType> _Result, IBMemoryServiceInterface _MemoryService, BMemoryQueryParameters _QueryParameters, Action <string> _ErrorMessageAction)
        {
            _Result = _MemoryService.GetKeysValues(_QueryParameters,
                                                   new List <string>()
            {
                UserDBEntry.KEY_NAME_USER_ID,
                "refresh_token",
                "expires_at"
            }, _ErrorMessageAction);

            if (_Result == null)
            {
                return(true);
            }
            if (!_Result.ContainsKey(UserDBEntry.KEY_NAME_USER_ID) || !_Result.ContainsKey("refresh_token") || !_Result.ContainsKey("expires_at"))
            {
                var DebugString = "";
                foreach (var Returned in _Result)
                {
                    DebugString += Returned.Key + "->" + Returned.Value.ToString();
                }
                _ErrorMessageAction?.Invoke("Error: Controller_SSOAccessToken->IsTokenExpiredOrInvalid: MemoryService.GetKeysValues did not return all mandatory fields. Deleting the entry. Returned: " + DebugString);
                _MemoryService.DeleteAllKeys(_QueryParameters, true, _ErrorMessageAction);
                _Result = null;

                return(true);
            }
            if (_Result["expires_at"].AsInteger <= new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds())
            {
                return(true);
            }
            return(false);
        }