or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication-service.mdindex.mdrequest-credential-handling.mdservice-access-control.md

service-access-control.mddocs/

0

# Service Access Control

1

2

Service-level access control strategies for surrogate authentication enable fine-grained authorization at the individual CAS service level. These strategies determine whether surrogate authentication is permitted for specific services and provide different authorization mechanisms including attribute-based and script-based control.

3

4

## Capabilities

5

6

### Base Access Strategy

7

8

Abstract base class providing common functionality for surrogate-aware service access strategies.

9

10

```java { .api }

11

public abstract class BaseSurrogateRegisteredServiceAccessStrategy extends BaseRegisteredServiceAccessStrategy {

12

13

/**

14

* Check if the current request is from a surrogate authentication session.

15

*

16

* @param request the service access strategy request

17

* @return true if this is a surrogate authentication session

18

*/

19

protected boolean isSurrogateAuthenticationSession(RegisteredServiceAccessStrategyRequest request) {

20

return request.getAttributes().containsKey(SurrogateAuthenticationService.AUTHENTICATION_ATTR_SURROGATE_ENABLED);

21

}

22

}

23

```

24

25

### Attribute-Based Access Strategy

26

27

Service access strategy that uses principal attributes to determine surrogate authentication authorization.

28

29

```java { .api }

30

@Getter

31

@Setter

32

@EqualsAndHashCode(callSuper = true)

33

public class SurrogateRegisteredServiceAccessStrategy extends BaseSurrogateRegisteredServiceAccessStrategy {

34

35

/**

36

* Defines the attribute aggregation behavior when checking for required attributes.

37

* Default requires that all attributes be present and match the principal's.

38

*/

39

protected boolean requireAllAttributes = true;

40

41

/**

42

* Indicates whether matching on required attribute values

43

* should be done in a case-insensitive manner.

44

*/

45

protected boolean caseInsensitive;

46

47

/**

48

* Required attributes for surrogate access authorization.

49

* Map of attribute names to sets of required values.

50

*/

51

private Map<String, Set<String>> surrogateRequiredAttributes = new HashMap<>(0);

52

53

/**

54

* Main authorization method for service access requests.

55

*

56

* @param request the service access request

57

* @return true if access is authorized

58

*/

59

@Override

60

public boolean authorizeRequest(RegisteredServiceAccessStrategyRequest request) {

61

return !isSurrogateAuthenticationSession(request) || doPrincipalAttributesAllowSurrogateServiceAccess(request);

62

}

63

64

/**

65

* Evaluate principal attributes against required surrogate attributes.

66

*

67

* @param request the service access request

68

* @return true if attributes meet requirements

69

*/

70

protected boolean doPrincipalAttributesAllowSurrogateServiceAccess(RegisteredServiceAccessStrategyRequest request) {

71

return RegisteredServiceAccessStrategyEvaluator.builder()

72

.caseInsensitive(this.caseInsensitive)

73

.requireAllAttributes(this.requireAllAttributes)

74

.requiredAttributes(this.surrogateRequiredAttributes)

75

.rejectedAttributes(new LinkedHashMap<>(0))

76

.build()

77

.apply(request);

78

}

79

}

80

```

81

82

### Groovy Script-Based Access Strategy

83

84

Service access strategy that uses Groovy scripts for flexible, programmatic authorization logic.

85

86

```java { .api }

87

@Slf4j

88

@Getter

89

@Setter

90

@EqualsAndHashCode(callSuper = true)

91

public class GroovySurrogateRegisteredServiceAccessStrategy extends BaseSurrogateRegisteredServiceAccessStrategy {

92

93

/**

94

* Path to Groovy script for authorization logic.

95

* Supports Spring Expression Language for dynamic script resolution.

96

*/

97

@ExpressionLanguageCapable

98

private String groovyScript;

99

100

/**

101

* Execute Groovy script to determine authorization.

102

*

103

* @param request the service access request

104

* @return true if access is authorized

105

* @throws Throwable if script execution fails

106

*/

107

@Override

108

public boolean authorizeRequest(RegisteredServiceAccessStrategyRequest request) throws Throwable {

109

if (isSurrogateAuthenticationSession(request)) {

110

try {

111

Object[] args = new Object[]{request.getPrincipalId(), request.getAttributes(), LOGGER};

112

Resource resource = ResourceUtils.getResourceFrom(SpringExpressionLanguageValueResolver.getInstance().resolve(this.groovyScript));

113

ExecutableCompiledScriptFactory scriptFactory = ExecutableCompiledScriptFactory.getExecutableCompiledScriptFactory();

114

return scriptFactory.fromResource(resource).execute(args, Boolean.class);

115

} catch (Exception e) {

116

LoggingUtils.error(LOGGER, e);

117

}

118

return false;

119

}

120

return super.authorizeRequest(request);

121

}

122

}

123

```

124

125

## Usage Examples

126

127

### Configuring Attribute-Based Access Control

128

129

