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