SkyeHoefling / dnn-powershell

A DNN Powershell Module
MIT License
6 stars 0 forks source link

Interacting with the Prompt WebAPI #4

Open donker opened 6 years ago

donker commented 6 years ago

I created the following code to show how you can access the WebAPI through JWT. This should be the basis for the code we'll create.

    class Program
    {
        static void Main(string[] args)
        {
            var scheme = "http";
            var host = "localhost/path/to/site";
            var uname = "host";
            var pass = "dnnhost";
            var url = string.Format("{0}://{1}/DesktopModules/JwtAuth/API/mobile/login", scheme, host);
            var request = WebRequest.Create(url);
            request.ContentType = "application/json; charset=utf-8";
            request.Method = WebRequestMethods.Http.Post;
            using (var streamWriter = new StreamWriter(request.GetRequestStream()))
            {
                string json = "{\"u\":\"" + uname + "\"," +
                              "\"p\":\"" + pass + "\"}";

                streamWriter.Write(json);
                streamWriter.Flush();
                streamWriter.Close();
            }
            string text;
            var response = (HttpWebResponse)request.GetResponse();
            using (var sr = new StreamReader(response.GetResponseStream()))
            {
                text = sr.ReadToEnd();
            }
            var outfile = string.Format("D:\\Documents\\Visual Studio\\Projects\\JwtTest\\{0:HHmmss}.json", DateTime.Now);
            using (var sw = new StreamWriter(outfile, false))
            {
                sw.WriteLine(text);
                sw.Flush();
            }

            var token = Newtonsoft.Json.JsonConvert.DeserializeObject<Jwt>(text);
            var promptUrl = string.Format("{0}://{1}/API/PersonaBar/Command/Cmd", scheme, host);
            request = WebRequest.Create(promptUrl);
            request.ContentType = "application/json; charset=utf-8";
            request.Method = WebRequestMethods.Http.Post;
            request.Headers.Add("Authorization", "Bearer " + token.accessToken);
            using (var streamWriter = new StreamWriter(request.GetRequestStream()))
            {
                string json = "{\"cmdLine\":\"list-commands\"," +
                              "\"currentPage\":\"20\"}";

                streamWriter.Write(json);
                streamWriter.Flush();
                streamWriter.Close();
            }
            response = (HttpWebResponse)request.GetResponse();
            using (var sr = new StreamReader(response.GetResponseStream()))
            {
                text = sr.ReadToEnd();
            }
            outfile = string.Format("D:\\Documents\\Visual Studio\\Projects\\JwtTest\\{0:HHmmss}-prompt.json", DateTime.Now);
            using (var sw = new StreamWriter(outfile, false))
            {
                sw.WriteLine(text);
                sw.Flush();
            }

        }
    }

The token is simply this:

    public class Jwt
    {
        public int userId { get; set; }
        public string displayName { get; set; }
        public string accessToken { get; set; }
        public string renewalToken { get; set; }
    }

Note you need to enable JWT and if you're running locally over http (not https) then you need to adjust the web.config to allow for this.

donker commented 6 years ago

The next step is to decide how we intend the user to manage his/her websites. Here are a few scenarios:

  1. Plain text/csv file with site plus logins. This is of course not good practice and unsafe. But it is trivially simple to do.

  2. If the user wishes to add a site they run a command along the lines "Add-Site {url}". At that moment our code would prompt for a login and get the token. The token then gets added to a local store (where/how?) so that every time we wish to use this url we can use the token.

There are a few hurdles to take in the second example. And keep in mind that the token can be renewed but at some point the renewal will time out and the user needs to log in again. So there is a scenario that even though we have a JWT for the site the renewal can't be done and the user needs to supply his/her credentials again.

SkyeHoefling commented 6 years ago

Is it safe to assume the code you wrote that you are referencing in this thread is the code you submitted in the PR #6 ? I'll be taking a look at the PR at some point tomorrow

donker commented 6 years ago

The code above is sufficient for a proof of concept. I.e. can I authenticate and run a command through the WebAPI from Powershell? That worked.

PR #6 is how I'd set up the project given the success of the code above. It's far from complete but provides the basic mechanism described above and tidied up.