Example #1
0
        // function to get actual logs from Microsoft
        // Checks if subscription for specified type is running
        // if it is not returns error and stops
        // if it is
        //      makes a log request
        //      gets nextpage header from response
        //      response will contain 0-200 URLS to call for actual records
        //      spins off new thread to pull down the actual records
        //      thread handles writing to the file
        //      makes next page request
        //      waits until all threads are finished

        public void ThreadedGetLogs()
        {
            ISOLogPullLibrary.AppOptions appOptions = new AppOptions();

            //Removed do to redirects causing error
            //Version 2 - allow use
            //ConsoleSpinner spin = new ConsoleSpinner();


            //This if statement has been deprecated for now
            // subtype in AppOptions has been removed until v2

            // If SubscriptionType was not set in command line
            // try to use value in config file; Allows user to set own default subtype
            // If not set in config use default Exchange

            /*if (SubscriptionType == null)
             * {
             *  if (appOptions.SubscriptionType == "" || appOptions.SubscriptionType == null)
             *  {
             *      SubscriptionType = "Exchange";
             *  }
             *  else
             *  {
             *      SubscriptionType = appOptions.SubscriptionType;
             *  }
             *
             * }*/
            try
            {
                HttpResponseMessage response;
                //HttpResponseMessage logResponse;
                AuthenticationResult authResult = Auth.Result;
                if (authResult == null)
                {
                    Console.WriteLine("Error: Error with Certificate authentication, check if cert properly installed and permissions of user");
                    return;
                }
                string content;
                string request;
                JArray logs = new JArray();
                IEnumerable <string> values = null;

                // check to see if any subscriptions have been started
                // if can't find subscriptions print error and exit

                //*Note - If you are sure subscriptions have been started but are reaching this branch
                //        make sure to check if the certificate was installed properly and that the account
                //        has proper permissions to access this cert.
                //        Service accounts were behaving in a weird way, in which the could not access cert.
                //        If cert was installed on local machine, and not current user, make sure that the
                //        application is run as admin.

                // call ListSubscription method to handle actual requests
                var subscriptionList = ListSubscription();
                if (subscriptionList == null || subscriptionList.Count == 0)
                {
                    //using (StreamWriter writer = new StreamWriter("SubscriptionError.log"))
                    //{
                    Console.WriteLine("Error: No Subscriptions found.");
                    int tmp = StartSubscription();
                    if (tmp == 0)
                    {
                        Console.WriteLine("Error: Failed to start subscription for {0}", SubscriptionType);
                        Console.WriteLine("Specify <start subtype={0}> to manually start subscription", SubscriptionType);
                    }
                    else
                    {
                        Console.WriteLine("Successfully Started Subscription");
                    }
                    return;
                    //}
                }
                else
                {
                    // if there is a non empty response, check to see if the specified
                    // subscription type has been started
                    bool   found = false;
                    string type  = "Audit." + SubscriptionType;
                    foreach (var subscription in subscriptionList)
                    {
                        if (subscription.Value <string>("contentType") == type)
                        {
                            if (subscription.Value <string>("status") == "enabled")
                            {
                                Console.WriteLine(subscription);
                                found = true;
                            }
                        }
                    }

                    if (found == true)
                    {
                        // If found, make default request or use start and end time if specified
                        if (StartTime != null && EndTime != null)
                        {
                            request = String.Format(CultureInfo.InvariantCulture, "https://manage.office.com/api/v1.0/{0}/activity/feed/subscriptions/content?contentType=Audit.{1}&startTime={2}&endTime={3}", appOptions.TenantId, SubscriptionType, StartTime, EndTime);
                            //Console.WriteLine(request);
                        }
                        else
                        {
                            request = String.Format(CultureInfo.InvariantCulture, "https://manage.office.com/api/v1.0/{0}/activity/feed/subscriptions/content?contentType=Audit.{1}", appOptions.TenantId, SubscriptionType);
                        }


                        // use an array of Manual Reset Events to track if threads are done
                        // WaitAll can only handle 64 events
                        // the WaitAll is really only waiting for the last 64 threads to finish
                        // Likelihood of an earlier thread not finishing before the last 64 is very small
                        // Printing out all threads number to verify that they all finish
                        ManualResetEvent[] doneEvents = new ManualResetEvent[64];
                        int i     = 0;
                        int retry = 0;
                        int throttle;
                        do
                        {
                            //spin.Turn();

                            // Get initial page request or nextpage request
                            // Pass the request and authentication result to HttpGet method to make actual Get request
                            throttle = 0;
                            do
                            {
                                response = HttpGet(request, authResult);
                                //response.Headers.TryGetValues("Status", out values);
                                try
                                {
                                    content = response.Content.ReadAsStringAsync().Result;
                                    JObject tmpObj = JObject.Parse(content);
                                    Console.WriteLine(tmpObj["error"]["code"]);
                                    if (tmpObj["error"]["code"].ToString() == "AF429")
                                    {
                                        Thread.Sleep(5000 + (1000 * throttle));
                                        throttle++;
                                    }
                                    else
                                    {
                                        throttle = 20;
                                    }
                                }catch
                                {
                                    throttle = 20;
                                }
                            }while(throttle < 20);



                            // if the response is not null;
                            // often microsoft returns null response for next page requests
                            // library will retry the request up to 50 times sleeping for 2 seconds
                            // each time

                            if (response != null)
                            {
                                // If next page header is specified in response then store in
                                // variable values
                                response.Headers.TryGetValues("NextPageUri", out values);

                                // Read content from body of response
                                // Content will be a json array in string format of up to 200 urls
                                // Each url must be called to obtain actual records
                                content = response.Content.ReadAsStringAsync().Result;

                                // Parse string to JArray object type
                                try
                                {
                                    var records = JArray.Parse(content);

                                    // Create new manual reset event which will be passed to thread
                                    var done = new ManualResetEvent(false);
                                    doneEvents[i % 64] = done;

                                    // Create new Log Object type which has the work item method
                                    // Pass the urls as records, authentication result of certificate authentication,
                                    // the manual reset event, and thread safe Writer, to the contrsuctor class
                                    Log l = new Log(records, authResult, done, SafeWriter);

                                    // Call ThreadPoolCallback method and add to threadpool work item queue
                                    ThreadPool.QueueUserWorkItem(l.ThreadPoolCallback, i);
                                }
                                catch
                                {
                                    Console.Error.WriteLine(content);
                                }


                                // if the NextPageUri header was empty, set request to null to end loop
                                // else set request to the NextPageUri
                                if (values == null)
                                {
                                    request = null;
                                }
                                else
                                {
                                    request = values.First();
                                }
                                //clear values and response, increment i, and then loop
                                values   = null;
                                response = null;
                                i++;
                            }
                            // else branch from if(response !=null)
                            else
                            {
                                // Check if retry attempts below 50
                                // If it is increment sleep and the increment retry and loop
                                if (retry < 50)
                                {
                                    Thread.Sleep(2000);
                                    //Console.WriteLine("Error: Retrying ...");
                                    retry++;
                                }
                                // else print error statement, current threads will finish and application
                                // will end early, there is no way to proceed because we cannot get a NextPageUri
                                else
                                {
                                    Console.Error.WriteLine("Error: Page Request came back null,");
                                    Console.Error.WriteLine("Error: Not all pages were acquired");
                                    retry   = 0;
                                    request = null;
                                }
                            }
                        } while (request != null);

                        // Once all the pages have been received and all the threads needed have been created
                        // application needs to wait for threads to finish, since we are using array need to check
                        // if the array was filled or not.

                        // if less than 64 threads were created, application must resize array to correct length
                        if (i < 64)
                        {
                            Array.Resize <ManualResetEvent>(ref doneEvents, (i));
                        }

                        // Use wait handle all to wait for the last threads to finish
                        int j = i;
                        do
                        {
                            try
                            {
                                Console.WriteLine("Waiting...");
                                WaitHandle.WaitAll(doneEvents);
                                Console.WriteLine("All threads are complete.");
                                j = 0;
                            }
                            catch
                            {
                                j--;
                                if (i < 64)
                                {
                                    Array.Resize <ManualResetEvent>(ref doneEvents, (i));
                                }
                            }
                        } while (j != 0);

                        SafeWriter.Stitch(i);
                    }

                    // else branch from if(found==true)
                    // reach this branch if subscriptions found but not the subtype specified
                    else
                    {
                        //using (StreamWriter writer = new StreamWriter("SubscriptionError.log"))
                        //{
                        Console.WriteLine("Error: Subscription {0} was not found", SubscriptionType);
                        int tmp = StartSubscription();
                        if (tmp == 0)
                        {
                            Console.WriteLine("Error: Failed to start subscription for {0}", SubscriptionType);
                            Console.WriteLine("Specify <start subtype={0}> to manually start subscription", SubscriptionType);
                        }
                        else
                        {
                            Console.WriteLine("Started Subscription");
                        }
                        return;
                        //}
                    }
                }
            }
            // Catch all branch
            catch (Exception ex)
            {
                Console.Error.WriteLine("{0}:{1}", ex.Message, ex.InnerException);
                Console.Error.WriteLine("{0}", ex.ToString());
                return;
            }
        }
