NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

《Linux就是这个范儿》读书笔记(一) - 理解Linux用户和用户组

| Comments

理解什么是多用户多任务分时操作系统

“将大型电脑的珍贵时间资源适当的分配到所有使用者身上,让所有使用者都有独占整部机器的感觉,这是当时计算机先驱提出的分时系统的概念。依据这个想法,通用电气、麻省理工学院和贝尔实验室联手启动Multics项目,这是在当时看着最靠谱的分时系统概念。但是由于太“靠谱”了(真正的多用户多任务分时操作系统),在当时的技术条件下去完成它实在是吃力,所以最终的命运很悲惨。但是有两个游戏爱好者,Multics的成员Ken和Dennis为了能够有电脑玩游戏,决定自己给一台闲置的电脑写个操作系统,于是 — 一个实用的多用户多任务分时操作系统就诞生了。” —-《Linux就是这个范》

我们所熟知的Windows、Linux、Mac OS X等都是多用户多任务分时操作系统。最显著的特点就是可以让多个人使用同一台电脑而不能互相窥探对方的秘密(多用户)。当你使用电脑时,可以边放音乐,边聊QQ,边浏览网页(多任务)。分时就像之前的定义那样,将电脑的时间资源适当的分配给所有的使用者身上,如果将使用者抽象,它不仅仅代表“人”,可以代表任何使用电脑时间资源的任务,在这样的理解下,分时就成为了多用户和多任务的基础。

澡堂文化 - 多用户

Linux中的用户管理是管理用户的等级和对文件的访问权限。

用户等级只有两个root和非root用户。root用户拥有至高无上的权利,用户名就是root,相当于Windows中的Administrator,但幸运的是root用户只有一个。root用户通过文件严格控制着非root用户的访问权限。

在《Linux就是这个范》这本书中,作者将这种管理方式形象的描述为“澡堂子模型”。root用户就是澡堂子的服务生,每个来澡堂子的人,服务生都会给分配一个号码牌,就像root用户给非root用户分配账号。每个号码牌上都有一个钥匙,可以打开对应的柜子。

而每个非root用户一般会拥有自己的文件目录(某些不会,它们可能是执行特殊任务的用户,不需要自己的文件目录),目录路径一般是/home/[username],这就是,每个非root用户的目录就对应着每个来澡堂中的柜子。

用户权限(不同的职业)

在使用Linux的时候,经常会遇到无法对文件读写,或者执行,因为当前登录账号的权限不够。因此,会给予一种错觉,那就是账号分为不同的权限级别,另一个账号可以访问,因为它比当前登录账号权限更高。

但这其实是一种错误的理解,前面已经提到,Linux中用户等级只有两个,root和非root,除了root用户拥有至高无上的权利外,其他用户都是一样的渣渣。

导致这种错觉的原因,是因为还有一个用户组的概念(职业)。

一个用户可以属于多个用户组,就像一个人可以身兼多职一样。由于用户组能够在更高的层面来抽象用户所能够访问文件的数量,因此结合不同的用户组,就能给每个用户构建出独一无二的文件访问列表。

用户和用户组管理

用户和用户组信息分别存放在etc/passwd和etc/group中,Linux系统为用户和用户组文件的CRUD操作提供了一些基本命令,这些命令的作用就是对etc/passwd和etc/group两个文件的文件内容进行增删改,然后,外加一个etc/shadow文件来管理密码,就实现了对用户和用户组的管理。

关于什么样的命令来管理用户和用户组,这里不做更多介绍,可以参考其他资料。

神秘的sudo-假借身份

安装软件是使用Linux操作系统最常见的操作。但Linux中的用户除了root就是普通用户,而普通用户的权限非常低,就连向系统中安装软件的权利都没有。很多时候系统管理员为了能够让普通用户具备一点root的特权,就赋给普通用户一个称为sudo的特权。

普通用户一旦拥有sudo的特权,几乎就可以胡作非为,但需要付出一点代价,需要在将要执行的命令前加上sudo作为前缀,同时被系统提示输入当前用户的密码。这样做的好处是防止不怀好意的进行不安全的操作。因为你不是root用户,所以如果有恶意软件要使用sudo进行操作,此时就会被需要输入密码,这种无缘无故需要输入密码的行为一定会被你发现。

不同的Linux发行版本,可能一般的非root用户不会立即拥有sudo特权。所以这时就需要自己去给某个用户赋予sudo特权,方法是修改/etc/sudoers这个文件。至于文件里的内容长什么样,这里也不过多介绍,可以参考其他资料。

每次都要sudo,好麻烦,干脆su