```java

130

import org.apereo.cas.services.SurrogateRegisteredServiceAccessStrategy;

131

132

import java.util.*;

133

134

// Create attribute-based access strategy

135

SurrogateRegisteredServiceAccessStrategy strategy = new SurrogateRegisteredServiceAccessStrategy();

136

137

// Configure to require all attributes and use case-insensitive matching

138

strategy.setRequireAllAttributes(true);

139

strategy.setCaseInsensitive(true);

140

141

// Set required attributes for surrogate access

142

Map<String, Set<String>> requiredAttributes = new HashMap<>();

143

requiredAttributes.put("role", Set.of("admin", "support"));

144

requiredAttributes.put("department", Set.of("IT", "Security"));

145

strategy.setSurrogateRequiredAttributes(requiredAttributes);

146

147

// Use in service registry

148

RegisteredService service = // ... create service

149

service.setAccessStrategy(strategy);

150

```

151

152

### Groovy Script Authorization

153

154

```java

155

import org.apereo.cas.services.GroovySurrogateRegisteredServiceAccessStrategy;

156

157

// Create script-based access strategy

158

GroovySurrogateRegisteredServiceAccessStrategy strategy = new GroovySurrogateRegisteredServiceAccessStrategy();

159

160

// Set Groovy script path (supports classpath:, file:, http: URLs)

161

strategy.setGroovyScript("classpath:surrogate-authorization.groovy");

162

163

// Use in service registry

164

RegisteredService service = // ... create service

165

service.setAccessStrategy(strategy);

166

```

167

168

Example Groovy script (`surrogate-authorization.groovy`):

169

170

```groovy

171

// Script receives: principalId, attributes, logger

172

def principalId = args[0]

173

def attributes = args[1]

174

def logger = args[2]

175

176

logger.debug("Evaluating surrogate access for principal: {}", principalId)

177

178

// Check if user has admin role

179

def roles = attributes.get("roles")

180

if (roles != null && roles.contains("admin")) {

181

logger.info("Granting surrogate access to admin user: {}", principalId)

182

return true

183

}

184

185

// Check business hours for support staff

186

def supportRoles = attributes.get("roles")

187

if (supportRoles != null && supportRoles.contains("support")) {

188

def hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)

189

def isBusinessHours = hour >= 9 && hour <= 17

190

191

if (isBusinessHours) {

192

logger.info("Granting surrogate access to support user during business hours: {}", principalId)

193

return true

194

}

195

}

196

197

logger.warn("Denying surrogate access for principal: {}", principalId)

198

return false

199

```

200

201

### Custom Access Strategy Implementation

202

203

```java

204

import org.apereo.cas.services.BaseSurrogateRegisteredServiceAccessStrategy;

205

import org.apereo.cas.services.RegisteredServiceAccessStrategyRequest;

206

207

public class TimeBoundSurrogateAccessStrategy extends BaseSurrogateRegisteredServiceAccessStrategy {

208

209

private int startHour = 9;

210

private int endHour = 17;

211

212

@Override

213

public boolean authorizeRequest(RegisteredServiceAccessStrategyRequest request) {

214

if (!isSurrogateAuthenticationSession(request)) {

215

return true; // Non-surrogate sessions are always allowed

216

}

217

218

// Check time bounds for surrogate sessions

219

Calendar now = Calendar.getInstance();

220

int currentHour = now.get(Calendar.HOUR_OF_DAY);

221

222

boolean withinBusinessHours = currentHour >= startHour && currentHour <= endHour;

223

224

if (!withinBusinessHours) {

225

LOGGER.warn("Surrogate authentication denied outside business hours for principal: {}",

226

request.getPrincipalId());

227

}

228

229

return withinBusinessHours;

230

}

231

232

// Getters and setters

233

public int getStartHour() { return startHour; }

234

public void setStartHour(int startHour) { this.startHour = startHour; }

235

public int getEndHour() { return endHour; }

236

public void setEndHour(int endHour) { this.endHour = endHour; }

237

}

238

```

239

240

### JSON Configuration

241

242

Service access strategies can be configured via JSON in the CAS service registry:

243

244

```json

245

{

246

"@class": "org.apereo.cas.services.CasRegisteredService",

247

"serviceId": "^https://example\\.com/.*",

248

"name": "Example Service",

249

"id": 1,

250

"accessStrategy": {

251

"@class": "org.apereo.cas.services.SurrogateRegisteredServiceAccessStrategy",

252

"requireAllAttributes": true,

253

"caseInsensitive": false,

254

"surrogateRequiredAttributes": {

255

"@class": "java.util.HashMap",

256

"role": ["admin", "support"],

257

"department": ["IT"]

258

}

259

}

260

}

261

```

262

263

## Required Dependencies

264

265

These classes depend on types from:

266

267

```java

268

import org.apereo.cas.services.BaseRegisteredServiceAccessStrategy;

269

import org.apereo.cas.services.RegisteredServiceAccessStrategyRequest;

270

import org.apereo.cas.services.util.RegisteredServiceAccessStrategyEvaluator;

271

import org.apereo.cas.authentication.surrogate.SurrogateAuthenticationService;

272

import org.apereo.cas.configuration.support.ExpressionLanguageCapable;

273

import org.apereo.cas.util.LoggingUtils;

274

import org.apereo.cas.util.ResourceUtils;

275

import org.apereo.cas.util.scripting.ExecutableCompiledScriptFactory;

276

import org.apereo.cas.util.spring.SpringExpressionLanguageValueResolver;

277

278

import lombok.EqualsAndHashCode;

279

import lombok.Getter;

280

import lombok.Setter;

281

import lombok.extern.slf4j.Slf4j;

282

import lombok.val;

283

284

import org.springframework.core.io.Resource;

285

286

import java.io.Serial;

287

import java.util.*;

288

```