Example #2
0
        // Method which attempts to authenticate with cert
        private async Task <AuthenticationResult> CertAuthentication()
        {
            // Create an instance of AppOptions to get values from config
            ISOLogPullLibrary.AppOptions appOptions = new AppOptions();
            ClientAssertionCertificate   cac;
            AuthenticationResult         result      = null;
            AuthenticationContext        authContext = null;

            try
            {
                //this happens regardless of authentication method
                // Find Certificate by thumbprint in Cert Store using getCert method
                // getCert handles checking different stores for cert and permissions
                X509Certificate2 cert = getCert(appOptions.CertThumbPrint);

                // Use clientId and Certificate to create Client Assertion
                cac = new ClientAssertionCertificate(appOptions.ClientId, cert);

                // determine if we're using oauth and act accordingly
                string oAuthUri = appOptions.Authority + appOptions.Oauth2AuthorityId;
                if (appOptions.UseOauth2)
                {
                    authContext = new AuthenticationContext(oAuthUri);
                }
                else
                {
                    // Create an Authentication Context
                    // Uses the Authority attribute from AppOptions
                    // This is the AADInstance + Tenant and is not actually listed in config file
                    authContext = new AuthenticationContext(appOptions.Authority);
                }


                //Attempt to Authenticate to resource id
                try
                {
                    if (appOptions.UseOauth2)
                    {
                        IPlatformParameters ipm = new PlatformParameters(PromptBehavior.Never);
                        //result = await authContext.AcquireTokenAsync(appOptions.ResourceId, appOptions.ClientId, new Uri(appOptions.Oauth2RedirectUi), ipm,);

                        result = await authContext.AcquireTokenAsync(appOptions.ResourceId, cac);
                    }
                    else
                    {
                        // Use the acquire token method and wait until finishes
                        result = await authContext.AcquireTokenAsync(appOptions.ResourceId, cac);
                    }
                    return(result);
                }
                catch (Exception ex)
                {
                    // Return null if can't authenticate
                    Debug.WriteLine(ex.Message);
                    return(null);
                }
            }
            catch (AdalException ex)
            {
                if (ex.ErrorCode != "user_interaction_required")
                {
                    // An unexpected error occurred.
                    Debug.WriteLine(ex.Message);
                }

                // An unexpected error occurred, or user canceled the sign in.
                if (ex.ErrorCode != "access_denied")
                {
                    Debug.WriteLine(ex.Message);
                }

                return(null);
            }
            #endregion
        }