sso.html 16 KB

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