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