### Run Spring Boot Example Source: https://github.com/apache/shiro/blob/main/samples/spring-boot-3-web/README.md Use this command to run the Spring Boot example application locally. Ensure Maven is installed. ```bash mvn spring-boot:run ``` -------------------------------- ### Configure JdbcRealm Programmatically Source: https://context7.com/apache/shiro/llms.txt Sets up a JdbcRealm with custom SQL queries for authentication, roles, and permissions. ```java import org.apache.shiro.realm.jdbc.JdbcRealm; import org.apache.shiro.realm.jdbc.JdbcRealm.SaltStyle; import javax.sql.DataSource; // Create and configure JdbcRealm JdbcRealm jdbcRealm = new JdbcRealm(); // Set the data source DataSource dataSource = getDataSource(); // Your DataSource implementation jdbcRealm.setDataSource(dataSource); // Custom authentication query (default: "select password from users where username = ?") jdbcRealm.setAuthenticationQuery( "SELECT password FROM app_users WHERE username = ? AND active = true" ); // Custom user roles query (default: "select role_name from user_roles where username = ?") jdbcRealm.setUserRolesQuery( "SELECT r.role_name FROM user_roles ur " + "JOIN roles r ON ur.role_id = r.id " + "WHERE ur.username = ?" ); // Enable permission lookup jdbcRealm.setPermissionsLookupEnabled(true); // Custom permissions query (default: "select permission from roles_permissions where role_name = ?") jdbcRealm.setPermissionsQuery( "SELECT permission FROM role_permissions WHERE role_name = ?" ); // Configure salt style for password hashing jdbcRealm.setSaltStyle(SaltStyle.COLUMN); // Database schema example: // CREATE TABLE users ( // username VARCHAR(100) PRIMARY KEY, // password VARCHAR(255) NOT NULL, // password_salt VARCHAR(255), // active BOOLEAN DEFAULT true // ); // // CREATE TABLE user_roles ( // username VARCHAR(100), // role_name VARCHAR(100), // PRIMARY KEY (username, role_name) // ); // // CREATE TABLE roles_permissions ( // role_name VARCHAR(100), // permission VARCHAR(255), // PRIMARY KEY (role_name, permission) // ); ``` -------------------------------- ### Initialize SecurityManager and Access Subject with SecurityUtils Source: https://context7.com/apache/shiro/llms.txt Demonstrates initializing the SecurityManager from an INI file and obtaining the current Subject using SecurityUtils. Useful for setting up Shiro in an application. ```java import org.apache.shiro.SecurityUtils; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.env.BasicIniEnvironment; // Initialize SecurityManager from INI configuration SecurityManager securityManager = new BasicIniEnvironment("classpath:shiro.ini").getSecurityManager(); SecurityUtils.setSecurityManager(securityManager); // Get the currently executing Subject (user) Subject currentUser = SecurityUtils.getSubject(); // Check if user is authenticated if (currentUser.isAuthenticated()) { System.out.println("User " + currentUser.getPrincipal() + " is logged in"); } // Get the SecurityManager if needed SecurityManager sm = SecurityUtils.getSecurityManager(); ``` -------------------------------- ### Apply Shiro Security Annotations Source: https://context7.com/apache/shiro/llms.txt Demonstrates securing service methods using Shiro's permission and role-based annotations. ```java // Service using Shiro annotations import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; import org.springframework.stereotype.Service; @Service public class DocumentService { @RequiresPermissions("document:read") public Document getDocument(Long id) { // Only users with 'document:read' permission can call this return documentRepository.findById(id); } @RequiresPermissions("document:write") public void saveDocument(Document doc) { // Only users with 'document:write' permission can call this return documentRepository.save(doc); } @RequiresRoles("admin") public void deleteDocument(Long id) { // Only admins can delete documentRepository.delete(id); } } ``` -------------------------------- ### Create and Commit Changes Source: https://github.com/apache/shiro/blob/main/CONTRIBUTING.md Create a new branch for your changes, make modifications, and commit them with a descriptive message. ```bash $ git checkout -b feature_x (make your changes) $ git status $ git add . $ git commit -a -m "descriptive commit message for your changes" ``` -------------------------------- ### Run the Shiro Spring Web Application Source: https://github.com/apache/shiro/blob/main/samples/spring/README.md Executes the web application using the Maven Jetty plugin. ```bash mvn jetty:run ``` -------------------------------- ### Programmatic Subject Creation with Subject.Builder Source: https://context7.com/apache/shiro/llms.txt Demonstrates building Subjects with specific identities, session IDs, or host information, and executing code within those contexts. ```java import org.apache.shiro.SecurityUtils; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.Subject; SecurityManager securityManager = SecurityUtils.getSecurityManager(); // Build a Subject with known identity (useful for background jobs) PrincipalCollection principals = new SimplePrincipalCollection("systemUser", "myRealm"); Subject systemSubject = new Subject.Builder(securityManager) .principals(principals) .authenticated(true) .buildSubject(); // Execute code as this subject systemSubject.execute(() -> { // This code runs as 'systemUser' Subject current = SecurityUtils.getSubject(); System.out.println("Executing as: " + current.getPrincipal()); // Perform privileged operations... }); // Build Subject from existing session ID String sessionId = "abc123..."; // Retrieved from cookie or header Subject sessionSubject = new Subject.Builder() .sessionId(sessionId) .buildSubject(); // Build Subject with specific host Subject remoteSubject = new Subject.Builder() .principals(principals) .host("192.168.1.100") .sessionCreationEnabled(false) // Stateless .buildSubject(); // Associate callable with subject for async execution Callable task = systemSubject.associateWith(() -> { // This will execute with systemSubject's context return "Task completed by " + SecurityUtils.getSubject().getPrincipal(); }); // Execute in thread pool ExecutorService executor = Executors.newFixedThreadPool(4); Future future = executor.submit(task); ``` -------------------------------- ### Implement Custom Realm in Java Source: https://context7.com/apache/shiro/llms.txt Extend AuthorizingRealm to integrate custom authentication and authorization logic with a data source. Requires implementing doGetAuthenticationInfo and doGetAuthorizationInfo methods. ```java import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; public class MyCustomRealm extends AuthorizingRealm { // Injected DAO or service for database access private UserService userService; public MyCustomRealm() { setName("MyCustomRealm"); } // Called during login to get authentication info @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); // Fetch user from database User user = userService.findByUsername(username); if (user == null) { throw new UnknownAccountException("No account found for user: " + username); } if (user.isLocked()) { throw new LockedAccountException("Account is locked: " + username); } // Return authentication info (principal, credentials, realm name) // Shiro will compare submitted password with stored password return new SimpleAuthenticationInfo( user.getId(), // Principal (user identifier) user.getPassword(), // Stored hashed password getName() // Realm name ); } // Called to get authorization info (roles and permissions) @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { Long userId = (Long) principals.getPrimaryPrincipal(); User user = userService.findById(userId); if (user == null) { return null; } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // Add user's roles for (Role role : user.getRoles()) { info.addRole(role.getName()); // Add permissions associated with each role info.addStringPermissions(role.getPermissions()); } // Add direct user permissions info.addStringPermissions(user.getDirectPermissions()); return info; } public void setUserService(UserService userService) { this.userService = userService; } } ``` -------------------------------- ### Subject Authentication with UsernamePasswordToken Source: https://context7.com/apache/shiro/llms.txt Shows how to authenticate a user using UsernamePasswordToken, including enabling 'Remember Me' and handling various authentication exceptions. Ensure to clear sensitive token data in the finally block. ```java import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.subject.Subject; Subject currentUser = SecurityUtils.getSubject(); if (!currentUser.isAuthenticated()) { // Create authentication token with username and password UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); // Enable "Remember Me" functionality token.setRememberMe(true); try { // Perform login currentUser.login(token); System.out.println("User [" + currentUser.getPrincipal() + "] logged in successfully."); } catch (UnknownAccountException uae) { System.out.println("No account found for user: " + token.getPrincipal()); } catch (IncorrectCredentialsException ice) { System.out.println("Invalid password for user: " + token.getPrincipal()); } catch (LockedAccountException lae) { System.out.println("Account is locked for user: " + token.getPrincipal()); } catch (ExcessiveAttemptsException eae) { System.out.println("Too many login attempts for user: " + token.getPrincipal()); } catch (AuthenticationException ae) { System.out.println("Authentication failed: " + ae.getMessage()); } finally { // Clear sensitive data from token token.clear(); } } // Logout when done currentUser.logout(); ``` -------------------------------- ### Manage User Sessions with Shiro API Source: https://context7.com/apache/shiro/llms.txt Demonstrates session lifecycle management, attribute storage, and timeout configuration. Requires an active Shiro Subject. ```java import org.apache.shiro.SecurityUtils; import org.apache.shiro.session.Session; import org.apache.shiro.session.InvalidSessionException; import org.apache.shiro.subject.Subject; import java.util.Date; Subject currentUser = SecurityUtils.getSubject(); // Get session (creates one if it doesn't exist) Session session = currentUser.getSession(); // Get session without creating one if it doesn't exist Session existingSession = currentUser.getSession(false); // Session properties System.out.println("Session ID: " + session.getId()); System.out.println("Host: " + session.getHost()); System.out.println("Start Time: " + session.getStartTimestamp()); System.out.println("Last Access: " + session.getLastAccessTime()); // Get/Set session timeout (in milliseconds) long timeout = session.getTimeout(); System.out.println("Timeout: " + timeout + "ms"); session.setTimeout(1800000); // 30 minutes // Store attributes in session session.setAttribute("userPreferences", "dark-mode"); session.setAttribute("shoppingCart", new Object()); // Retrieve attributes String prefs = (String) session.getAttribute("userPreferences"); System.out.println("User preferences: " + prefs); // Get all attribute keys for (Object key : session.getAttributeKeys()) { System.out.println("Session attribute: " + key); } // Remove attribute Object removed = session.removeAttribute("shoppingCart"); // Touch session to prevent timeout (useful for long-running operations) session.touch(); // Explicitly stop/invalidate the session try { session.stop(); } catch (InvalidSessionException e) { System.out.println("Session was already invalid"); } ``` -------------------------------- ### Push Changes to Fork Source: https://github.com/apache/shiro/blob/main/CONTRIBUTING.md Push your local changes, including the feature branch, to your GitHub fork to prepare for a pull request. ```bash $ git push origin main $ git push origin feature_x ``` -------------------------------- ### Clone Apache Shiro Repository Source: https://github.com/apache/shiro/blob/main/CONTRIBUTING.md Clone the Apache Shiro repository to your local machine and set up upstream remote for future updates. ```bash $ git clone https://github.com/YOUR_ACCOUNT/shiro.git $ cd shiro $ git remote add upstream https://github.com/apache/shiro.git $ git checkout main $ git fetch upstream $ git rebase upstream/main ``` -------------------------------- ### Configure Web URL Filters in shiro.ini Source: https://context7.com/apache/shiro/llms.txt Defines authentication, authorization, and security filters for specific URL patterns in a Shiro web application. ```ini # shiro.ini - Web URL filter configuration [main] # Custom form authentication filter settings authc.loginUrl = /login.jsp authc.successUrl = /home.jsp authc.usernameParam = username authc.passwordParam = password authc.rememberMeParam = rememberMe # Logout filter configuration logout.redirectUrl = /login.jsp # SSL filter for HTTPS enforcement ssl.port = 443 [urls] # anon - Anonymous access allowed /public/** = anon /login = anon # authc - Form-based authentication required /account/** = authc # authcBasic - HTTP Basic authentication /api/v1/** = authcBasic # authcBearer - Bearer token authentication /api/v2/** = authcBearer # user - Authenticated OR remembered users /dashboard = user # perms - Permission required /admin/users = authc, perms[user:manage] /admin/reports = authc, perms["report:view,report:export"] # roles - Role required /admin/** = authc, roles[admin] /moderator/** = authc, roles[moderator] # ssl - Require HTTPS /secure/** = ssl, authc # port - Require specific port /payment/** = port[8443], authc # logout - Logout and redirect /logout = logout # noSessionCreation - Stateless API endpoints /api/** = noSessionCreation, authcBearer # Multiple filters in chain (processed left to right) /admin/settings = ssl, authc, roles[admin], perms[settings:manage] ``` -------------------------------- ### Hash Passwords with DefaultPasswordService Source: https://context7.com/apache/shiro/llms.txt Secure password hashing and verification using Argon2id. The resulting hash string includes all necessary parameters for future verification. ```java import org.apache.shiro.authc.credential.DefaultPasswordService; import org.apache.shiro.authc.credential.PasswordService; import org.apache.shiro.crypto.hash.Hash; // Create password service (uses Argon2id by default in Shiro 2.x) PasswordService passwordService = new DefaultPasswordService(); // Hash a password for storage String plainTextPassword = "secretPassword123"; String hashedPassword = passwordService.encryptPassword(plainTextPassword); System.out.println("Hashed password: " + hashedPassword); // Output: $shiro2$argon2id$v=19$m=4096,t=3,p=4$... // Verify password during login boolean passwordMatches = passwordService.passwordsMatch("secretPassword123", hashedPassword); System.out.println("Password matches: " + passwordMatches); // true boolean wrongPassword = passwordService.passwordsMatch("wrongPassword", hashedPassword); System.out.println("Wrong password matches: " + wrongPassword); // false // For storing in database, just save the hashed string // The hash contains the algorithm, parameters, salt, and hash value // This allows password verification even if settings change later ``` -------------------------------- ### Check and Enforce Permissions in Java Source: https://context7.com/apache/shiro/llms.txt Manage permission-based access using `isPermitted()`, `isPermittedAll()`, and `checkPermission()`. `checkPermission()` throws an `UnauthorizedException` if the permission is not granted. Supports domain:action:instance and wildcard patterns. ```java import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.subject.Subject; Subject currentUser = SecurityUtils.getSubject(); // Simple permission check if (currentUser.isPermitted("document:read")) { System.out.println("User can read documents"); } // Domain:action permission pattern if (currentUser.isPermitted("printer:print")) { System.out.println("User can print"); } // Instance-level permission: domain:action:instance if (currentUser.isPermitted("user:edit:12345")) { System.out.println("User can edit user with ID 12345"); } // Wildcard permissions // lightsaber:* means all actions on lightsaber domain if (currentUser.isPermitted("lightsaber:wield")) { System.out.println("You may use a lightsaber!"); } // Check multiple permissions at once boolean[] permissions = currentUser.isPermitted("file:read", "file:write", "file:delete"); System.out.println("Can read: " + permissions[0]); System.out.println("Can write: " + permissions[1]); System.out.println("Can delete: " + permissions[2]); // Check if user has ALL specified permissions if (currentUser.isPermittedAll("project:read", "project:write")) { System.out.println("User has full project access"); } // Assert permission - throws exception if not permitted try { currentUser.checkPermission("winnebago:drive:eagle5"); System.out.println("Here are the keys - have fun!"); } catch (UnauthorizedException e) { System.out.println("Sorry, you can't drive the winnebago"); } ``` -------------------------------- ### Configure Shiro via INI Source: https://context7.com/apache/shiro/llms.txt Define security settings, users, roles, and URL filter chains using the Shiro INI format. This configuration is processed by the Shiro SecurityManager. ```ini # shiro.ini - Shiro configuration file # ============================================================================= # Main SecurityManager configuration # ============================================================================= [main] # Configure a custom realm myRealm = com.example.security.MyCustomRealm myRealm.userService = $myUserService # Session timeout (30 minutes in milliseconds) securityManager.sessionManager.globalSessionTimeout = 1800000 # Remember Me cookie settings securityManager.rememberMeManager.cookie.name = rememberMe securityManager.rememberMeManager.cookie.maxAge = 2592000 # ============================================================================= # Users section: username = password, role1, role2, ... # ============================================================================= [users] # User 'admin' with password 'admin123' and roles 'admin' and 'user' admin = admin123, admin, user # User 'developer' with password 'dev123' and 'user' role developer = dev123, user # User 'guest' with password 'guest' and 'guest' role guest = guest, guest # ============================================================================= # Roles section: roleName = permission1, permission2, ... # ============================================================================= [roles] # Admin has all permissions (wildcard) admin = * # User role can read and write documents user = document:read, document:write, profile:* # Guest can only read guest = document:read # ============================================================================= # URL filter chain definitions (for web applications) # ============================================================================= [urls] # Static assets are accessible anonymously /assets/** = anon /css/** = anon /images/** = anon # Login page is anonymous /login = authc # Logout URL /logout = logout # Admin pages require 'admin' role /admin/** = authc, roles[admin] # API endpoints require authentication and specific permissions /api/users/** = authc, perms[user:manage] /api/documents/** = authc, perms[document:read] # Everything else requires authentication /** = authc ``` -------------------------------- ### Configure Shiro in Spring Boot Source: https://context7.com/apache/shiro/llms.txt Defines a configuration class for Shiro realms and filter chain definitions within a Spring Boot application. ```java import org.apache.shiro.realm.Realm; import org.apache.shiro.realm.text.TextConfigurationRealm; import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition; import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ShiroConfig { @Bean public Realm realm() { TextConfigurationRealm realm = new TextConfigurationRealm(); // Define users: username = password, role1, role2 realm.setUserDefinitions( "admin = admin123, admin\n" + "user = user123, user\n" + "guest = guest, guest" ); // Define roles: roleName = permission1, permission2 realm.setRoleDefinitions( "admin = *\n" + "user = document:*, profile:read\n" + "guest = document:read" ); return realm; } @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); // Public endpoints chainDefinition.addPathDefinition("/login", "anon"); chainDefinition.addPathDefinition("/register", "anon"); chainDefinition.addPathDefinition("/css/**", "anon"); // Admin endpoints chainDefinition.addPathDefinition("/admin/**", "authc, roles[admin]"); // All other endpoints require authentication chainDefinition.addPathDefinition("/**", "authc"); return chainDefinition; } } ``` -------------------------------- ### Check and Enforce User Roles in Java Source: https://context7.com/apache/shiro/llms.txt Use `hasRole()`, `hasRoles()`, `hasAllRoles()`, and `checkRole()` to manage role-based access control for a Subject. `checkRole()` throws an `UnauthorizedException` if the role is missing. ```java import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.subject.Subject; import java.util.Arrays; Subject currentUser = SecurityUtils.getSubject(); // Simple role check - returns boolean if (currentUser.hasRole("admin")) { System.out.println("User has admin role - showing admin dashboard"); } else { System.out.println("User does not have admin role"); } // Check multiple roles at once boolean[] hasRoles = currentUser.hasRoles(Arrays.asList("admin", "user", "guest")); System.out.println("Has admin: " + hasRoles[0]); System.out.println("Has user: " + hasRoles[1]); System.out.println("Has guest: " + hasRoles[2]); // Check if user has ALL specified roles if (currentUser.hasAllRoles(Arrays.asList("user", "moderator"))) { System.out.println("User has both user and moderator roles"); } // Assert role - throws UnauthorizedException if missing try { currentUser.checkRole("schwartz"); System.out.println("May the Schwartz be with you!"); } catch (UnauthorizedException e) { System.out.println("Sorry, you don't have the schwartz role"); } // Assert multiple roles try { currentUser.checkRoles("admin", "developer"); } catch (AuthorizationException e) { System.out.println("Missing required roles: " + e.getMessage()); } ``` -------------------------------- ### Perform AES Encryption with AesCipherService Source: https://context7.com/apache/shiro/llms.txt Utilizes AesCipherService to generate keys, encrypt sensitive data, and decrypt it. Note that 256-bit key sizes require the JCE Unlimited Strength policy. ```java import org.apache.shiro.crypto.cipher.AesCipherService; import org.apache.shiro.lang.util.ByteSource; import java.security.Key; import java.util.Base64; // Create AES cipher service AesCipherService cipherService = new AesCipherService(); // Generate a secure random key Key key = cipherService.generateNewKey(); byte[] keyBytes = key.getEncoded(); System.out.println("Key (Base64): " + Base64.getEncoder().encodeToString(keyBytes)); // Encrypt data String sensitiveData = "This is sensitive information"; byte[] plaintext = sensitiveData.getBytes(); ByteSource encrypted = cipherService.encrypt(plaintext, keyBytes); byte[] encryptedBytes = encrypted.getBytes(); System.out.println("Encrypted (Base64): " + Base64.getEncoder().encodeToString(encryptedBytes)); // Decrypt data ByteSource decrypted = cipherService.decrypt(encryptedBytes, keyBytes); String decryptedString = new String(decrypted.getBytes()); System.out.println("Decrypted: " + decryptedString); // For 256-bit key (requires JCE Unlimited Strength policy) cipherService.setKeySize(256); Key strongKey = cipherService.generateNewKey(); ``` -------------------------------- ### Enforce Security with Authorization Annotations Source: https://context7.com/apache/shiro/llms.txt Declarative security constraints for methods or classes. Requires AOP integration such as Spring, Guice, or AspectJ. ```java import org.apache.shiro.authz.annotation.*; // Requires the user to be authenticated (logged in) @RequiresAuthentication public void sensitiveOperation() { // Only authenticated users can execute this } // Requires specific roles @RequiresRoles("admin") public void adminOnlyMethod() { // Only users with 'admin' role can execute } // Requires multiple roles (AND logic by default) @RequiresRoles({"admin", "developer"}) public void adminAndDeveloperMethod() { // User must have BOTH roles } // Requires ANY of the specified roles (OR logic) @RequiresRoles(value = {"admin", "moderator"}, logical = Logical.OR) public void adminOrModeratorMethod() { // User needs at least one of the roles } // Requires specific permissions @RequiresPermissions("document:read") public void readDocument() { // Only users with 'document:read' permission } // Requires multiple permissions @RequiresPermissions({"file:read", "file:write"}) public void readWriteFile() { // User must have BOTH permissions } // Requires ANY of the specified permissions @RequiresPermissions(value = {"admin:*", "user:manage"}, logical = Logical.OR) public void manageUsers() { // User needs at least one permission } // Requires the user to be a "guest" (not authenticated or remembered) @RequiresGuest public void guestOnlyPage() { // Only non-authenticated users } // Requires the user to be known (authenticated or remembered) @RequiresUser public void userArea() { // Authenticated OR remembered users } ``` -------------------------------- ### Rebase Feature Branch Source: https://github.com/apache/shiro/blob/main/CONTRIBUTING.md Update your feature branch with the latest changes from the upstream main branch to resolve potential conflicts. ```bash $ git checkout main $ git fetch upstream $ git rebase upstream/main $ git checkout feature_x $ git rebase main ``` -------------------------------- ### Delete Local and Remote Feature Branches Source: https://github.com/apache/shiro/blob/main/CONTRIBUTING.md Use these commands to delete local and remote feature branches after they have been merged into upstream/main. Ensure changes are in upstream/main before executing. ```bash $ git checkout main $ git branch -D feature_x $ git push origin :feature_x ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.