001package ca.cdr.api.model.json;
002
003/*
004 * #%L
005 * Smile CDR - CDR
006 * %%
007 * Copyright (C) 2016 - 2024 Smile CDR, Inc.
008 * %%
009 * All rights reserved.
010 * #L%
011 */
012
013import ca.cdr.api.model.enm.PermissionEnum;
014import com.fasterxml.jackson.annotation.JsonIgnore;
015import com.fasterxml.jackson.annotation.JsonProperty;
016import io.swagger.v3.oas.annotations.media.Schema;
017import jakarta.annotation.Nonnull;
018import org.apache.commons.lang3.builder.EqualsBuilder;
019import org.apache.commons.lang3.builder.HashCodeBuilder;
020import org.slf4j.Logger;
021import org.slf4j.LoggerFactory;
022import org.springframework.security.core.GrantedAuthority;
023
024import static org.apache.commons.lang3.StringUtils.*;
025
026@Schema(
027                name = "GrantedAuthority",
028                description =
029                                "A granted authority is a single user authority (permission) that has been granted to a user. This authority has a permission name, and optionally an argument.")
030public class GrantedAuthorityJson implements GrantedAuthority, IModelJson, Comparable<GrantedAuthorityJson> {
031
032        private static final long serialVersionUID = 1L;
033        private static final Logger ourLog = LoggerFactory.getLogger(GrantedAuthorityJson.class);
034
035        @JsonProperty("permission")
036        @Schema(
037                        description =
038                                        "The name of the permission. See [permissions](/docs/security/roles_and_permissions.html) for "
039                                                        + "information on available permissions.",
040                        accessMode = Schema.AccessMode.READ_ONLY)
041        private PermissionEnum myPermission;
042
043        @JsonProperty("argument")
044        @Schema(
045                        description =
046                                        "The argument for this authority. Note that some permissions do not take an argument while "
047                                                        + "others require an argument. Consult the [permission](/docs/security/roles_and_permissions.html) documentation for more information.",
048                        accessMode = Schema.AccessMode.READ_ONLY)
049        private String myArgument;
050
051        @JsonIgnore
052        private transient Integer myHashCode;
053
054        /**
055         * Constructor
056         */
057        public GrantedAuthorityJson() {
058                super();
059        }
060
061        /**
062         * Constructor
063         */
064        public GrantedAuthorityJson(PermissionEnum thePermission) {
065                this(thePermission, null);
066        }
067
068        /**
069         * Constructor
070         */
071        public GrantedAuthorityJson(PermissionEnum thePermission, String theArgument) {
072                super();
073                myPermission = thePermission;
074                myArgument = theArgument;
075                if (isNotBlank(theArgument)) {
076                        if (!myPermission.isTakesArgument()) {
077                                ourLog.warn("Permission " + thePermission + " does not take any argument");
078                        }
079                } else {
080                        if (myPermission.isTakesArgument() && !myPermission.isArgumentOptional()) {
081                                ourLog.warn("Permission " + thePermission + " requires an argument");
082                        }
083                }
084        }
085
086        @Override
087        public boolean equals(Object theObj) {
088                if (!(theObj instanceof GrantedAuthorityJson)) {
089                        return false;
090                }
091
092                GrantedAuthorityJson obj = (GrantedAuthorityJson) theObj;
093                EqualsBuilder b = new EqualsBuilder();
094                b.append(myPermission, obj.myPermission);
095                b.append(defaultString(myArgument, ""), defaultString(obj.myArgument, ""));
096                return b.isEquals();
097        }
098
099        public String getArgument() {
100                return defaultString(myArgument, null);
101        }
102
103        @Override
104        public String getAuthority() {
105                return myPermission.name();
106        }
107
108        public PermissionEnum getPermission() {
109                return myPermission;
110        }
111
112        @Override
113        public int hashCode() {
114                Integer retVal = myHashCode;
115                if (retVal == null) {
116                        HashCodeBuilder b = new HashCodeBuilder();
117                        b.append(myPermission);
118                        b.append(defaultString(myArgument, ""));
119                        retVal = b.toHashCode();
120                        myHashCode = retVal;
121                }
122                return retVal;
123        }
124
125        @Override
126        public String toString() {
127                if (isBlank(myArgument)) {
128                        return myPermission.name();
129                } else {
130                        return myPermission.name() + "/" + myArgument;
131                }
132        }
133
134        /**
135         * Create a copy of this authority with the same permission but a different argument
136         */
137        public GrantedAuthorityJson withArgument(String theArgument) {
138                return new GrantedAuthorityJson(myPermission, theArgument);
139        }
140
141        @Override
142        public int compareTo(@Nonnull GrantedAuthorityJson theOther) {
143                return toString().compareTo(theOther.toString());
144        }
145
146        /**
147         * @param theValue E.g. "ROLE_FHIR_CLIENT" or "FHIR_READ_ALL_IN_COMPARTMENT/Patient/123"
148         * @throws IllegalArgumentException If the permission is invalid
149         */
150        public static GrantedAuthorityJson parse(String theValue) throws IllegalArgumentException {
151                String permName;
152                String argument;
153                int slashIdx = theValue.indexOf('/');
154                if (slashIdx == -1) {
155                        permName = theValue;
156                        argument = null;
157                } else {
158                        permName = theValue.substring(0, slashIdx);
159                        argument = theValue.substring(slashIdx + 1);
160                }
161
162                PermissionEnum permission;
163                try {
164                        permission = PermissionEnum.valueOf(permName);
165                } catch (Exception e) {
166                        throw new IllegalArgumentException("Unknown permission: " + permName);
167                }
168
169                argument = defaultIfBlank(argument, null);
170
171                return new GrantedAuthorityJson(permission, argument);
172        }
173}