sso.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. <div class="standardContainer">
  2. <div class="ui basic segment">
  3. <h2>Zoraxy SSO / Oauth</h2>
  4. <p>A centralized authentication system for all your subdomains</p>
  5. <div class="ui divider"></div>
  6. <div class="ui basic segment enabled ssoRunningState">
  7. <h4 class="ui header" id="ssoRunningState">
  8. <i class="circle check icon"></i>
  9. <div class="content">
  10. <span class="webserv_status">Running</span>
  11. <div class="sub header">Listen port :<span class="oauthserv_port">8081</span></div>
  12. </div>
  13. </h4>
  14. </div>
  15. <div class="ui form">
  16. <h4 class="ui dividing header">Oauth2 Server</h4>
  17. <div class="field">
  18. <div class="ui toggle checkbox">
  19. <input type="checkbox" name="enableOauth2">
  20. <label>Enable Oauth2 Server<br>
  21. <small>Oauth2 server for handling external authentication requests</small></label>
  22. </div>
  23. </div>
  24. <div class="field">
  25. <label>Oauth2 Server Port</label>
  26. <div class="ui action input">
  27. <input type="number" name="oauth2Port" placeholder="Port" value="5488">
  28. <button id="saveOauthServerPortBtn" class="ui basic green button"><i class="ui green circle check icon"></i> Update</button>
  29. </div>
  30. <small>Listening port of the Zoraxy internal Oauth2 Server.You can create a subdomain proxy rule to <code>127.0.0.1:<span class="ssoPort">5488</span></code></small>
  31. </div>
  32. <div class="field">
  33. <label>Auth URL</label>
  34. <div class="ui action input">
  35. <input type="text" name="authURL" placeholder="https://auth.yourdomain.com">
  36. <button id="saveAuthURLBtn" class="ui basic blue button"><i class="ui blue save icon"></i> Save</button>
  37. </div>
  38. <small>The exposed authentication URL of the Oauth2 server, usually <code>https://auth.example.com</code> or <code>https://sso.yourdomain.com</code>. <b>Remember to include the http:// or https:// in your URL.</b></small>
  39. </div>
  40. </div>
  41. <div class="ui divider"></div>
  42. <div>
  43. <h3 class="ui header">
  44. <i class="ui blue user circle icon"></i>
  45. <div class="content">
  46. Registered Users
  47. <div class="sub header">A list of users that are registered with the SSO server</div>
  48. </div>
  49. </h3>
  50. <table class="ui celled table">
  51. <thead>
  52. <tr>
  53. <th>Username</th>
  54. <th>Registered On</th>
  55. <th>Reset Password</th>
  56. <th>Remove</th>
  57. </tr>
  58. </thead>
  59. <tbody id="registeredSsoUsers">
  60. <tr>
  61. <td>admin</td>
  62. <td>2020-01-01</td>
  63. <td><button class="ui blue basic small icon button"><i class="ui blue key icon"></i></button></td>
  64. <td><button class="ui red basic small icon button"><i class="ui red trash icon"></i></button></td>
  65. </tr>
  66. </tbody>
  67. </table>
  68. <button onclick="handleUserListRefresh();" class="ui basic right floated button"><i class="ui green refresh icon"></i> Refresh</button>
  69. <button onclick="openRegisteredUserManager();" class="ui basic button"><i class="ui blue users icon"></i> Manage Registered Users</button>
  70. </div>
  71. <div class="ui divider"></div>
  72. <div>
  73. <h3 class="ui header">
  74. <i class="ui green th icon"></i>
  75. <div class="content">
  76. Registered Apps
  77. <div class="sub header">A list of apps that are registered with the SSO server</div>
  78. </div>
  79. </h3>
  80. <table class="ui celled table">
  81. <thead>
  82. <tr>
  83. <th>App Name</th>
  84. <th>Domain</th>
  85. <th>App ID</th>
  86. <th>Registered On</th>
  87. <th>Remove</th>
  88. </tr>
  89. </thead>
  90. <tbody id="registeredSsoApps">
  91. <tr>
  92. <td>My App</td>
  93. <td><a href="//example.com" target="_blank">example.com</a></td>
  94. <td>123456</td>
  95. <td>2020-01-01</td>
  96. <td><button class="ui red basic small icon button"><i class="ui red trash icon"></i></button></td>
  97. </tr>
  98. </tbody>
  99. </table>
  100. <button onclick="handleRegisterAppListRefresh();" class="ui basic right floated button"><i class="ui green refresh icon"></i> Refresh</button>
  101. <button onclick="openRegisterAppManagementSnippet();" class="ui basic button"><i style="font-size: 1em; margin-top: -0.2em;" class="ui green th large icon"></i> Manage Registered App</button>
  102. <p></p>
  103. </div>
  104. </div>
  105. </div>
  106. <script>
  107. $("input[name=oauth2Port]").on("change", function() {
  108. $(".ssoPort").text($(this).val());
  109. });
  110. function updateSSOStatus(){
  111. $.get("/api/sso/status", function(data){
  112. if(data.error != undefined){
  113. //Show error message
  114. $(".ssoRunningState").removeClass("enabled").addClass("disabled");
  115. $("#ssoRunningState .webserv_status").html('Error: '+data.error);
  116. }else{
  117. if (data.Enabled){
  118. $(".ssoRunningState").addClass("enabled");
  119. $("#ssoRunningState .webserv_status").html('Running');
  120. $(".ssoRunningState i").attr("class", "circle check icon");
  121. $("input[name=enableOauth2]").parent().checkbox("set checked");
  122. }else{
  123. $(".ssoRunningState").removeClass("enabled");
  124. $("#ssoRunningState .webserv_status").html('Stopped');
  125. $(".ssoRunningState i").attr("class", "circle times icon");
  126. $("input[name=enableOauth2]").parent().checkbox("set unchecked");
  127. }
  128. $("input[name=oauth2Port]").val(data.ListeningPort);
  129. $(".oauthserv_port").text(data.ListeningPort);
  130. $("input[name=authURL]").val(data.AuthURL);
  131. }
  132. });
  133. }
  134. function initSSOStatus(){
  135. $.get("/api/sso/status", function(data){
  136. //Update the SSO status from the server
  137. updateSSOStatus();
  138. //Bind events to the enable checkbox
  139. $("input[name=enableOauth2]").off("change").on("change", function(){
  140. var checked = $(this).prop("checked");
  141. $.cjax({
  142. url: "/api/sso/enable",
  143. method: "POST",
  144. data: {
  145. enable: checked
  146. },
  147. success: function(data){
  148. if(data.error != undefined){
  149. msgbox("Failed to toggle SSO: " + data.error, false);
  150. //Unbind the event to prevent infinite loop
  151. $("input[name=enableOauth2]").off("change");
  152. }else{
  153. initSSOStatus();
  154. }
  155. }
  156. });
  157. });
  158. });
  159. }
  160. initSSOStatus();
  161. /* Save the Oauth server port */
  162. function saveOauthServerPort(){
  163. var port = $("input[name=oauth2Port]").val();
  164. //Check if the port is valid
  165. if (port < 1 || port > 65535){
  166. msgbox("Invalid port number", false);
  167. return;
  168. }
  169. //Use cjax to send the port to the server with csrf token
  170. $.cjax({
  171. url: "/api/sso/setPort",
  172. method: "POST",
  173. data: {
  174. port: port
  175. },
  176. success: function(data) {
  177. if (data.error != undefined) {
  178. msgbox("Failed to update Oauth server port: " + data.error, false);
  179. } else {
  180. msgbox("Oauth server port updated", true);
  181. }
  182. updateSSOStatus();
  183. }
  184. });
  185. }
  186. //Bind the save button to the saveOauthServerPort function
  187. $("#saveOauthServerPortBtn").on("click", function() {
  188. saveOauthServerPort();
  189. });
  190. $("input[name=oauth2Port]").on("keypress", function(e) {
  191. if (e.which == 13) {
  192. saveOauthServerPort();
  193. }
  194. });
  195. /* Save the Oauth server URL (aka AuthURL) */
  196. function saveAuthURL(){
  197. var url = $("input[name=authURL]").val();
  198. //Make sure the url contains http:// or https://
  199. if (!url.startsWith("http://") && !url.startsWith("https://")){
  200. msgbox("Invalid URL. Make sure to include http:// or https://", false);
  201. $("input[name=authURL]").parent().parent().addClass("error");
  202. return;
  203. }else{
  204. $("input[name=authURL]").parent().parent().removeClass("error");
  205. }
  206. //Use cjax to send the port to the server with csrf token
  207. $.cjax({
  208. url: "/api/sso/setAuthURL",
  209. method: "POST",
  210. data: {
  211. "auth_url": url
  212. },
  213. success: function(data) {
  214. if (data.error != undefined) {
  215. msgbox("Failed to update Oauth server port: " + data.error, false);
  216. } else {
  217. msgbox("Oauth server port updated", true);
  218. }
  219. updateSSOStatus();
  220. }
  221. });
  222. }
  223. //Bind the save button to the saveAuthURL function
  224. $("#saveAuthURLBtn").on("click", function() {
  225. saveAuthURL();
  226. });
  227. $("input[name=authURL]").on("keypress", function(e) {
  228. if (e.which == 13) {
  229. saveAuthURL();
  230. }
  231. });
  232. /* Registered Apps Event Handlers */
  233. //Function to initialize the registered app table
  234. function initRegisteredAppTable(){
  235. $.get("/api/sso/app/list", function(data){
  236. if(data.error != undefined){
  237. msgbox("Failed to get registered apps: " + data.error, false);
  238. }else{
  239. var tbody = $("#registeredSsoApps");
  240. tbody.empty();
  241. for(var i = 0; i < data.length; i++){
  242. var app = data[i];
  243. var tr = $("<tr>");
  244. tr.append($("<td>").text(app.AppName));
  245. tr.append($("<td>").html('<a href="//'+app.Domain+'" target="_blank">'+app.Domain+'</a>'));
  246. tr.append($("<td>").text(app.AppID));
  247. tr.append($("<td>").text(app.RegisteredOn));
  248. var removeBtn = $("<button>").addClass("ui red basic small icon button").html('<i class="ui red trash icon"></i>');
  249. removeBtn.on("click", function(){
  250. removeApp(app.AppID);
  251. });
  252. tr.append($("<td>").append(removeBtn));
  253. tbody.append(tr);
  254. }
  255. if (data.length == 0){
  256. tbody.append($("<tr>").append($("<td>").attr("colspan", 4).html(`<i class="ui green circle check icon"></i> No registered users`)));
  257. }
  258. }
  259. });
  260. }
  261. initRegisteredAppTable();
  262. //Also bind the refresh button to the initRegisteredAppTable function
  263. function handleRegisterAppListRefresh(){
  264. initRegisteredAppTable();
  265. }
  266. function openRegisterAppManagementSnippet(){
  267. //Open the register app management snippet
  268. showSideWrapper("snippet/sso_app.html");
  269. }
  270. //Bind the remove button to the removeApp function
  271. function removeApp(appID){
  272. $.cjax({
  273. url: "/api/sso/removeApp",
  274. method: "POST",
  275. data: {
  276. appID: appID
  277. },
  278. success: function(data){
  279. if(data.error != undefined){
  280. msgbox("Failed to remove app: " + data.error, false);
  281. }else{
  282. msgbox("App removed", true);
  283. updateSSOStatus();
  284. }
  285. }
  286. });
  287. }
  288. /* Registered Users Event Handlers */
  289. function initUserList(){
  290. $.get("/api/sso/user/list", function(data){
  291. if(data.error != undefined){
  292. msgbox("Failed to get registered users: " + data.error, false);
  293. }else{
  294. var tbody = $("#registeredSsoUsers");
  295. tbody.empty();
  296. for(var i = 0; i < data.length; i++){
  297. var user = data[i];
  298. var tr = $("<tr>");
  299. tr.append($("<td>").text(user.Username));
  300. tr.append($("<td>").text(user.RegisteredOn));
  301. var resetBtn = $("<button>").addClass("ui blue basic small icon button").html('<i class="ui blue key icon"></i>');
  302. resetBtn.on("click", function(){
  303. resetPassword(user.Username);
  304. });
  305. tr.append($("<td>").append(resetBtn));
  306. var removeBtn = $("<button>").addClass("ui red basic small icon button").html('<i class="ui red trash icon"></i>');
  307. removeBtn.on("click", function(){
  308. removeUser(user.Username);
  309. });
  310. tr.append($("<td>").append(removeBtn));
  311. tbody.append(tr);
  312. }
  313. if (data.length == 0){
  314. tbody.append($("<tr>").append($("<td>").attr("colspan", 4).html(`<i class="ui green circle check icon"></i> No registered users`)));
  315. }
  316. }
  317. });
  318. }
  319. //Bind the refresh button to the initUserList function
  320. function handleUserListRefresh(){
  321. initUserList();
  322. }
  323. function openRegisteredUserManager(){
  324. //Open the registered user management snippet
  325. showSideWrapper("snippet/sso_user.html");
  326. }
  327. </script>