Keycloak RBAC සමඟ Spring Security සුරක්ෂිතභාවය: ගැඹුරු මාර්ගෝපදේශයක්

ආයුබෝවන් යාළුවනේ, කොහොමද ඉතින්?
අපි හැමෝම දන්නවා අපේ software applications හදනකොට ආරක්ෂාව කියන්නේ නැතුවම බැරි දෙයක් කියලා. පොඩි application එකක් වුණත්, ලොකු enterprise system එකක් වුණත්, user කෙනෙකුට තියෙන්න ඕන access level එක හරියට කළමනාකරණය කරන එක හරිම වැදගත්. නැත්නම් ඩේටා එක අවුල් වෙන්න පුළුවන්, සමහර වෙලාවට ලොකු හානි වෙන්නත් පුළුවන්.
අද අපි කතා කරන්න යන්නේ මේ security පැත්තේ තියෙන හරිම වැදගත් concept එකක් ගැන – ඒ තමයි Fine-Grained Authorization, විශේෂයෙන්ම Role-Based Access Control (RBAC). මේක Implement කරන්න ලෝකේ පුරාම ගොඩක් අය පාවිච්චි කරන බලසම්පන්න Identity and Access Management (IAM) විසඳුමක් තමයි Keycloak. අපි බලමු Keycloak භාවිතයෙන් අපේ Spring Boot applications කොහොමද මේ RBAC හරහා ආරක්ෂා කරගන්නේ කියලා, ඒ වගේම methods සහ URLs ආරක්ෂා කරන්න Spring Security වල @PreAuthorize
වගේ annotations කොහොමද පාවිච්චි කරන්නේ කියලත්.
ඉතින්, අපි පටන් ගමු!
RBAC සහ Keycloak හැඳින්වීම
Role-Based Access Control (RBAC) කියන්නේ මොකක්ද?
සරලව කිව්වොත්, RBAC කියන්නේ user කෙනෙකුට application එකක ඇතුළට වෙන්න පුළුවන් දේවල් (permissions) තීරණය කරන්නේ, ඒ user ට දීලා තියෙන role එක අනුවයි. User කෙනෙකුට එක role එකක් හෝ කිහිපයක් තියෙන්න පුළුවන්. උදාහරණයක් විදිහට:
- Admin Role එකක් තියෙන කෙනෙකුට system එකේ හැම දේටම access තියෙන්න පුළුවන්. (data delete කරන්න, users manage කරන්න)
- User Role එකක් තියෙන කෙනෙකුට තියෙන්නේ view-only access එකක් වෙන්න පුළුවන්. (data බලන්න විතරක්)
- Manager Role එකක් තියෙන කෙනෙකුට data approve කරන්න පුළුවන් වෙන්න පුළුවන්.
මේ ක්රමයෙන් security management එක ගොඩක් ලේසි වෙනවා. User කෙනෙක් අලුතෙන් ආවම අපි කරන්නේ එයාලට අදාල role එක assign කරන එක විතරයි. එච්චරයි! ඒක තමයි RBAC වල ලොකුම වාසිය.
Keycloak කියන්නේ මොකක්ද?
Keycloak කියන්නේ Red Hat ආයතනයෙන් නඩත්තු කරන open-source Identity and Access Management (IAM) විසඳුමක්. මේක Single Sign-On (SSO) විදිහටත්, OpenID Connect (OIDC) සහ OAuth 2.0 වගේ industry standards පාවිච්චි කරලා secure authentication සහ authorization ලබා දෙන්නත් පුළුවන්. Keycloak වල ප්රධානම කොටස් ටිකක් ගැන බලමු:
- Realms: Keycloak වල security domain එකක්. Application sets කිහිපයක් වෙන් කරලා manage කරන්න මේක පාවිච්චි කරනවා. උදාහරණයක් විදිහට, company එකේ HR system එකට වෙන realm එකක්, Sales system එකට වෙන realm එකක්.
- Clients: Application එකක් හෝ සේවාවක්. මේවා තමයි Keycloak එකෙන් authentication සහ authorization ගන්න අය. (e.g., your Spring Boot application).
- Users: System එකට log වෙන individuals.
- Roles: User කෙනෙක්ට තියෙන්න පුළුවන් access permissions group එකක්. Keycloak වල roles වර්ග දෙකක් තියෙනවා:
- Realm Roles: මුළු realm එකටම අදාලයි. මේවා සාමාන්යයෙන් user ගේ general capabilities (e.g.,
admin
,user
) විස්තර කරනවා. - Client Roles: යම්කිසි client (application) එකකට විතරක් අදාලයි. මේවා application-specific permissions (e.g.,
product_viewer
,order_creator
) විස්තර කරන්න පාවිච්චි කරනවා.
- Realm Roles: මුළු realm එකටම අදාලයි. මේවා සාමාන්යයෙන් user ගේ general capabilities (e.g.,
Keycloak හි Roles නිර්මාණය සහ කළමනාකරණය
මුලින්ම Keycloak server එකක් install කරගෙන run කරගන්න ඕනේ. Docker පාවිච්චි කරනවා නම් හරිම ලේසියි.
docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:latest start-dev
දැන් http://localhost:8080
වලට ගිහින් Keycloak admin console එකට log වෙන්න පුළුවන්. සාමාන්යයෙන් default master realm එකක් තියෙනවා. අපේ application එකට අලුත් realm එකක් හදාගමු. උදාහරණයක් විදිහට my-app-realm
කියලා.
Realm Roles නිර්මාණය කිරීම
Admin console එකේ my-app-realm
තෝරලා, වම් පැත්තේ menu එකෙන් Roles
වලට ගිහින් අලුත් role එකක් හදන්න පුළුවන්. අපි APP_ADMIN
සහ APP_USER
කියලා roles දෙකක් හදමු.
- Name:
APP_ADMIN
- Name:
APP_USER
Client සහ Client Roles නිර්මාණය කිරීම
දැන් අපේ Spring Boot application එකට client එකක් හදාගමු. වම් පැත්තේ menu එකෙන් Clients
වලට ගිහින් Create client
click කරන්න.
- Client ID:
spring-boot-app
- Client authentication:
Off
(Public client එකක් නිසා) - Authorization:
Off
- Root URL:
http://localhost:8081
(ඔබේ Spring Boot application එක run වෙන port එක) - Valid redirect URIs:
http://localhost:8081/*
- Web origins:
http://localhost:8081
Client එක හදලා ඉවර වුණාට පස්සේ, ඒ client එකේ Roles
tab එකට ගිහින් client roles හදන්න පුළුවන්. අපි PRODUCT_VIEWER
සහ PRODUCT_EDITOR
කියලා roles දෙකක් හදමු.
- Name:
PRODUCT_VIEWER
- Name:
PRODUCT_EDITOR
Users සහ Role Assignment
දැන් Users
වලට ගිහින් අලුත් user කෙනෙක් හදාගමු. උදාහරණයක් විදිහට john.doe
කියලා. එයාලට password එකකුත් set කරන්න. ඊට පස්සේ ඒ user ගේ Role Mappings
tab එකට ගිහින් roles assign කරන්න පුළුවන්. Client Roles
dropdown එකෙන් spring-boot-app
client එක තෝරලා, available roles වලින් PRODUCT_VIEWER
සහ PRODUCT_EDITOR
(හෝ වෙන ඕනෑම එකක්) Assigned Roles
වලට add කරන්න. ඒ වගේම Realm Roles
වලිනුත් APP_ADMIN
හෝ APP_USER
assign කරන්න පුළුවන්. මේ දෙකම Spring Security වලට map වෙන හැටි අපි බලමු.
Spring Boot Application එක Keycloak සමඟ සම්බන්ධ කිරීම
Dependencies Add කිරීම
මුලින්ම Spring Boot project එකකට Keycloak adapter dependencies add කරගන්න ඕනේ. Maven පාවිච්චි කරනවා නම් pom.xml
එකට මේ ටික add කරන්න.
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>24.0.2</version> <!-- Keycloak අනුවාදය අනුව වෙනස් විය හැක -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
application.properties Configuration
දැන් src/main/resources/application.properties
(හෝ application.yml
) file එකට Keycloak configuration එක add කරන්න.
# Keycloak Configuration
keycloak.auth-server-url=http://localhost:8080/
keycloak.realm=my-app-realm
keycloak.resource=spring-boot-app
keycloak.public-client=true
keycloak.use-resource-role-mappings=true # Client roles පාවිච්චි කරනවා නම් මේක true කරන්න
keycloak.ssl-required=none # Development වලට none, Production වලට all
keycloak.cors=true # CORS enabled කරනවා නම්
# Server Port
server.port=8081
keycloak.use-resource-role-mappings=true
කියන එක හරිම වැදගත්. මොකද මේක true
කළොත් තමයි Keycloak client එකට assign කරපු roles, Spring Security වල authorities විදිහට map වෙන්නේ. නැත්නම් realm roles විතරයි map වෙන්නේ.
Spring Security Configuration
Keycloak Spring Boot adapter එකෙන් KeycloakWebSecurityConfigurerAdapter
කියන class එක provide කරනවා. මේක extends කරලා අපිට custom security configuration එකක් හදාගන්න පුළුවන්.
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@KeycloakConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true) // @PreAuthorize enable කරන්න
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
// optionally set simple authority mapper to convert role names to uppercase
// and prefix with "ROLE_" for use with @PreAuthorize("hasRole('ROLE_ADMIN')")
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(buildSessionRegistry());
}
@Bean
protected SessionRegistry buildSessionRegistry() {
return new SessionRegistryImpl();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/public/**").permitAll() // Publicly accessible URLs
.antMatchers("/api/**").authenticated() // /api/ වලින් පටන් ගන්න හැම URL එකටම authenticated user කෙනෙක් ඕනේ
.anyRequest().permitAll() // Default: Allow all for simplicity, or denyAll()
.and()
.csrf().disable(); // REST APIs වලට CSRF අක්රීය කරන්න
}
}
මේ class එකේ @EnableGlobalMethodSecurity(prePostEnabled = true)
කියන annotation එක හරිම වැදගත්. මේක තමයි @PreAuthorize
වගේ annotation පාවිච්චි කරන්න enable කරන්නේ. configureGlobal
method එකේදී අපි SimpleAuthorityMapper()
එකක් set කරලා තියෙනවා. මේකෙන් Keycloak වල roles, Spring Security වලට map වෙද්දී, ROLE_
prefix එකක් add කරලා uppercase කරනවා. උදාහරණයක් විදිහට, Keycloak වල තියෙන APP_ADMIN
කියන role එක Spring Security වලට ROLE_APP_ADMIN
විදිහට map වෙනවා.
Fine-Grained Authorization: @PreAuthorize සමඟ සුරක්ෂිත කිරීම
දැන් තමයි වැඩේට බහින්නේ! අපේ application එකේ methods වලට සහ URLs වලට specific permissions දෙන්නේ කොහොමද කියලා බලමු. Spring Security වල @PreAuthorize
කියන annotation එක මේකට හොඳටම ගැලපෙනවා.
Controller Method එකක් සුරක්ෂිත කිරීම
අපි Product API එකක් හදමු.
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/products")
public class ProductController {
@GetMapping
@PreAuthorize("hasRole('APP_USER') or hasRole('APP_ADMIN') or hasRole('PRODUCT_VIEWER')")
public String getAllProducts() {
// මේ method එකට access කරන්න APP_USER, APP_ADMIN, හෝ PRODUCT_VIEWER role එකක් ඕනේ.
// SimpleAuthorityMapper නිසා මේවා ROLE_APP_USER, ROLE_APP_ADMIN, ROLE_PRODUCT_VIEWER ලෙස map වේ.
return "සියලුම නිෂ්පාදන මෙහි ඇත!";
}
@PostMapping
@PreAuthorize("hasRole('APP_ADMIN') or hasRole('PRODUCT_EDITOR')")
public String createProduct() {
// මේ method එකට access කරන්න APP_ADMIN හෝ PRODUCT_EDITOR role එකක් ඕනේ.
return "නව නිෂ්පාදනයක් සාදන ලදී!";
}
@DeleteMapping("/{id}")
@PreAuthorize("hasAuthority('ROLE_APP_ADMIN')") // 'ROLE_' prefix එක සමඟ exact authority name එක පාවිච්චි කිරීම.
public String deleteProduct(@PathVariable String id) {
// මේ method එකට access කරන්න APP_ADMIN role එක විතරයි ඕනේ.
return id + " අංක දරණ නිෂ්පාදනය මකා දමන ලදී.";
}
@PutMapping("/{id}")
@PreAuthorize("isAuthenticated() and hasAnyRole('APP_ADMIN', 'PRODUCT_EDITOR')")
public String updateProduct(@PathVariable String id) {
// මේ method එකට access කරන්න authenticated user කෙනෙක් වෙන්න ඕනේ වගේම
// APP_ADMIN හෝ PRODUCT_EDITOR role එකකුත් ඕනේ.
return id + " අංක දරණ නිෂ්පාදනය update කරන ලදී.";
}
}
මේ උදාහරණයේදී, අපි Keycloak වල හදපු Realm Roles (APP_ADMIN
, APP_USER
) සහ Client Roles (PRODUCT_VIEWER
, PRODUCT_EDITOR
) දෙකම @PreAuthorize
එකේ පාවිච්චි කරලා තියෙනවා. SimpleAuthorityMapper()
එක නිසා මේවා Spring Security වලට එන්නේ ROLE_APP_ADMIN
, ROLE_PRODUCT_VIEWER
වගේ විදිහට. ඒ නිසා hasRole('ROLE_APP_ADMIN')
වගේ දේවල් ලිව්වොත් වැරදියි. hasRole('APP_ADMIN')
හෝ hasAuthority('ROLE_APP_ADMIN')
විදිහට ලිවිය යුතුයි. hasRole()
කියන එක automatically ROLE_
prefix එක check කරනවා. ඒත් hasAuthority()
නම් exact authority string එකම බලාපොරොත්තු වෙනවා.
Expression-Based Security ටිකක් ගැඹුරට
@PreAuthorize
එකේදී Spring Expression Language (SpEL) පාවිච්චි කරනවා. මේකෙන් අපිට ගොඩක් complex authorization rules ලියන්න පුළුවන්.
hasRole('ROLE_NAME')
: User ට දීලා තියෙන roles අතරේ ROLE_NAME කියන role එක තියෙනවද බලනවා.hasAnyRole('ROLE_NAME1', 'ROLE_NAME2')
: දීලා තියෙන roles වලින් එකක් හරි තියෙනවද බලනවා.hasAuthority('AUTHORITY_NAME')
: User ට දීලා තියෙන authorities අතරේ AUTHORITY_NAME එක තියෙනවද බලනවා. මේකෙන් role එකක් වෙන්නත් පුළුවන්, වෙන custom authority එකක් වෙන්නත් පුළුවන්.isAuthenticated()
: User කෙනෙක් authenticated වෙලාද කියලා බලනවා.principal.username == #username
: User ගේ username එක path variable එකක තියෙන username එකට සමානද කියලා බලනවා. (e.g.,@PreAuthorize("principal.username == #username")
ongetUser(@PathVariable String username)
)hasPermission('domainObject', 'permissionName')
: මේක custom permission logic වලට.
අපේ Keycloak settings වල keycloak.use-resource-role-mappings=true
තියෙන නිසා, Keycloak client roles (e.g., PRODUCT_VIEWER) සහ realm roles (e.g., APP_ADMIN) දෙකම Spring Security වල authorities විදිහට map වෙනවා. ඒ නිසා අපිට hasRole('PRODUCT_VIEWER')
හෝ hasRole('APP_ADMIN')
වගේ use කරන්න පුළුවන්.
හොඳම පුරුදු සහ ගැටළු විසඳීම
Best Practices:
- Client Roles භාවිතය: Application-specific authorization වලට හැමවිටම Client Roles පාවිච්චි කරන්න. Realm Roles වඩාත් සුදුසුයි general permissions (e.g., administrator of the Keycloak realm) වලට.
- Least Privilege Principle: User කෙනෙකුට තමන්ගේ කාර්යය ඉටු කරන්න අවශ්ය අවම permissions විතරක් දෙන්න. අනවශ්ය permissions දෙන්න එපා.
- Separate Realms: Production, Staging, Development වගේ environments වලට වෙන වෙනම Keycloak realms පාවිච්චි කරන්න.
- Consistency: Roles නම් කරනකොට පැහැදිලි, තේරුම්ගත හැකි නම් පාවිච්චි කරන්න.
ROLE_
prefix එක spring security වලට map වෙද්දී add වෙන නිසා ඔබේ Keycloak role එකට මේක add කරන්න අවශ්ය නැහැ. - Logging and Auditing: Authorization failures log කරන්න. ඒ වගේම Security auditing වලට Keycloak වල built-in features පාවිච්චි කරන්න.
Troubleshooting:
- Role එක හඳුනාගන්නේ නැද්ද?:
application.properties
එකේkeycloak.use-resource-role-mappings=true
ද කියලා බලන්න. Client roles පාවිච්චි කරනවා නම් මේක අනිවාර්යයි.- Keycloak වලදී user ට අදාල client එකට role එක assign කරලාද කියලා බලන්න.
- Spring Security configuration එකේ
SimpleAuthorityMapper()
එකක් පාවිච්චි කරනවා නම්, role එකේROLE_
prefix එක automatic add වෙනවා. ඒ නිසා@PreAuthorize
එකේhasRole('APP_ADMIN')
වගේ ලියනවා නම් ඒක වැඩ කරනවා.hasAuthority('ROLE_APP_ADMIN')
වගේ ලිව්වොත් exact string එකම ඕනේ. - User ගේ JWT token එක decode කරලා (JWT.io වගේ tool එකකින්) roles claims වලට එනවද කියලා බලන්න.
- Token Validation Issues: Keycloak configuration (
auth-server-url
,realm
,resource
) හරියටම ගැලපෙනවද කියලා double check කරන්න. - 403 Forbidden Error:
- User ට අදාල role එක තියෙනවද කියලා බලන්න.
@PreAuthorize
annotation එකේ typo එකක් තියෙනවද කියලා බලන්න.@EnableGlobalMethodSecurity(prePostEnabled = true)
Spring Security config class එකට දාලාද කියලා බලන්න.
අවසන් වශයෙන්
අද අපි කතා කළා Fine-Grained Authorization කියන්නේ මොකක්ද, RBAC වල වැදගත්කම, Keycloak සහ Spring Boot එකට එකතු කරගෙන අපේ applications වලට කොහොමද security layer එකක් add කරන්නේ කියලා. @PreAuthorize
වගේ annotations පාවිච්චි කරලා කොහොමද methods සහ URLs වලට specific access rules දෙන්නේ කියලත් අපි බැලුවා.
මේක ඔබේ applications වල security එක ගොඩක් වැඩි කරන වැදගත් පියවරක්. මුලදී පොඩ්ඩක් සංකීර්ණ වගේ පෙනුනත්, මේ concepts හොඳට තේරුම් ගත්තොත් ඔබේ applications ආරක්ෂා කරගන්න එක කිසිම ගැටලුවක් නැතුව කරගන්න පුළුවන්. Keycloak කියන්නේ ගොඩක් බලසම්පන්න tool එකක්, ඒකේ තව ගොඩක් features තියෙනවා Explore කරන්න.
ඉතින්, මේකෙන් ඔබට ප්රයෝජනයක් වෙන්න ඇති කියලා හිතනවා. මේ concepts ඔබේ project වලට implement කරලා බලන්න. මොනවා හරි ප්රශ්න තියෙනවා නම්, ඔබේ අත්දැකීම් පහත comments වලින් බෙදාගන්න අමතක කරන්න එපා. අපි ඊළඟ ලිපියෙන් හම්බවෙමු!