1package OpenXPKI::Server::API2::Plugin::Cert::get_cert_actions; 2use OpenXPKI::Server::API2::EasyPlugin; 3 4=head1 NAME 5 6OpenXPKI::Server::API2::Plugin::Cert::get_cert_actions 7 8=cut 9 10use Data::Dumper; 11# Project modules 12use OpenXPKI::Debug; 13use OpenXPKI::Server::Context qw( CTX ); 14use OpenXPKI::Server::API2::Types; 15 16 17 18=head1 COMMANDS 19 20=head2 get_cert_actions 21 22Requires a certificate identifier and optional role. 23Returns a list of actions that the given role (defaults to current 24session role) can do with the given certificate. The return value is a 25nested hash with options available for lifecyle actions. The list of 26workflows is read from the roles uicontrol. The key I<certaction> 27must contain a list where each item is a hash giving label and workflow 28and optional a set of conditions to be met. 29 30Example: 31 32 certaction: 33 - label: I18N_OPENXPKI_UI_DOWNLOAD_PRIVATE_KEY 34 workflow: certificate_privkey_export 35 condition: keyexport 36 37 - label: I18N_OPENXPKI_UI_CERT_ACTION_RENEW 38 workflow: certificate_renewal_request 39 condition: issued 40 41 - label: I18N_OPENXPKI_UI_CERT_ACTION_AUTHORIZE 42 workflow: certificate_authorize 43 condition: issued profile 44 profile: tls-client tls-client-server 45 46The return value is a list with label and workflow set for each element 47that meets the condition(s) given in the I<condition> keyword. Conditions 48are optional, if multiple conditions are given (separated by a whitespace) 49all conditions must be met. 50 51Valid conditions are: 52 53=over 54 55=item keyexport 56 57A private key must exist in the datapool 58 59=item issued 60 61The certificate is not revoked 62 63=item valid 64 65The certificate is not revoked and within the validity interval 66 67=item owner 68 69current user is the certificate owner (see is_certificate_owner) 70 71=item profile 72 73Certificate must be of a certain profile, the list of allowed profiles 74must be given with the I<profile> key, multiple profiles can be given, 75separated by whitespace. 76 77=back 78 79In addition to the conditional checks, the given workflow must be 80accessible by the given role. 81 82B<Parameters> 83 84=over 85 86=item * C<XXX> I<Bool> - XXX. Default: XXX 87 88=back 89 90=cut 91command "get_cert_actions" => { 92 identifier => { isa => 'Base64', required => 1, }, 93 role => { isa => 'Value', }, 94} => sub { 95 my ($self, $params) = @_; 96 97 my $role = $params->has_role ? $params->role : CTX('session')->data->role; 98 my $cert_id = $params->identifier; 99 my $cert = $self->api->get_cert( identifier => $cert_id, format => 'DBINFO' ); 100 ##! 2: "cert $cert_id, role $role" 101 102 # check if this is a entity certificate from the current realm 103 return {} unless $cert->{req_key} and $cert->{pki_realm} eq CTX('session')->data->pki_realm; 104 105 my @actions; 106 my @options; 107 108 my $conn = CTX('config'); 109 110 # check if certaction list is defined for this role 111 if ($conn->exists( ['uicontrol', $role, 'certaction' ])) { 112 @options = $conn->get_list(['uicontrol', $role, 'certaction']); 113 ##! 32: 'Got action list for role ' . Dumper \@options 114 } 115 # default uicontrol 116 elsif ($conn->exists( ['uicontrol', '_default', 'certaction'] )) { 117 @options = $conn->get_list(['uicontrol', '_default', 'certaction']) unless(@options); 118 ##! 32: 'Got action list for ui default ' . Dumper \@options 119 } 120 # Legacy - fallback to the default set 121 else { 122 ##! 32: 'No action list, fall back to default' 123 @options = ( 124 { 125 label => 'I18N_OPENXPKI_UI_DOWNLOAD_PRIVATE_KEY', 126 workflow => 'certificate_privkey_export', 127 condition => 'keyexport' 128 }, 129 { 130 label => 'I18N_OPENXPKI_UI_CERT_ACTION_RENEW', 131 workflow => 'certificate_renewal_request', 132 condition => 'issued' 133 }, 134 { 135 label => 'I18N_OPENXPKI_UI_CERT_ACTION_REVOKE', 136 workflow => 'certificate_revocation_request_v2', 137 condition => 'issued' 138 }, 139 { 140 label => 'I18N_OPENXPKI_UI_CERT_ACTION_UPDATE_METADATA', 141 workflow => 'change_metadata' 142 } 143 ); 144 } 145 146 OPTION: 147 for my $item (@options) { 148 ##! 32: 'Checking Item ' . Dumper $item 149 if ($item->{condition}) { 150 my @cond = split /[\W]/, $item->{condition}; 151 ##! 32: 'Conditions ' . join " + ", @cond 152 for my $rule (@cond) { 153 if ($rule eq 'keyexport') { 154 next OPTION unless $self->api->private_key_exists_for_cert( identifier => $cert_id ); 155 } 156 elsif ($rule eq 'issued') { 157 next OPTION unless ($cert->{status} eq 'ISSUED' or $cert->{status} eq 'EXPIRED'); 158 } 159 elsif ($rule eq 'valid') { 160 next OPTION unless $cert->{status} eq 'ISSUED'; 161 } 162 elsif ($rule eq 'owner') { 163 next OPTION unless $self->api->is_certificate_owner(identifier => $cert_id); 164 } 165 elsif ($rule eq 'profile') { 166 my $profile = $self->api->get_profile_for_cert( identifier => $cert_id ); 167 my @profiles = split /[\s]/, $item->{profile}; 168 next OPTION unless ((grep { $_ eq $profile } @profiles) != 0); 169 } 170 } 171 } 172 173 # all conditions are met, check workflow permissions 174 if ($conn->exists([ 'workflow', 'def', $item->{workflow}, 'acl', $role, 'creator' ] )) { 175 ##! 32: 'Adding Item ' . $item->{label} 176 push @actions, { label => $item->{label}, workflow => $item->{workflow} }; 177 } 178 } 179 180 return { workflow => \@actions }; 181}; 182 183__PACKAGE__->meta->make_immutable; 184