要使用sudo特权,必须每次在命令前加上sudo,这样对管理Linux系统不太方便。su命令可以临时切换用户,默认是切换到root用户。

切换用户需要输入目标用户的密码,切换到root用户就需要root用户的密码。

我是谁和我到底是谁

要知道当前用户是谁,有三条命令可以用,whoami,who am i和who。第一个命令和后两条命令有本质区别,这里要引入实际用户(UID)和有效用户(EUID)的概念。

实际用户就是指用户登录时所使用的用户,整个登录会话中,实际用户不会改变;有效用户是指当前执行操作的用户,该用户可以通过su切换,决定了权限的高低。

whoami查看的是有效用户,而who和who am i可以查看实际用户。

参考资料:
1.Linux就是这个范儿

Spring Web Security 实战 (四) - 了解Security基础架构

| Comments

在了解了Spring Security的基本使用之后,还是需要更深入的了解Spring Security的基础架构,核心组件等。

Spring Security是以自包含的角度来实现安全设计,所以使用Spring Security没有任何侵入性。因为Spring Security的目标是自己容器内管理, 所以不需要为你的Java运行环境进行什么特别的配置。

核心组件

SecurityContextHolder, SecurityContext和Authentication对象

SecurityContextHolder,就如该类的名字所描述的那样,它用来存放当前应用程序的当前安全上下文中的细节,当然也包括“当事人Principal”的细节。SecurityContextHolder将上下文信息存储在ThreadLocal当中,这意味着,安全环境在同一个线程执行的方法一直是有效的。这种情况下使用ThreadLocal是非常安全的,只要记得在处理完当前主体的请求以后,把这个线程清除就行了。当然,Spring Security自动帮你管理这一切了,你就不用担心什么了。

下面这段代码很清晰的说明了上面的实现策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
  private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<SecurityContext>();

  public SecurityContext getContext() {
      SecurityContext ctx = contextHolder.get();

      if (ctx == null) {
          ctx = createEmptyContext();
          contextHolder.set(ctx);
      }

      return ctx;
  }
}

当你从SecurityContextHolder中拿到SecurityContext后,你就可以通过下面的这段代码取到“当事人”或者说用户的信息:

1
2
3
4
5
6
7
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

if (principal instanceof UserDetails) {
  String username = ((UserDetails)principal).getUsername();
} else {
  String username = principal.toString();
}

看完上面的代码,就要引入第二个关键组件Authentication:

Authentication是一个接口,代表着一种“认证”令牌,它里面存放着“当事人”的基本信息和是否认证的标志信息。框架在接受到认证请求时,会将新创建的Authentication对象会传递给AuthenticationManager.authenticate(Authentication),由它来决定“认证”是否成功。

而一旦“认证”请求通过,Authentication通常都会存储在SecurityContext中,由SecurityContextHolder来管理。

除了主体,另一个Authentication提供的重要方法是getAuthorities()。 这个方法提供了GrantedAuthority对象数组。 毫无疑问,GrantedAuthority是赋予到主体的权限。这些权限通常使用角色表示,比如ROLE_ADMINISTRATOR或ROLE_HR_SUPERVISOR。

SecurityContextHolder,提供访问SecurityContext的方式。
SecurityContext,保存Authentication信息,和请求对应的安全信息。
Authentication,作为认证的令牌。
GrantedAuthority,反应在应用程序范围内,赋予的权限。

Spring Security的认证(Authentication)过程

让我们考虑一种标准的验证场景,每个人都很熟悉的那种。
一个用户想使用一个账号和密码进行登陆。
系统(成功的)验证了密码对于这个用户名是正确的。
这个用户对应的信息获取(他们的角色列表以及等等)。
为用户建立一个安全环境。
用户会执行一些操作,这些都是潜在被权限控制机制所保护的,通过对操作的授权,使用当前的安全环境信息。

前三个项目执行了验证过程,所以我们可以看一下Spring Security的作用。
用户名和密码被获得,并进行比对,在一个UsernamePasswordAuthenticationToken的实例中(它是Authentication接口的一个实例,我们在之前已经见过了)。
这个标志被发送给一个AuthenticationManager的实例进行校验。
AuthenticationManager返回一个完全的Authentication实例,在成功校验后。
安全环境被建立,通过调用SecurityContextHolder.getContext().setAuthentication(…),传递到返回的验证对象中。

事实上,Spring Security并不介意你如何将Authentication对象放到SecurityContextHolder里。唯一关键的一点是 在AbstractSecurityInterceptor需要验证一个用户操作之前,SecurityContextHolder必须包含了一个表示了主体的Authentication。

待续。。。