[ https://issues.apache.org/jira/browse/AIRAVATA-2279?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16242964#comment-16242964 ]
ASF GitHub Bot commented on AIRAVATA-2279: ------------------------------------------ stephenpaul2727 closed pull request #75: [AIRAVATA-2279 & 2280] FIXED. URL: https://github.com/apache/airavata-php-gateway/pull/75 This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/app/controllers/AdminController.php b/app/controllers/AdminController.php index 03b67a726..2838d52ae 100644 --- a/app/controllers/AdminController.php +++ b/app/controllers/AdminController.php @@ -121,7 +121,7 @@ public function gatewayView(){ $gatewaysInfo = CRUtilities::getAllGatewayProfilesData(); $gateways = $gatewaysInfo["gateways"]; usort($gateways, array($this, "cmp")); - $tokens = AdminUtilities::get_all_ssh_tokens(); + $tokens = AdminUtilities::get_all_ssh_tokens_with_description(); $pwdTokens = AdminUtilities::get_all_pwd_tokens(); $srData = SRUtilities::getEditSRData(); $crData = CRUtilities::getEditCRData(); @@ -345,9 +345,9 @@ public function deleteRole(){ public function credentialStoreView(){ Session::put("admin-nav", "credential-store"); - $tokens = AdminUtilities::get_all_ssh_tokens(); + $tokens = AdminUtilities::get_all_ssh_tokens_with_description(); $pwdTokens = AdminUtilities::get_all_pwd_tokens(); - //var_dump( $tokens); exit; + // var_dump( $pwdTokens); exit; return View::make("admin/manage-credentials", array("tokens" => $tokens , "pwdTokens" => $pwdTokens) ); } @@ -421,33 +421,33 @@ public function getExperimentsOfTimeRange() } public function createSSH(){ - $newToken = AdminUtilities::create_ssh_token_for_gateway(null); + $description = Input::get("description"); + $newToken = AdminUtilities::create_ssh_token_for_gateway($description); $pubkey = AdminUtilities::get_pubkey_from_token( $newToken); - return Response::json( array( "token" => $newToken, "pubkey" => $pubkey)); + return Redirect::to("admin/dashboard/credential-store")->with("message", "SSH Key was successfully created"); } public function createPWD(){ AdminUtilities::create_pwd_token(Input::all()); - return $this->credentialStoreView(); + return Redirect::to("admin/dashboard/credential-store")->with("message", "Password Credential was successfully created"); + } public function removeSSH(){ $removeToken = Input::get("token"); if( AdminUtilities::remove_ssh_token( $removeToken) ) - return 1; + return Redirect::to("admin/dashboard/credential-store")->with("message", "SSH Key was successfully deleted"); else - return 0; - + return Redirect::to("admin/dashboard/credential-store")->with("error-message", "Unable to delete SSH Key"); } public function removePWD(){ $removeToken = Input::get("token"); if( AdminUtilities::remove_pwd_token( $removeToken) ) - return 1; + return Redirect::to("admin/dashboard/credential-store")->with("message", "Password Credential was successfully deleted"); else - return 0; - + return Redirect::to("admin/dashboard/credential-store")->with("error-message", "Unable to delete Password Credential"); } diff --git a/app/libraries/AdminUtilities.php b/app/libraries/AdminUtilities.php index b66ab4c5e..4620cd348 100644 --- a/app/libraries/AdminUtilities.php +++ b/app/libraries/AdminUtilities.php @@ -332,6 +332,10 @@ public static function get_all_ssh_tokens(){ return Airavata::getAllGatewaySSHPubKeys( Session::get('authz-token'), Session::get("gateway_id") ); } + public static function get_all_ssh_tokens_with_description(){ + return Airavata::getAllCredentialSummaryForGateway( Session::get('authz-token'), "SSH", Session::get("gateway_id") ); + } + public static function get_all_pwd_tokens(){ return Airavata::getAllGatewayPWDCredentials( Session::get('authz-token'), Session::get("gateway_id") ); } diff --git a/app/views/admin/manage-credentials.blade.php b/app/views/admin/manage-credentials.blade.php index daa6149c3..7fc3e0186 100644 --- a/app/views/admin/manage-credentials.blade.php +++ b/app/views/admin/manage-credentials.blade.php @@ -15,58 +15,79 @@ <div class="container-fluid"> <div class="col-md-12"> @if( Session::has("message")) - <div class="row"> - <div class="alert alert-success alert-dismissible" role="alert"> - <button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span - class="sr-only">Close</span></button> - {{ Session::get("message") }} - </div> + <div class="alert alert-success alert-dismissible" role="alert"> + <button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span + class="sr-only">Close</span></button> + {{{ Session::get("message") }}} </div> {{ Session::forget("message") }} @endif + @if( Session::has("error-message")) + <div class="alert alert-danger alert-dismissible" role="alert"> + <button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span + class="sr-only">Close</span></button> + {{{ Session::get("error-message") }}} + </div> + {{ Session::forget("error-message") }} + @endif + <h1 class="text-center">SSH Keys</h1> + <div class="error-alert"></div> + @if(Session::has("admin")) - <table class="table"> - <tr class="text-center table-condensed"> - <td> - <button class="btn btn-default generate-ssh">Generate a new token</button> - </td> - </tr> - </table> - <div class="loading-img text-center hide"> - <img src="../../assets/ajax-loader.gif"/> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">Generate New SSH Key</h3> + </div> + <div class="panel-body"> + <form id="new-ssh-form-submit" class="form-inline" action="{{URL::to('/')}}/admin/create-ssh-token" method="post"> + <div id="credential-description-form-group" class="form-group"> + <label for="credential-description" class="sr-only">Description for new SSH key</label> + <input type="text" id="credential-description" name="description" class="form-control" placeholder="Description" required/> + </div> + <button type="submit" class="btn btn-default">Generate</button> + </form> + </div> </div> @endif - <table class="table table-bordered table-condensed" style="word-wrap: break-word;"> - <tr> - <th class="text-center"> - Token - </th> - <th class="text-center">Public Key</th> - @if( Session::has("admin")) - <th>Delete</th> - @endif - </tr> - <tbody class="token-values-ssh"> - @foreach( $tokens as $token => $publicKey) - <tr> - <td class=""> - {{ $token }} - </td> - <td class="public-key"> - {{ $publicKey }} - </td> - @if( Session::has("admin")) - <td> - <span data-token="{{$token}}" class="glyphicon glyphicon-trash remove-ssh-token"></span> - </td> - @endif - </tr> + + <ul class="list-group"> + @foreach ($tokens as $val) + <li class="list-group-item credential-item"> + <div class="row row_desc"> + <div class="col-md-12 ssh_description"> + @if($val->description!=null) + <p><strong>{{{ $val->description }}}</strong></p> + @else + <p style="color:red"><strong>NO DESCRIPTION!</strong></p> + @endif + </div> + </div><!-- .row --> + <div class="row row_details"> + <div class="col-md-6"> + <div class="input-group"> + <input type="text" class="form-control public-key" readonly + id="credential-publickey-{{$val->token}}" + value="{{ $val->publicKey }}"> + <span class="input-group-btn"> + <button type="button" class="btn btn-default copy-credential" + data-clipboard-target="#credential-publickey-{{$val->token}}" + data-toggle="tooltip" data-placement="bottom" + data-title="Copied!" data-trigger="manual"> + Copy + </button> + </span> + </div> + </div> + <div class="col-md-6"> + <button data-token="{{$val->token}}"class="btn btn-danger delete-credential" + @if(!Session::has("admin")) disabled @endif>Delete</button> + </div><br/> + </div><!-- .row --> + </li> @endforeach - </tbody> - </table> - + </ul> <!-- @if(Session::has("admin")) @@ -113,34 +134,38 @@ class="sr-only">Close</span></button> <img src="../../assets/ajax-loader.gif"/> </div> @endif - <table class="table table-bordered table-condensed" style="word-wrap: break-word;"> - <tr> - <th class="text-center"> - Token - </th> - <th class="text-center">Description</th> - @if( Session::has("admin")) - <th>Delete</th> - @endif - </tr> - <tbody class="token-values"> - @foreach( $pwdTokens as $token => $publicKey) - <tr> - <td class=""> - {{ $token }} - </td> - <td class="description"> - {{ $publicKey }} - </td> - @if( Session::has("admin")) - <td> - <span data-token="{{$token}}" class="glyphicon glyphicon-trash remove-pwd-token"></span> - </td> - @endif - </tr> + <ul class="list-group"> + @foreach ($pwdTokens as $token => $desc) + <li class="list-group-item credential-item"> + <div class="row row_desc"> + <div class="col-md-12 pwd_description"> + <p><strong>{{{ $desc }}}</strong></p> + </div> + </div><!-- .row --> + <div class="row row_details"> + <div class="col-md-6"> + <div class="input-group"> + <input type="text" class="form-control public-key" readonly + id="credential-publickey-{{$token}}" + value="{{ $token }}"> + <span class="input-group-btn"> + <button type="button" class="btn btn-default copy-credential" + data-clipboard-target="#credential-publickey-{{$token}}" + data-toggle="tooltip" data-placement="bottom" + data-title="Copied!" data-trigger="manual"> + Copy + </button> + </span> + </div> + </div> + <div class="col-md-6"> + <button data-token="{{$token}}"class="btn btn-danger remove-pwd-token" + @if(!Session::has("admin")) disabled @endif>Delete</button> + </div><br/> + </div><!-- .row --> + </li> @endforeach - </tbody> - </table> + </ul> {{--<h1 class="text-center">Amazon Credentials</h1>--}} @@ -162,6 +187,56 @@ class="sr-only">Close</span></button> </div> </div> +<div class="modal fade" id="delete-credential-modal" tabindex="-1" role="dialog" aria-labelledby="delete-credential-modal-title" + aria-hidden="true"> + <div class="modal-dialog"> + + <form action="{{URL::to('/')}}/admin/remove-ssh-token" method="POST"> + <div class="modal-content"> + <div class="modal-header"> + <h3 class="text-center" id="delete-credential-modal-title">Delete SSH Public Key</h3> + </div> + <div class="modal-body"> + <input type="hidden" class="form-control" name="token"/> + + Do you really want to delete the "<span class="credential-description"></span>" SSH public key? + </div> + <div class="modal-footer"> + <div class="form-group"> + <input type="submit" class="btn btn-danger" value="Delete"/> + <input type="button" class="btn btn-default" data-dismiss="modal" value="Cancel"/> + </div> + </div> + </div> + </form> + </div> +</div> + +<div class="modal fade" id="delete-pwd-modal" tabindex="-1" role="dialog" aria-labelledby="delete-pwd-modal-title" + aria-hidden="true"> + <div class="modal-dialog"> + + <form action="{{URL::to('/')}}/admin/remove-pwd-token" method="POST"> + <div class="modal-content"> + <div class="modal-header"> + <h3 class="text-center" id="delete-pwd-modal-title">Delete Password Credential</h3> + </div> + <div class="modal-body"> + <input type="hidden" class="form-control" name="token"/> + + Do you really want to delete the "<span class="pwd-description"></span>" Password Credential? + </div> + <div class="modal-footer"> + <div class="form-group"> + <input type="submit" class="btn btn-danger" value="Delete"/> + <input type="button" class="btn btn-default" data-dismiss="modal" value="Cancel"/> + </div> + </div> + </div> + </form> + </div> +</div> + <div class="modal fade" id="pwd-cred-form" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> @@ -217,101 +292,90 @@ class="sr-only">Close</span></button> @section('scripts') @parent +{{ HTML::script('js/clipboard.min.js') }} <script> - $(".generate-ssh").click( function(){ - $(".loading-img").removeClass("hide"); - $.ajax({ - type: "POST", - url: "{{URL::to('/')}}/admin/create-ssh-token" - }).success( function( data){ - - var tokenJson = data; - - //$(".token-values").html(""); - $(".generate-ssh").after("<div class='alert alert-success new-token-msg'>New Token has been generated.</div>"); - - $(".token-values-ssh").prepend("<tr class='alert alert-success'><td>" + tokenJson.token + "</td><td class='public-key'>" + tokenJson.pubkey + "</td>" + "<td><a href=''><span data-token='"+tokenJson.token+"' class='glyphicon glyphicon-trash remove-token'></span></a></td></<tr>"); - $(".loading-img").addClass("hide"); - - setInterval( function(){ - $(".new-token-msg").fadeOut(); - }, 3000); - }).fail( function( data){ - $(".loading-img").addClass("hide"); - - failureObject = $.parseJSON( data.responseText); - $(".generate-ssh").after("<div class='alert alert-danger'>" + failureObject.error.message + "</div>"); - }); - }); + $('.delete-credential').on('click', function(e){ - $(".remove-ssh-token").click( function(){ var removeSpan = $(this); - var tr = removeSpan.parent().parent(); - var tokenToRemove = removeSpan.data("token"); - var publicKey = tr.children(".public-key").html(); - tr.children(".public-key").html("<div class='alert alert-danger'>Do you really want to remove the token? This action cannot be undone.<br/>" + - "<span class='btn-group'>"+ - "<input type='button' class='btn btn-default remove-token-confirmation' value='Yes'/>" + - "<input type='button' class='btn btn-default remove-token-cancel' value='Cancel'/>"+ - "</span></div>"); - - - tr.find( ".remove-token-confirmation").click( function(){ - $(".loading-img").removeClass("hide"); - $.ajax({ - type: "POST", - data:{ "token" : tokenToRemove}, - url: "{{URL::to('/')}}/admin/remove-ssh-token" - }).success( function( data){ - if( data.responseText == 1) - tr.addClass("alert").addClass("alert-danger"); - tr.fadeOut(1000); - }).fail( function( data){ - tr.after("<tr class='alert alert-danger'><td></td><td>Error occurred : " + $.parseJSON( data.responseText).error.message + "</td><td></td></tr>"); - }).complete( function(){ - $(".loading-img").addClass("hide"); - - }); - }); - tr.find( ".remove-token-cancel").click( function(){ - tr.children(".public-key").html( publicKey); - }); - + var par = removeSpan.closest("li"); + var credentialStoreToken = removeSpan.data("token"); + var credentialDescription = $.trim(par.find('.ssh_description').text()); + + if(credentialDescription != "Default SSH Key"){ + $("#delete-credential-modal input[name=token]").val(credentialStoreToken); + $("#delete-credential-modal .credential-description").text(credentialDescription); + $("#delete-credential-modal").modal("show"); + } + else { + $("#delete-credential-modal").modal("hide"); + } + }); + + $('#credential-description').on('invalid', function(event){ + this.setCustomValidity("Please provide a description"); + $('#credential-description-form-group').addClass('has-error'); + }); + $('#credential-description').on('keyup input change', function(event){ + if (this.checkValidity) { + // Reset custom error message. If it isn't empty string it is considered invalid. + this.setCustomValidity(""); + // checkValidity will cause invalid event to be dispatched. See invalid + // event handler above which will set the custom error message. + var valid = this.checkValidity(); + $('#credential-description-form-group').toggleClass('has-error', !valid); + } + }); + + $("#new-ssh-form-submit").submit( function(){ + var description = $("#credential-description").val(); + var items = $('.ssh_description').map(function () { return $.trim($(this).text()); }).get(); + for(var i=0;i<items.length;++i){ + if(description === $.trim(items[i])){ + $('.error-alert').html("<div class='alert alert-danger' role='alert'><button type='button' class='close' data-dismiss='alert'><span aria-hidden='true'>×</span><span class='sr-only'>Close</span></button>Description should be unique for each key.</div>"); + return false; + } + } + return true; }); - $(".remove-pwd-token").click( function(){ - var removeSpan = $(this); - var tr = removeSpan.parent().parent(); - var tokenToRemove = removeSpan.data("token"); - var description = tr.children(".description").html(); - tr.children(".description").html("<div class='alert alert-danger'>Do you really want to remove the token? This action cannot be undone.<br/>" + - "<span class='btn-group'>"+ - "<input type='button' class='btn btn-default remove-token-confirmation' value='Yes'/>" + - "<input type='button' class='btn btn-default remove-token-cancel' value='Cancel'/>"+ - "</span></div>"); - - - tr.find( ".remove-token-confirmation").click( function(){ - $(".loading-img-pwd").removeClass("hide"); - $.ajax({ - type: "POST", - data:{ "token" : tokenToRemove}, - url: "{{URL::to('/')}}/admin/remove-pwd-token" - }).success( function( data){ - if( data.responseText == 1) - tr.addClass("alert").addClass("alert-danger"); - tr.fadeOut(1000); - }).fail( function( data){ - tr.after("<tr class='alert alert-danger'><td></td><td>Error occurred : " + $.parseJSON( data.responseText).error.message + "</td><td></td></tr>"); - }).complete( function(){ - $(".loading-img-pwd").addClass("hide"); - - }); - }); - tr.find( ".remove-token-cancel").click( function(){ - tr.children(".description").html( description); - }); + $("#register-pwd-form").submit( function() { + var pcred_description = $("#description").val(); + var items = $('.pwd_description').map(function() { return $.trim($(this).text()); }).get(); + for(var i=0;i<items.length;++i){ + if(pcred_description === $.trim(items[i])){ + $("#pwd-cred-form").modal("hide"); + $('.error-alert').html("<div class='alert alert-danger' role='alert'><button type='button' class='close' data-dismiss='alert'><span aria-hidden='true'>×</span><span class='sr-only'>Close</span></button>Description should be unique for each key.</div>"); + return false; + } + } + return true; }); + + + $(".remove-pwd-token").click( function(){ + var removeSpan = $(this); + var par = removeSpan.closest("li"); + var credentialStoreToken = removeSpan.data("token"); + var credentialDescription = $.trim(par.find('.pwd_description').text()); + if(credentialDescription != "Keycloak admin password for realm default"){ + $("#delete-pwd-modal input[name=token]").val(credentialStoreToken); + $("#delete-pwd-modal .pwd-description").text(credentialDescription); + $("#delete-pwd-modal").modal("show"); + } + else { + alert("it is not unique"); + $("#delete-pwd-modal").modal("hide"); + } + }); + + var clipboard = new Clipboard('.copy-credential'); + clipboard.on('success', function(e){ + // Show 'Copied!' tooltip for 2 seconds on successful copy + $(e.trigger).tooltip('show'); + setTimeout(function(){ + $(e.trigger).tooltip('hide'); + }, 2000); + }); </script> @stop \ No newline at end of file diff --git a/app/views/partials/compute-resource-preferences.blade.php b/app/views/partials/compute-resource-preferences.blade.php index 62a3a3915..3c485f3e6 100644 --- a/app/views/partials/compute-resource-preferences.blade.php +++ b/app/views/partials/compute-resource-preferences.blade.php @@ -89,8 +89,8 @@ <div class="col-md-9"> <select class="form-control gateway-credential-store-token" name="resourceSpecificCredentialStoreToken" > <option value="">Select a Credential Token from Store</option> - @foreach( $tokens as $token => $publicKey) - <option value="{{$token}}" @if( isset( $preferences) ) @if( $token == $preferences->resourceSpecificCredentialStoreToken) selected @endif @endif>{{$token}}</option> + @foreach( $tokens as $val) + <option value="{{$val->token}}" @if( isset( $preferences) ) @if( $val->token == $preferences->resourceSpecificCredentialStoreToken) selected @endif @endif>{{$val->description}}</option> @endforeach <option value="">DO-NO-SET</option> </select> diff --git a/app/views/partials/gateway-preferences-block.blade.php b/app/views/partials/gateway-preferences-block.blade.php index c112b469e..2f2c0896f 100644 --- a/app/views/partials/gateway-preferences-block.blade.php +++ b/app/views/partials/gateway-preferences-block.blade.php @@ -27,14 +27,14 @@ <label class="control-label col-md-12">{{ Session::get('theme') }} Credential Store Token</label> <div class="col-md-9"> <select class="form-control gateway-credential-store-token" id="gateway-credential-store-token" name="resourceSpecificCredentialStoreToken" data-gpid="{{$gp->gatewayId}}" > + <option value="">Select a Credential Token from Store</option> @if( isset( $gp->profile->credentialStoreToken) ) - @foreach( $tokens as $token => $publicKey) - <option value="{{$token}}" @if( $token == $gp->profile->credentialStoreToken) selected @endif>{{$token}}</option> + @foreach( $tokens as $val) + <option value="{{$val->token}}" @if( $val->token == $gp->profile->credentialStoreToken) selected @endif>{{$val->description}}</option> @endforeach @else - <option value="">Select a Credential Token from Store</option> - @foreach( $tokens as $token => $publicKey) - <option value="{{$token}}">{{$token}}</option> + @foreach( $tokens as $val) + <option value="{{$val->token}}">{{$val->description}}</option> @endforeach @endif <option value="">DO-NO-SET</option> diff --git a/app/views/partials/storage-resource-preferences.blade.php b/app/views/partials/storage-resource-preferences.blade.php index ca432917a..22fd31433 100644 --- a/app/views/partials/storage-resource-preferences.blade.php +++ b/app/views/partials/storage-resource-preferences.blade.php @@ -40,8 +40,8 @@ <div class="col-md-9"> <select class="form-control gateway-credential-store-token" name="resourceSpecificCredentialStoreToken" > <option value="">Select a Credential Token from Store</option> - @foreach( $tokens as $token => $publicKey) - <option value="{{$token}}" @if( isset( $preferences) ) @if( $token == $preferences->resourceSpecificCredentialStoreToken) selected @endif @endif>{{$token}}</option> + @foreach( $tokens as $val) + <option value="{{$val->token}}" @if( isset( $preferences) ) @if( $val->token == $preferences->resourceSpecificCredentialStoreToken) selected @endif @endif>{{$val->description}}</option> @endforeach <option value="">DO-NO-SET</option> </select> ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org > Gateway credential store UI also to have the same format as individual user > settings > ------------------------------------------------------------------------------------ > > Key: AIRAVATA-2279 > URL: https://issues.apache.org/jira/browse/AIRAVATA-2279 > Project: Airavata > Issue Type: Bug > Components: PGA PHP Web Gateway > Environment: dev.seagrid.org > Reporter: Eroma > Assignee: Marcus Christie > Fix For: 0.18 > > > Currently there are no description ora copy button to copy the public key in > gateway credential store. > Unifying the UI with User settings will make it easy for the gateway admins. -- This message was sent by Atlassian JIRA (v6.4.14#64029)