diff --git a/apache-shiro/.gitignore b/apache-shiro/.gitignore
new file mode 100644
index 0000000000..020cda4898
--- /dev/null
+++ b/apache-shiro/.gitignore
@@ -0,0 +1,4 @@
+
+/.idea/
+/target/
+/apache-shiro.iml
\ No newline at end of file
diff --git a/apache-shiro/README.md b/apache-shiro/README.md
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apache-shiro/pom.xml b/apache-shiro/pom.xml
new file mode 100644
index 0000000000..97ed872a26
--- /dev/null
+++ b/apache-shiro/pom.xml
@@ -0,0 +1,65 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ apache-shiro
+ 1.0-SNAPSHOT
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+ 1.4.0
+ 1.2.17
+ 1.7.25
+
+
+
+
+ org.apache.shiro
+ shiro-core
+ ${apache-shiro-core-version}
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${slf4j-version}
+ runtime
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-version}
+ runtime
+
+
+ log4j
+ log4j
+ ${log4j-version}
+ runtime
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.6.2
+
+
+ 1.8
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apache-shiro/src/main/java/com/baeldung/Main.java b/apache-shiro/src/main/java/com/baeldung/Main.java
new file mode 100644
index 0000000000..68af5d7b46
--- /dev/null
+++ b/apache-shiro/src/main/java/com/baeldung/Main.java
@@ -0,0 +1,84 @@
+package com.baeldung;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.*;
+import org.apache.shiro.config.IniSecurityManagerFactory;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.Factory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Main {
+ private static final transient Logger log = LoggerFactory.getLogger(Main.class);
+
+ public static void main(String[] args) {
+
+ Factory factory
+ = new IniSecurityManagerFactory("classpath:shiro.ini");
+ SecurityManager securityManager = factory.getInstance();
+
+ SecurityUtils.setSecurityManager(securityManager);
+ Subject currentUser = SecurityUtils.getSubject();
+
+ if (!currentUser.isAuthenticated()) {
+ UsernamePasswordToken token
+ = new UsernamePasswordToken("user", "password");
+ token.setRememberMe(true);
+ try {
+ currentUser.login(token);
+ } catch (UnknownAccountException uae) {
+ log.error("Username Not Found!", uae);
+ } catch (IncorrectCredentialsException ice) {
+ log.error("Invalid Credentials!", ice);
+ } catch (LockedAccountException lae) {
+ log.error("Your Account is Locked!", lae);
+ } catch (AuthenticationException ae) {
+ log.error("Unexpected Error!", ae);
+ }
+ }
+
+ log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
+
+ if (currentUser.hasRole("admin")) {
+ log.info("Welcome Admin");
+ } else if(currentUser.hasRole("editor")) {
+ log.info("Welcome, Editor!");
+ } else if(currentUser.hasRole("author")) {
+ log.info("Welcome, Author");
+ } else {
+ log.info("Welcome, Guest");
+ }
+
+ if(currentUser.isPermitted("articles:compose")) {
+ log.info("You can compose an article");
+ } else {
+ log.info("You are not permitted to compose an article!");
+ }
+
+ if(currentUser.isPermitted("articles:save")) {
+ log.info("You can save articles");
+ } else {
+ log.info("You can not save articles");
+ }
+
+ if(currentUser.isPermitted("articles:publish")) {
+ log.info("You can publish articles");
+ } else {
+ log.info("You can not publish articles");
+ }
+
+ Session session = currentUser.getSession();
+ session.setAttribute("key", "value");
+ String value = (String) session.getAttribute("key");
+ if (value.equals("value")) {
+ log.info("Retrieved the correct value! [" + value + "]");
+ }
+
+ currentUser.logout();
+
+ System.exit(0);
+ }
+
+}
diff --git a/apache-shiro/src/main/java/com/baeldung/MyCustomRealm.java b/apache-shiro/src/main/java/com/baeldung/MyCustomRealm.java
new file mode 100644
index 0000000000..8d792c76a5
--- /dev/null
+++ b/apache-shiro/src/main/java/com/baeldung/MyCustomRealm.java
@@ -0,0 +1,102 @@
+package com.baeldung;
+
+import org.apache.shiro.authc.*;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.jdbc.JdbcRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.*;
+
+public class MyCustomRealm extends JdbcRealm {
+
+ private Map credentials = new HashMap<>();
+ private Map> roles = new HashMap<>();
+ private Map> perm = new HashMap<>();
+
+ {
+ credentials.put("user", "password");
+ credentials.put("user2", "password2");
+ credentials.put("user3", "password3");
+
+ roles.put("user", new HashSet<>(Arrays.asList("admin")));
+ roles.put("user2", new HashSet<>(Arrays.asList("editor")));
+ roles.put("user3", new HashSet<>(Arrays.asList("author")));
+
+ perm.put("admin", new HashSet<>(Arrays.asList("*")));
+ perm.put("editor", new HashSet<>(Arrays.asList("articles:*")));
+ perm.put("author",
+ new HashSet<>(Arrays.asList("articles:compose",
+ "articles:save")));
+
+ }
+
+ @Override
+ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
+ throws AuthenticationException {
+
+ UsernamePasswordToken uToken = (UsernamePasswordToken) token;
+
+ if(uToken.getUsername() == null
+ || uToken.getUsername().isEmpty()
+ || !credentials.containsKey(uToken.getUsername())
+ ) {
+ throw new UnknownAccountException("username not found!");
+ }
+
+
+ return new SimpleAuthenticationInfo(
+ uToken.getUsername(), credentials.get(uToken.getUsername()),
+ getName());
+ }
+
+ @Override
+ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+ Set roleNames = new HashSet<>();
+ Set permissions = new HashSet<>();
+
+ principals.forEach(p -> {
+ try {
+ Set roles = getRoleNamesForUser(null, (String) p);
+ roleNames.addAll(roles);
+ permissions.addAll(getPermissions(null, null,roles));
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ });
+
+ SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
+ info.setStringPermissions(permissions);
+ return info;
+ }
+
+ @Override
+ protected Set getRoleNamesForUser(Connection conn, String username) throws SQLException {
+ if(!roles.containsKey(username)) {
+ throw new SQLException("username not found!");
+ }
+
+ return roles.get(username);
+ }
+
+ @Override
+ protected Set getPermissions(Connection conn, String username, Collection roleNames) throws SQLException {
+ for (String role : roleNames) {
+ if (!perm.containsKey(role)) {
+ throw new SQLException("role not found!");
+ }
+ }
+
+ Set finalSet = new HashSet<>();
+ for (String role : roleNames) {
+ finalSet.addAll(perm.get(role));
+ }
+
+ return finalSet;
+ }
+
+}
diff --git a/apache-shiro/src/main/resources/log4j.properties b/apache-shiro/src/main/resources/log4j.properties
new file mode 100644
index 0000000000..897bf08221
--- /dev/null
+++ b/apache-shiro/src/main/resources/log4j.properties
@@ -0,0 +1,12 @@
+log4j.rootLogger=INFO, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
+
+log4j.logger.org.apache=WARN
+
+log4j.logger.org.apache.shiro=INFO
+
+log4j.logger.org.apache.shiro.util.ThreadContext=WARN
+log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
\ No newline at end of file
diff --git a/apache-shiro/src/main/resources/shiro.ini b/apache-shiro/src/main/resources/shiro.ini
new file mode 100644
index 0000000000..a75f591015
--- /dev/null
+++ b/apache-shiro/src/main/resources/shiro.ini
@@ -0,0 +1,3 @@
+jdbcRealm = com.baeldung.MyCustomRealm
+
+securityManager.realms = $jdbcRealm
\ No newline at end of file